diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 91135dac6..a181b7e52 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -12,6 +12,24 @@ library TokenLib { using SafeMath for uint256; + struct EIP712Domain { + string name; + uint256 chainId; + address verifyingContract; + } + + struct Acknowledgment { + string text; + } + + bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256( + "EIP712Domain(string name,uint256 chainId,address verifyingContract)" + ); + + bytes32 constant ACK_TYPEHASH = keccak256( + "Acknowledgment(string text)" + ); + bytes32 internal constant WHITELIST = "WHITELIST"; bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) @@ -26,6 +44,80 @@ library TokenLib { // Emit when the budget allocated to a module is changed event ModuleBudgetChanged(uint8[] _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget); + function hash(EIP712Domain memory _eip712Domain) internal pure returns (bytes32) { + return keccak256( + abi.encode( + EIP712DOMAIN_TYPEHASH, + keccak256(bytes(_eip712Domain.name)), + _eip712Domain.chainId, + _eip712Domain.verifyingContract + ) + ); + } + + function hash(Acknowledgment memory _ack) internal pure returns (bytes32) { + return keccak256(abi.encode(ACK_TYPEHASH, keccak256(bytes(_ack.text)))); + } + + function recoverFreezeIssuanceAckSigner(bytes memory _signature) public view returns (address) { + Acknowledgment memory ack = Acknowledgment("I acknowledge that freezing Issuance is a permanent and irrevocable change"); + return extractSigner(ack, _signature); + } + + function recoverDisableControllerAckSigner(bytes memory _signature) public view returns (address) { + Acknowledgment memory ack = Acknowledgment("I acknowledge that disabling controller is a permanent and irrevocable change"); + return extractSigner(ack, _signature); + } + + function extractSigner(Acknowledgment memory _ack, bytes memory _signature) internal view returns (address) { + bytes32 r; + bytes32 s; + uint8 v; + + // Check the signature length + if (_signature.length != 65) { + return (address(0)); + } + + // Divide the signature in r, s and v variables + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + // solhint-disable-next-line no-inline-assembly + assembly { + r := mload(add(_signature, 0x20)) + s := mload(add(_signature, 0x40)) + v := byte(0, mload(add(_signature, 0x60))) + } + + // Version of signature should be 27 or 28, but 0 and 1 are also possible versions + if (v < 27) { + v += 27; + } + + // If the version is correct return the signer address + if (v != 27 && v != 28) { + return (address(0)); + } + + bytes32 DOMAIN_SEPARATOR = hash( + EIP712Domain( + { + name: "Polymath", + chainId: 1, + verifyingContract: address(this) + } + ) + ); + + // Note: we need to use `encodePacked` here instead of `encode`. + bytes32 digest = keccak256(abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + hash(_ack) + )); + return ecrecover(digest, v, r, s); + } + /** * @notice Archives a module attached to the SecurityToken * @param _moduleData Storage data diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 31776f8e5..1600237d1 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -12,7 +12,6 @@ import "../interfaces/token/IERC1594.sol"; import "../interfaces/token/IERC1643.sol"; import "../interfaces/token/IERC1644.sol"; import "../interfaces/IModuleRegistry.sol"; -import "../interfaces/IFeatureRegistry.sol"; import "../interfaces/ITransferManager.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol"; @@ -115,11 +114,6 @@ contract SecurityToken is ERC20, ERC20Detailed, Ownable, ReentrancyGuard, Securi _; } - modifier isEnabled(string memory _nameKey) { - require(IFeatureRegistry(featureRegistry).getFeatureStatus(_nameKey)); - _; - } - /** * @notice constructor * @param _name Name of the SecurityToken @@ -485,7 +479,8 @@ contract SecurityToken is ERC20, ERC20Detailed, Ownable, ReentrancyGuard, Securi * @notice Permanently freeze issuance of this security token. * @dev It MUST NOT be possible to increase `totalSuppy` after this function is called. */ - function freezeIssuance() external isIssuanceAllowed isEnabled("freezeIssuanceAllowed") onlyOwner { + function freezeIssuance(bytes calldata _signature) external isIssuanceAllowed onlyOwner { + require(owner() == TokenLib.recoverFreezeIssuanceAckSigner(_signature), "Owner did not sign"); issuance = false; /*solium-disable-next-line security/no-block-members*/ emit FreezeIssuance(); @@ -614,7 +609,8 @@ contract SecurityToken is ERC20, ERC20Detailed, Ownable, ReentrancyGuard, Securi * @notice Used by the issuer to permanently disable controller functionality * @dev enabled via feature switch "disableControllerAllowed" */ - function disableController() external isEnabled("disableControllerAllowed") onlyOwner { + function disableController(bytes calldata _signature) external onlyOwner { + require(owner() == TokenLib.recoverDisableControllerAckSigner(_signature), "Owner did not sign"); require(isControllable()); controllerDisabled = true; delete controller; @@ -768,7 +764,6 @@ contract SecurityToken is ERC20, ERC20Detailed, Ownable, ReentrancyGuard, Securi function updateFromRegistry() public onlyOwner { moduleRegistry = PolymathRegistry(polymathRegistry).getAddress("ModuleRegistry"); securityTokenRegistry = PolymathRegistry(polymathRegistry).getAddress("SecurityTokenRegistry"); - featureRegistry = PolymathRegistry(polymathRegistry).getAddress("FeatureRegistry"); polyToken = PolymathRegistry(polymathRegistry).getAddress("PolyToken"); } } diff --git a/contracts/tokens/SecurityTokenStorage.sol b/contracts/tokens/SecurityTokenStorage.sol index f11c0a1c5..4b33047cc 100644 --- a/contracts/tokens/SecurityTokenStorage.sol +++ b/contracts/tokens/SecurityTokenStorage.sol @@ -53,7 +53,6 @@ contract SecurityTokenStorage { address public polymathRegistry; address public moduleRegistry; address public securityTokenRegistry; - address public featureRegistry; address public polyToken; address public delegate; // Address of the data store used to store shared data diff --git a/test/helpers/signData.js b/test/helpers/signData.js index f0d0a09bb..e6f1ad414 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -1,4 +1,5 @@ const Web3 = require("web3"); +//const sigUtil = require('eth-sig-util') let BN = Web3.utils.BN; function getSignSTMData(tmAddress, nonce, validFrom, expiry, fromAddress, toAddress, amount, pk) { @@ -32,6 +33,90 @@ function getSignSTMData(tmAddress, nonce, validFrom, expiry, fromAddress, toAddr return data; } +async function getFreezeIssuanceAck(stAddress, from) { + const typedData = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' } + ], + Acknowledgment: [ + { name: 'text', type: 'string' } + ], + }, + primaryType: 'Acknowledgment', + domain: { + name: 'Polymath', + chainId: 1, + verifyingContract: stAddress + }, + message: { + text: 'I acknowledge that freezing Issuance is a permanent and irrevocable change', + }, + }; + const result = await new Promise((resolve, reject) => { + web3.currentProvider.send( + { + method: 'eth_signTypedData', + params: [from, typedData] + }, + (err, result) => { + if (err) { + return reject(err); + } + resolve(result.result); + } + ); + }); + // console.log('signed by', from); + // const recovered = sigUtil.recoverTypedSignature({ + // data: typedData, + // sig: result + // }) + // console.log('recovered address', recovered); + return result; +} + +async function getDisableControllerAck(stAddress, from) { + const typedData = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' } + ], + Acknowledgment: [ + { name: 'text', type: 'string' } + ], + }, + primaryType: 'Acknowledgment', + domain: { + name: 'Polymath', + chainId: 1, + verifyingContract: stAddress + }, + message: { + text: 'I acknowledge that disabling controller is a permanent and irrevocable change', + }, + }; + const result = await new Promise((resolve, reject) => { + web3.currentProvider.send( + { + method: 'eth_signTypedData', + params: [from, typedData] + }, + (err, result) => { + if (err) { + return reject(err); + } + resolve(result.result); + } + ); + }); + return result; +} + function getSignGTMData(tmAddress, investorAddress, fromTime, toTime, expiryTime, validFrom, validTo, nonce, pk) { let hash = web3.utils.soliditySha3({ t: 'address', @@ -109,5 +194,7 @@ module.exports = { getSignSTMData, getSignGTMData, getSignGTMTransferData, - getMultiSignGTMData + getMultiSignGTMData, + getFreezeIssuanceAck, + getDisableControllerAck }; \ No newline at end of file diff --git a/test/o_security_token.js b/test/o_security_token.js index 772b1f4b9..7c71ed7f1 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -1,5 +1,6 @@ import latestTime from "./helpers/latestTime"; import { duration, ensureException, promisifyLogWatch, latestBlock } from "./helpers/utils"; +import { getFreezeIssuanceAck, getDisableControllerAck } from "./helpers/signData"; import { takeSnapshot, increaseTime, revertToSnapshot } from "./helpers/time"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; @@ -29,6 +30,8 @@ contract("SecurityToken", async (accounts) => { let account_investor1; let account_issuer; let token_owner; + let disableControllerAckHash; + let freezeIssuanceAckHash; let account_investor2; let account_investor3; let account_affiliate1; @@ -193,7 +196,7 @@ contract("SecurityToken", async (accounts) => { I_SecurityToken = await SecurityToken.at(tx.logs[2].args._securityTokenAddress); stGetter = await STGetter.at(I_SecurityToken.address); assert.equal(await stGetter.getTreasuryWallet.call(), token_owner, "Incorrect wallet set") - const log = (await I_SecurityToken.getPastEvents('ModuleAdded', {filter: {transactionHash: tx.transactionHash}}))[0]; + const log = (await I_SecurityToken.getPastEvents('ModuleAdded', {filter: {transactionHash: tx.transactionHash}}))[0]; // Verify that GeneralTransferManager module get added successfully or not assert.equal(log.args._types[0].toNumber(), transferManagerKey); @@ -328,37 +331,31 @@ contract("SecurityToken", async (accounts) => { assert.equal(balance1.div(new BN(10).pow(new BN(18))).toNumber(), 200); let balance2 = await I_SecurityToken.balanceOf(account_affiliate2); assert.equal(balance2.div(new BN(10).pow(new BN(18))).toNumber(), 110); - + }); it("Should ST be issuable", async() => { assert.isTrue(await I_SecurityToken.isIssuable.call()); }) - it("Should finish the minting -- fail because feature is not activated", async () => { - await catchRevert(I_SecurityToken.freezeIssuance({ from: token_owner })); - }); - - it("Should finish the minting -- fail to activate the feature because msg.sender is not polymath", async () => { - await catchRevert(I_FeatureRegistry.setFeatureStatus("freezeIssuanceAllowed", true, { from: token_owner })); - }); - - it("Should finish the minting -- successfully activate the feature", async () => { - await catchRevert(I_FeatureRegistry.setFeatureStatus("freezeIssuanceAllowed", false, { from: account_polymath })); - assert.equal(false, await I_FeatureRegistry.getFeatureStatus("freezeIssuanceAllowed", { from: account_temp })); - await I_FeatureRegistry.setFeatureStatus("freezeIssuanceAllowed", true, { from: account_polymath }); - assert.equal(true, await I_FeatureRegistry.getFeatureStatus("freezeIssuanceAllowed", { from: account_temp })); - - await catchRevert(I_FeatureRegistry.setFeatureStatus("freezeIssuanceAllowed", true, { from: account_polymath })); + + it("Should finish the minting -- fail because owner didn't sign correct acknowledegement", async () => { + let trueButOutOfPlaceAcknowledegement = web3.utils.utf8ToHex( + "F O'Brien is the best!" + ); + await catchRevert(I_SecurityToken.freezeIssuance(trueButOutOfPlaceAcknowledegement, { from: token_owner })); }); - it("Should finish the minting -- fail because msg.sender is not the owner", async () => { - await catchRevert(I_SecurityToken.freezeIssuance({ from: account_temp })); + // solidity-coverage uses an older version of testrpc that does not support eth_signTypedData. It is required to signt he acknowledgement + process.env.COVERAGE ? it.skip : it("Should finish the minting -- fail because msg.sender is not the owner", async () => { + freezeIssuanceAckHash = await getFreezeIssuanceAck(I_SecurityToken.address, token_owner); + await catchRevert(I_SecurityToken.freezeIssuance(freezeIssuanceAckHash, { from: account_temp })); }); - it("Should finish minting & restrict the further minting", async () => { + // solidity-coverage uses an older version of testrpc that does not support eth_signTypedData. It is required to signt he acknowledgement + process.env.COVERAGE ? it.skip : it("Should finish minting & restrict the further minting", async () => { let id = await takeSnapshot(); - await I_SecurityToken.freezeIssuance({ from: token_owner }); + await I_SecurityToken.freezeIssuance(freezeIssuanceAckHash, { from: token_owner }); assert.isFalse(await I_SecurityToken.isIssuable.call()); await catchRevert(I_SecurityToken.issue(account_affiliate1, new BN(100).mul(new BN(10).pow(new BN(18))), "0x0", { from: token_owner, gas: 500000 })); await revertToSnapshot(id); @@ -420,14 +417,15 @@ contract("SecurityToken", async (accounts) => { it("Should successfully issue tokens while STO attached", async () => { await I_SecurityToken.issue(account_affiliate1, new BN(100).mul(new BN(10).pow(new BN(18))), "0x0", { from: token_owner }); - + let balance = await I_SecurityToken.balanceOf(account_affiliate1); assert.equal(balance.div(new BN(10).pow(new BN(18))).toNumber(), 300); }); - it("Should fail to issue tokens while STO attached after freezeMinting called", async () => { + // solidity-coverage uses an older version of testrpc that does not support eth_signTypedData. It is required to signt he acknowledgement + process.env.COVERAGE ? it.skip : it("Should fail to issue tokens while STO attached after freezeMinting called", async () => { let id = await takeSnapshot(); - await I_SecurityToken.freezeIssuance({ from: token_owner }); + await I_SecurityToken.freezeIssuance(freezeIssuanceAckHash, { from: token_owner }); await catchRevert(I_SecurityToken.issue(account_affiliate1, new BN(100).mul(new BN(10).pow(new BN(18))), "0x0", { from: token_owner })); await revertToSnapshot(id); @@ -498,13 +496,13 @@ contract("SecurityToken", async (accounts) => { assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address); await I_SecurityToken.issue(account_investor1, new BN(web3.utils.toWei("500")), "0x0", { from: token_owner }); let _canTransfer = await I_SecurityToken.canTransfer.call(account_investor2, new BN(web3.utils.toWei("200")), "0x0", {from: account_investor1}); - + assert.isTrue(_canTransfer[0]); assert.equal(_canTransfer[1], 0x51); assert.equal(_canTransfer[2], empty_hash); - + await I_SecurityToken.transfer(account_investor2, new BN(web3.utils.toWei("200")), { from: account_investor1 }); - + assert.equal((await I_SecurityToken.balanceOf(account_investor2)).div(new BN(10).pow(new BN(18))).toNumber(), 200); await revertToSnapshot(key); }); @@ -650,7 +648,7 @@ contract("SecurityToken", async (accounts) => { it("Should Fail in transferring the token from one whitelist investor 1 to non whitelist investor 2", async () => { let _canTransfer = await I_SecurityToken.canTransfer.call(account_investor2, new BN(10).mul(new BN(10).pow(new BN(18))), "0x0", {from: account_investor1}); - + assert.isFalse(_canTransfer[0]); assert.equal(_canTransfer[1], 0x50); @@ -678,7 +676,7 @@ contract("SecurityToken", async (accounts) => { it("Should activate allow All Transfer", async () => { ID_snap = await takeSnapshot(); await I_GeneralTransferManager.modifyTransferRequirementsMulti( - [0, 1, 2], + [0, 1, 2], [false, false, false], [false, false, false], [false, false, false], @@ -745,7 +743,7 @@ contract("SecurityToken", async (accounts) => { it("Should activate allow All Whitelist Transfers", async () => { ID_snap = await takeSnapshot(); await I_GeneralTransferManager.modifyTransferRequirementsMulti( - [0, 1, 2], + [0, 1, 2], [true, false, true], [true, true, false], [false, false, false], @@ -813,7 +811,7 @@ contract("SecurityToken", async (accounts) => { assert.equal(balance1.div(new BN(10).pow(new BN(18))).toNumber(), 500); let balance2 = await I_SecurityToken.balanceOf(account_affiliate2); assert.equal(balance2.div(new BN(10).pow(new BN(18))).toNumber(), 220); - + }); it("Should provide more permissions to the delegate", async () => { @@ -852,9 +850,10 @@ contract("SecurityToken", async (accounts) => { assert.equal((await I_SecurityToken.balanceOf(account_investor1)).div(new BN(10).pow(new BN(18))).toNumber(), 1000); }); - it("STO should fail to issue tokens after minting is frozen", async () => { + // solidity-coverage uses an older version of testrpc that does not support eth_signTypedData. It is required to signt he acknowledgement + process.env.COVERAGE ? it.skip : it("STO should fail to issue tokens after minting is frozen", async () => { let id = await takeSnapshot(); - await I_SecurityToken.freezeIssuance({ from: token_owner }); + await I_SecurityToken.freezeIssuance(freezeIssuanceAckHash, { from: token_owner }); await catchRevert( web3.eth.sendTransaction({ @@ -977,7 +976,7 @@ contract("SecurityToken", async (accounts) => { it("Should force burn the tokens - value too high", async () => { await I_GeneralTransferManager.modifyTransferRequirementsMulti( - [0, 1, 2], + [0, 1, 2], [true, false, false], [true, true, false], [true, false, false], @@ -1251,41 +1250,40 @@ contract("SecurityToken", async (accounts) => { assert.equal(new BN(web3.utils.toWei("10", "ether")).toString(), eventTransfer.args.value.toString(), "Event not emitted as expected"); }); - it("Should fail to freeze controller functionality because not owner", async () => { - await catchRevert(I_SecurityToken.disableController({ from: account_investor1 })); + it("Should fail to freeze controller functionality because proper acknowledgement not signed by owner", async () => { + let trueButOutOfPlaceAcknowledegement = web3.utils.utf8ToHex( + "F O'Brien is the best!" + ); + await catchRevert(I_SecurityToken.disableController(trueButOutOfPlaceAcknowledegement, { from: token_owner })); }); - it("Should fail to freeze controller functionality because disableControllerAllowed not activated", async () => { - await catchRevert(I_SecurityToken.disableController({ from: token_owner })); + // solidity-coverage uses an old version of testrpc that does not support eth_signTypedData. It is required to sign he acknowledgement + process.env.COVERAGE ? it.skip : it("Should fail to freeze controller functionality because not owner", async () => { + disableControllerAckHash = await getDisableControllerAck(I_SecurityToken.address, token_owner); + await catchRevert(I_SecurityToken.disableController(disableControllerAckHash, { from: account_investor1 })); }); - it("Should successfully freeze controller functionality", async () => { - let tx1 = await I_FeatureRegistry.setFeatureStatus("disableControllerAllowed", true, { from: account_polymath }); - - // check event - assert.equal("disableControllerAllowed", tx1.logs[0].args._nameKey, "Event not emitted as expected"); - assert.equal(true, tx1.logs[0].args._newStatus, "Event not emitted as expected"); - - let tx2 = await I_SecurityToken.disableController({ from: token_owner }); - + // solidity-coverage uses an old version of testrpc that does not support eth_signTypedData. It is required to sign he acknowledgement + process.env.COVERAGE ? it.skip : it("Should successfully freeze controller functionality", async () => { + await I_SecurityToken.disableController(disableControllerAckHash, { from: token_owner }); // check state assert.equal(address_zero, await I_SecurityToken.controller.call(), "State not changed"); assert.equal(true, await I_SecurityToken.controllerDisabled.call(), "State not changed"); - }); - - it("Should ST be not controllable", async() => { assert.isFalse(await I_SecurityToken.isControllable.call()); }); - it("Should fail to freeze controller functionality because already frozen", async () => { - await catchRevert(I_SecurityToken.disableController({ from: token_owner })); + // solidity-coverage uses an old version of testrpc that does not support eth_signTypedData. It is required to sign he acknowledgement + process.env.COVERAGE ? it.skip : it("Should fail to freeze controller functionality because already frozen", async () => { + await catchRevert(I_SecurityToken.disableController(disableControllerAckHash, { from: token_owner })); }); - it("Should fail to set controller because controller functionality frozen", async () => { + // solidity-coverage uses an old version of testrpc that does not support eth_signTypedData. It is required to sign he acknowledgement + process.env.COVERAGE ? it.skip : it("Should fail to set controller because controller functionality frozen", async () => { await catchRevert(I_SecurityToken.setController(account_controller, { from: token_owner })); }); - it("Should fail to controllerTransfer because controller functionality frozen", async () => { + // solidity-coverage uses an old version of testrpc that does not support eth_signTypedData. It is required to sign he acknowledgement + process.env.COVERAGE ? it.skip : it("Should fail to controllerTransfer because controller functionality frozen", async () => { await catchRevert( I_SecurityToken.controllerTransfer(account_investor1, account_investor2, new BN(web3.utils.toWei("10", "ether")), "0x0", web3.utils.fromAscii("reason"), { from: account_controller @@ -1399,6 +1397,7 @@ contract("SecurityToken", async (accounts) => { assert.oneOf( await readStorage(I_SecurityToken.address, 7), [ + (await stGetter.controller.call()).toLowerCase(), (await stGetter.controller.call()).substring(0, 4), (await stGetter.controller.call()).substring(0, 3), await stGetter.controller.call() @@ -1434,78 +1433,68 @@ contract("SecurityToken", async (accounts) => { web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 10)) ); - console.log(` - FeatureRegistry address from the contract: ${await stGetter.featureRegistry.call()} - FeatureRegistry address from the storage: ${await readStorage(I_SecurityToken.address, 11)} - `) - - assert.equal( - await stGetter.featureRegistry.call(), - web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 11)) - ); - console.log(` PolyToken address from the contract: ${await stGetter.polyToken.call()} - PolyToken address from the storage: ${await readStorage(I_SecurityToken.address, 12)} + PolyToken address from the storage: ${await readStorage(I_SecurityToken.address, 11)} `) assert.equal( await stGetter.polyToken.call(), - web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 12)) + web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 11)) ); console.log(` Delegate address from the contract: ${await stGetter.delegate.call()} - Delegate address from the storage: ${await readStorage(I_SecurityToken.address, 13)} + Delegate address from the storage: ${await readStorage(I_SecurityToken.address, 12)} `) assert.equal( await stGetter.delegate.call(), - web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 13)) + web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 12)) ); console.log(` Datastore address from the contract: ${await stGetter.dataStore.call()} - Datastore address from the storage: ${await readStorage(I_SecurityToken.address, 14)} + Datastore address from the storage: ${await readStorage(I_SecurityToken.address, 13)} `) assert.equal( await stGetter.dataStore.call(), - web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 14)) + web3.utils.toChecksumAddress(await readStorage(I_SecurityToken.address, 13)) ); console.log(` Granularity value from the contract: ${await stGetter.granularity.call()} - Granularity value from the storage: ${(web3.utils.toBN(await readStorage(I_SecurityToken.address, 15))).toString()} + Granularity value from the storage: ${(web3.utils.toBN(await readStorage(I_SecurityToken.address, 14))).toString()} `) assert.equal( web3.utils.fromWei(await stGetter.granularity.call()), - web3.utils.fromWei((web3.utils.toBN(await readStorage(I_SecurityToken.address, 15))).toString()) + web3.utils.fromWei((web3.utils.toBN(await readStorage(I_SecurityToken.address, 14))).toString()) ); console.log(` Current checkpoint ID from the contract: ${await stGetter.currentCheckpointId.call()} - Current checkpoint ID from the storage: ${(web3.utils.toBN(await readStorage(I_SecurityToken.address, 16))).toString()} + Current checkpoint ID from the storage: ${(web3.utils.toBN(await readStorage(I_SecurityToken.address, 15))).toString()} `) assert.equal( await stGetter.currentCheckpointId.call(), - (web3.utils.toBN(await readStorage(I_SecurityToken.address, 16))).toString() + (web3.utils.toBN(await readStorage(I_SecurityToken.address, 15))).toString() ); console.log(` TokenDetails from the contract: ${await stGetter.tokenDetails.call()} - TokenDetails from the storage: ${(web3.utils.toUtf8((await readStorage(I_SecurityToken.address, 17)).substring(0, 60)))} + TokenDetails from the storage: ${(web3.utils.toUtf8((await readStorage(I_SecurityToken.address, 16)).substring(0, 60)))} `) assert.equal( await stGetter.tokenDetails.call(), - (web3.utils.toUtf8((await readStorage(I_SecurityToken.address, 17)).substring(0, 60))).replace(/\u0000/g, "") + (web3.utils.toUtf8((await readStorage(I_SecurityToken.address, 16)).substring(0, 60))).replace(/\u0000/g, "") ); }); }); - + describe(`Test cases for the ERC1643 contract\n`, async () => { describe(`Test cases for the setDocument() function of the ERC1643\n`, async() => { @@ -1597,7 +1586,7 @@ contract("SecurityToken", async (accounts) => { }); it("\tShould succssfully remove the document from the contract which is present in the last index of the `_docsName` and check the params of the `DocumentRemoved` event\n", async() => { - // first add the new document + // first add the new document await I_SecurityToken.setDocument(web3.utils.utf8ToHex("doc3"), "https://www.bts.l", "0x0", {from: token_owner}); // as this will be last in the array so remove this let tx = await I_SecurityToken.removeDocument(web3.utils.utf8ToHex("doc3"), {from: token_owner});