From 4a487600c1eb308b86628bc88e75319aad7548f9 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 24 Jan 2019 15:06:50 +0530 Subject: [PATCH 1/9] Signed TM added --- .../KYCTransferManagerFactory.sol | 3 +- .../TransferManager/SignedTransferManager.sol | 184 ++++++++++++++++++ .../SignedTransferManagerFactory.sol | 110 +++++++++++ 3 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 contracts/modules/Experimental/TransferManager/SignedTransferManager.sol create mode 100644 contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol diff --git a/contracts/modules/Experimental/TransferManager/KYCTransferManagerFactory.sol b/contracts/modules/Experimental/TransferManager/KYCTransferManagerFactory.sol index 13c9bc5a2..8a5d8f23c 100644 --- a/contracts/modules/Experimental/TransferManager/KYCTransferManagerFactory.sol +++ b/contracts/modules/Experimental/TransferManager/KYCTransferManagerFactory.sol @@ -38,8 +38,9 @@ contract KYCTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[] memory) { - uint8[] memory res = new uint8[](1); + uint8[] memory res = new uint8[](2); res[0] = 2; + res[1] = 6; return res; } diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol new file mode 100644 index 000000000..236182e1e --- /dev/null +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol @@ -0,0 +1,184 @@ +pragma solidity ^0.5.0; + +import "../../TransferManager/TransferManager.sol"; +import "../../../interfaces/IDataStore.sol"; +import "../../../interfaces/ISecurityToken.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; + +/** + * @title Transfer Manager module for verifing transations with a signed message + */ +contract SignedTransferManager is TransferManager { + using SafeMath for uint256; + + bytes32 constant public ADMIN = "ADMIN"; + + //Keeps track of if the signature has been used or invalidated + //mapping(bytes => bool) invalidSignatures; + bytes32 constant public INVALID_SIG = "INVALIDSIG"; + + //keep tracks of the address that allows to sign messages + //mapping(address => bool) public signers; + bytes32 constant public SIGNER = "SIGNER"; + + // Emit when signer stats was changed + event SignersUpdated(address[] _signers, bool[] _signersStats); + + // Emit when a signature has been deemed invalid + event SignatureInvalidated(bytes _data); + + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) + public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice This function returns the signature of configure function + */ + function getInitFunction() external pure returns (bytes4) { + return bytes4(0); + } + + /** + * @notice function to check if a signature is still valid + * @param _data signature + */ + function checkSignatureIsInvalid(bytes calldata _data) external view returns(bool) { + return _checkSignatureIsInvalid(_data); + } + + function checkSigner(address _signer) external view returns(bool) { + return _checkSigner(_signer); + } + + /** + * @notice function to remove or add signer(s) onto the signer mapping + * @param _signers address array of signers + * @param _signersStats bool array of signers stats + */ + function updateSigners(address[] memory _signers, bool[] memory _signersStats) external withPerm(ADMIN) { + require(_signers.length == _signersStats.length, "Array length mismatch"); + IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); + for(uint256 i=0; i<_signers.length; i++) { + require(_signers[i] != address(0), "Invalid address"); + dataStore.setBool(keccak256(abi.encodePacked(SIGNER, _signers[i])), _signersStats[i]); + } + emit SignersUpdated(_signers, _signersStats); + } + + /** + * @notice allow verify transfer with signature + * @param _from address transfer from + * @param _to address transfer to + * @param _amount transfer amount + * @param _data signature + * @param _isTransfer bool value of isTransfer + * Sig needs to be valid (not used or deemed as invalid) + * Signer needs to be in the signers mapping + */ + function verifyTransfer(address _from, address _to, uint256 _amount, bytes memory _data , bool _isTransfer) public returns(Result) { + if (!paused) { + + require (_isTransfer == false || msg.sender == securityToken, "Sender is not ST"); + + if (_data.length == 0 || _checkSignatureIsInvalid(_data)) { + return Result.NA; + } + + bytes32 hash = keccak256(abi.encodePacked(this, _from, _to, _amount)); + bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + address signer = _recoverSignerAdd(prependedHash, _data); + + if (!_checkSigner(signer)) { + return Result.NA; + } else if(_isTransfer) { + _invalidateSignature(_data); + return Result.VALID; + } else { + return Result.VALID; + } + } + return Result.NA; + } + + /** + * @notice allow signers to deem a signature invalid + * @param _from address transfer from + * @param _to address transfer to + * @param _amount transfer amount + * @param _data signature + * Sig needs to be valid (not used or deemed as invalid) + * Signer needs to be in the signers mapping + */ + function invalidateSignature(address _from, address _to, uint256 _amount, bytes calldata _data) external { + require(_checkSigner(signer), "Unauthorized Signer"); + require(!_checkSignatureIsInvalid(_data), "Signature already invalid"); + + bytes32 hash = keccak256(abi.encodePacked(this, _from, _to, _amount)); + bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + + require(_recoverSignerAdd(prependedHash, _data) == msg.sender, "Incorrect Signer"); + + _invalidateSignature(_data); + } + + /** + * @notice used to recover signers' address from signature + */ + function _recoverSignerAdd(bytes32 _hash, bytes memory _data) internal pure returns(address) { + + if (_data.length != 65) { + return address(0); + } + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + r := mload(add(_data, 32)) + s := mload(add(_data, 64)) + v := and(mload(add(_data, 65)), 255) + } + if (v < 27) { + v += 27; + } + if (v != 27 && v != 28) { + + } + + return ecrecover(_hash, v, r, s); + } + + /** + * @notice Return the permissions flag that are associated with ManualApproval transfer manager + */ + function getPermissions() public view returns(bytes32[] memory) { + bytes32[] memory allPermissions = new bytes32[](1); + allPermissions[0] = ADMIN; + return allPermissions; + } + + function _checkSignatureIsInvalid(bytes memory _data) internal view returns(bool) { + IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); + return dataStore.getBool(keccak256(abi.encodePacked(INVALID_SIG, _data))); + } + + function _checkSigner(address _signer) internal view returns(bool) { + IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); + return dataStore.getBool(keccak256(abi.encodePacked(SIGNER, _signer))); + } + + function _invalidateSignature(bytes memory _data) internal { + IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); + dataStore.setBool(keccak256(abi.encodePacked(INVALID_SIG, _data)), true); + emit SignatureInvalidated(_data); + } +} diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol new file mode 100644 index 000000000..1617a4884 --- /dev/null +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol @@ -0,0 +1,110 @@ +pragma solidity ^0.5.0; + +import "./SignedTransferManager.sol"; +import "../../ModuleFactory.sol"; + +/** + * @title Factory for deploying SignedTransferManager module + */ +contract SignedTransferManagerFactory is ModuleFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + ModuleFactory(_setupCost, _usageCost, _subscriptionCost) + { + version = "1.0.0"; + name = "SignedTransferManager"; + title = "Signed Transfer Manager"; + description = "Manage transfers using a signature"; + compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + } + + + /** + * @notice used to launch the Module with the help of factory + * @return address Contract address of the Module + */ + // function deploy(bytes calldata /* _data */) external returns(address) { + // if (setupCost > 0) + // require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom because of sufficent Allowance is not provided"); + // address signedTransferManager = new SignedTransferManager(msg.sender, address(polyToken)); + // emit GenerateModuleFromFactory(address(signedTransferManager), getName(), address(this), msg.sender, setupCost, now); + // return address(signedTransferManager); + // } + + function deploy(bytes calldata /* _data */) external returns(address) { + address polyToken = _takeFee(); + SignedTransferManager signedTransferManager = new SignedTransferManager(msg.sender, polyToken); + emit GenerateModuleFromFactory(address(signedTransferManager), getName(), address(this), msg.sender, now); + return address(signedTransferManager); + } + + + /** + * @notice Type of the Module factory + */ + function getTypes() external view returns(uint8[] memory) { + uint8[] memory res = new uint8[](2); + res[0] = 2; + res[1] = 6; + return res; + } + + /** + * @notice Get the name of the Module + */ + function getName() public view returns(bytes32) { + return name; + } + + /** + * @notice Get the description of the Module + */ + function getDescription() external view returns(string memory) { + return description; + } + + /** + * @notice Get the version of the Module + */ + function getVersion() external view returns(string memory) { + return version; + } + + /** + * @notice Get the title of the Module + */ + function getTitle() external view returns(string memory) { + return title; + } + + /** + * @notice Get the setup cost of the module + */ + function getSetupCost() external view returns (uint256) { + return setupCost; + } + + /** + * @notice Get the Instructions that helped to used the module + */ + function getInstructions() external view returns(string memory) { + return "Allows an issuer to maintain a list of signers who can validate transfer request using signatures. A mapping is used to track valid signers which can be managed by the issuer. verifytransfer function takes in a signature and if the signature is valid, it will verify the transfer. invalidSigature function allow the signer to make a signature invalid after it is signed. Init function takes no parameters."; + } + + /** + * @notice Get the tags related to the module factory + */ + function getTags() public view returns(bytes32[] memory) { + bytes32[] memory availableTags = new bytes32[](2); + availableTags[0] = "General"; + availableTags[1] = "Transfer Restriction"; + return availableTags; + } + + +} From 938c8e71d5c43686535163d428e8c3d015bed99f Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 24 Jan 2019 15:07:04 +0530 Subject: [PATCH 2/9] web3 updated --- package.json | 2 +- yarn.lock | 332 +++++++++++++++++++++++++-------------------------- 2 files changed, 166 insertions(+), 168 deletions(-) diff --git a/package.json b/package.json index 809f9148e..a30b1040a 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "request-promise": "^4.2.2", "truffle-contract": "^3.0.4", "truffle-hdwallet-provider-privkey": "0.2.0", - "web3": "1.0.0-beta.34" + "web3": "1.0.0-beta.35" }, "devDependencies": { "@soldoc/soldoc": "^0.4.3", diff --git a/yarn.lock b/yarn.lock index fbe3ccc99..05f706a51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -139,7 +139,7 @@ ajv@^6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.5.5, ajv@^6.6.1: +ajv@^6.5.5: version "6.6.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== @@ -196,7 +196,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -318,11 +318,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -2654,10 +2649,10 @@ eslint@^5.8.0: table "^5.0.2" text-table "^0.2.0" -espree@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" - integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA== +espree@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-4.1.0.tgz#728d5451e0fd156c04384a7ad89ed51ff54eb25f" + integrity sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w== dependencies: acorn "^6.0.2" acorn-jsx "^5.0.0" @@ -4238,6 +4233,11 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" +is-resolvable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" @@ -4670,7 +4670,7 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash@4.x, lodash@=4.17.11, lodash@^4.13.1, lodash@^4.14.2, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5: +lodash@4.x, lodash@=4.17.11, lodash@^4.13.1, lodash@^4.14.2, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -6104,7 +6104,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^2.0.1: +regexpp@^2.0.0, regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -6621,13 +6621,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -slice-ansi@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7" - integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ== +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" snapdragon-node@^2.0.1: @@ -7729,87 +7727,87 @@ watchr@~2.4.13: taskgroup "^4.2.0" typechecker "^2.0.8" -web3-bzz@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.34.tgz#068d37777ab65e5c60f8ec8b9a50cfe45277929c" - integrity sha1-Bo03d3q2Xlxg+OyLmlDP5FJ3kpw= +web3-bzz@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.35.tgz#9d5e1362b3db2afd77d65619b7cd46dd5845c192" + integrity sha512-BhAU0qhlr8zltm4gs/+P1gki2VkxHJaM2Rrh4DGesDW0lzwufRoNvWFlwx1bKHoFPWNbSmm9PRkHOYOINL/Tgw== dependencies: got "7.1.0" swarm-js "0.1.37" underscore "1.8.3" -web3-core-helpers@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.34.tgz#b168da00d3e19e156bc15ae203203dd4dfee2d03" - integrity sha1-sWjaANPhnhVrwVriAyA91N/uLQM= +web3-core-helpers@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz#d681d218a0c6e3283ee1f99a078ab9d3eef037f1" + integrity sha512-APOu3sEsamyqWt//8o4yq9KF25/uqGm+pQShson/sC4gKzmfJB07fLo2ond0X30E8fIqAPeVCotPXQxGciGUmA== dependencies: underscore "1.8.3" - web3-eth-iban "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-eth-iban "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-core-method@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.34.tgz#ec163c8a2c490fa02a7ec15559fa7307fc7cc6dd" - integrity sha1-7BY8iixJD6AqfsFVWfpzB/x8xt0= +web3-core-method@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz#fc10e2d546cf4886038e6130bd5726b0952a4e5f" + integrity sha512-jidImCide8q0GpfsO4L73qoHrbkeWgwU3uOH5DKtJtv0ccmG086knNMRgryb/o9ZgetDWLmDEsJnHjBSoIwcbA== dependencies: underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" - web3-core-promievent "1.0.0-beta.34" - web3-core-subscriptions "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" + web3-core-promievent "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-core-promievent@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.34.tgz#a4f4fa6784bb293e82c60960ae5b56a94cd03edc" - integrity sha1-pPT6Z4S7KT6CxglgrltWqUzQPtw= +web3-core-promievent@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz#4f1b24737520fa423fee3afee110fbe82bcb8691" + integrity sha512-GvqXqKq07OmHuVi5uNRg6k79a1/CI0ViCC+EtNv4CORHtDRmYEt5Bvdv6z6FJEiaaQkD0lKbFwNhLxutx7HItw== dependencies: any-promise "1.3.0" eventemitter3 "1.1.1" -web3-core-requestmanager@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.34.tgz#01f8f6cf2ae6b6f0b70c38bae1ef741b5bab215c" - integrity sha1-Afj2zyrmtvC3DDi64e90G1urIVw= +web3-core-requestmanager@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz#2b77cbf6303720ad68899b39fa7f584dc03dbc8f" + integrity sha512-S+zW2h17ZZQU9oe3yaCJE0E7aJS4C3Kf4kGPDv+nXjW0gKhQQhgVhw1Doq/aYQGqNSWJp7f1VHkz5gQWwg6RRg== dependencies: underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" - web3-providers-http "1.0.0-beta.34" - web3-providers-ipc "1.0.0-beta.34" - web3-providers-ws "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" + web3-providers-http "1.0.0-beta.35" + web3-providers-ipc "1.0.0-beta.35" + web3-providers-ws "1.0.0-beta.35" -web3-core-subscriptions@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.34.tgz#9fed144033f221c3cf21060302ffdaf5ef2de2de" - integrity sha1-n+0UQDPyIcPPIQYDAv/a9e8t4t4= +web3-core-subscriptions@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz#c1b76a2ad3c6e80f5d40b8ba560f01e0f4628758" + integrity sha512-gXzLrWvcGkGiWq1y33Z4Y80XI8XMrwowiQJkrPSjQ81K5PBKquOGwcMffLaKcwdmEy/NpsOXDeFo3eLE1Ghvvw== dependencies: eventemitter3 "1.1.1" underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" -web3-core@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.34.tgz#121be8555e9fb00d2c5d05ddd3381d0c9e46987e" - integrity sha1-EhvoVV6fsA0sXQXd0zgdDJ5GmH4= +web3-core@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.35.tgz#0c44d3c50d23219b0b1531d145607a9bc7cd4b4f" + integrity sha512-ayGavbgVk4KL9Y88Uv411fBJ0SVgVfKhKEBweKYzmP0zOqneMzWt6YsyD1n6kRvjAbqA0AfUPEOKyMNjcx2tjw== dependencies: - web3-core-helpers "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-core-requestmanager "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-requestmanager "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-eth-abi@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.34.tgz#034533e3aa2f7e59ff31793eaea685c0ed5af67a" - integrity sha1-A0Uz46ovfln/MXk+rqaFwO1a9no= +web3-eth-abi@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz#2eb9c1c7c7233db04010defcb192293e0db250e6" + integrity sha512-KUDC+EtFFYG8z01ZleKrASdjj327/rtWHzEt6RWsEj7bBa0bGp9nEh+nqdZx/Sdgz1O8tnfFzJlrRcXpfr1vGg== dependencies: bn.js "4.11.6" underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-eth-accounts@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.34.tgz#e09142eeecc797ac3459b75e9b23946d3695f333" - integrity sha1-4JFC7uzHl6w0WbdemyOUbTaV8zM= +web3-eth-accounts@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.35.tgz#7d0e5a69f510dc93874471599eb7abfa9ddf3e63" + integrity sha512-duIgRsfht/0kAW/eQ0X9lKtVIykbETrnM2H7EnvplCzPHtQLodpib4o9JXfh9n6ZDgdDC7cuJoiVB9QJg089ew== dependencies: any-promise "1.3.0" crypto-browserify "3.12.0" @@ -7817,70 +7815,70 @@ web3-eth-accounts@1.0.0-beta.34: scrypt.js "0.2.0" underscore "1.8.3" uuid "2.0.1" - web3-core "1.0.0-beta.34" - web3-core-helpers "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-eth-contract@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.34.tgz#9dbb38fae7643a808427a20180470ec7415c91e6" - integrity sha1-nbs4+udkOoCEJ6IBgEcOx0FckeY= +web3-eth-contract@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.35.tgz#5276242d8a3358d9f1ce92b71575c74f9015935c" + integrity sha512-foPohOg5O1UCGKGZOIs+kQK5IZdV2QQ7pAWwNxH8WHplUA+fre1MurXNpoxknUmH6mYplFhXjqgYq2MsrBpHrA== dependencies: underscore "1.8.3" - web3-core "1.0.0-beta.34" - web3-core-helpers "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-core-promievent "1.0.0-beta.34" - web3-core-subscriptions "1.0.0-beta.34" - web3-eth-abi "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" - -web3-eth-iban@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.34.tgz#9af458605867ccf74ea979aaf326b38ba6a5ba0c" - integrity sha1-mvRYYFhnzPdOqXmq8yazi6alugw= + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-promievent "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-eth-abi "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth-iban@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz#5aa10327a9abb26bcfc4ba79d7bad18a002b332c" + integrity sha512-H5wkcNcAIc+h/WoDIKv7ZYmrM2Xqu3O7jBQl1IWo73EDVQji+AoB2i3J8tuwI1yZRInRwrfpI3Zuwuf54hXHmQ== dependencies: bn.js "4.11.6" - web3-utils "1.0.0-beta.34" + web3-utils "1.0.0-beta.35" -web3-eth-personal@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.34.tgz#9afba167342ebde5420bcd5895c3f6c34388f205" - integrity sha1-mvuhZzQuveVCC81YlcP2w0OI8gU= +web3-eth-personal@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz#ecac95b7a53d04a567447062d5cae5f49879e89f" + integrity sha512-AcM9nnlxu7ZRRxPvkrFB9eLxMM4A2cPfj2aCg21Wb2EpMnhR+b/O1cT33k7ApRowoMpM+T9M8vx2oPNwXfaCOQ== dependencies: - web3-core "1.0.0-beta.34" - web3-core-helpers "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-net "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" -web3-eth@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.34.tgz#74086000850c6fe6f535ef49837d6d4bb6113268" - integrity sha1-dAhgAIUMb+b1Ne9Jg31tS7YRMmg= +web3-eth@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.35.tgz#c52c804afb95e6624b6f5e72a9af90fbf5005b68" + integrity sha512-04mcb2nGPXThawuuYICPOxv0xOHofvQKsjZeIq+89nyOC8DQMGTAErDkGyMHQYtjpth5XDhic0wuEsA80AmFZA== dependencies: underscore "1.8.3" - web3-core "1.0.0-beta.34" - web3-core-helpers "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-core-subscriptions "1.0.0-beta.34" - web3-eth-abi "1.0.0-beta.34" - web3-eth-accounts "1.0.0-beta.34" - web3-eth-contract "1.0.0-beta.34" - web3-eth-iban "1.0.0-beta.34" - web3-eth-personal "1.0.0-beta.34" - web3-net "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" - -web3-net@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.34.tgz#427cea2f431881449c8e38d523290f173f9ff63d" - integrity sha1-QnzqL0MYgUScjjjVIykPFz+f9j0= - dependencies: - web3-core "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-eth-abi "1.0.0-beta.35" + web3-eth-accounts "1.0.0-beta.35" + web3-eth-contract "1.0.0-beta.35" + web3-eth-iban "1.0.0-beta.35" + web3-eth-personal "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-net@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.35.tgz#5c6688e0dea71fcd910ee9dc5437b94b7f6b3354" + integrity sha512-bbwaQ/KohGjIJ6HAKbZ6KrklCAaG6/B7hIbAbVLSFLxF+Yz9lmAgQYaDInpidpC/NLb3WOmcbRF+P77J4qMVIA== + dependencies: + web3-core "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" web3-provider-engine@^13.8.0: version "13.8.0" @@ -7927,46 +7925,46 @@ web3-provider-engine@^8.4.0: xhr "^2.2.0" xtend "^4.0.1" -web3-providers-http@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.34.tgz#e561b52bbb43766282007d40285bfe3550c27e7a" - integrity sha1-5WG1K7tDdmKCAH1AKFv+NVDCfno= +web3-providers-http@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz#92059d9d6de6e9f82f4fae30b743efd841afc1e1" + integrity sha512-DcIMFq52Fb08UpWyZ3ZlES6NsNqJnco4hBS/Ej6eOcASfuUayPI+GLkYVZsnF3cBYqlH+DOKuArcKSuIxK7jIA== dependencies: - web3-core-helpers "1.0.0-beta.34" - xhr2 "0.1.4" + web3-core-helpers "1.0.0-beta.35" + xhr2-cookies "1.1.0" -web3-providers-ipc@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.34.tgz#a1b77f1a306d73649a9c039052e40cb71328d00a" - integrity sha1-obd/GjBtc2SanAOQUuQMtxMo0Ao= +web3-providers-ipc@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz#031afeb10fade2ebb0ef2fb82f5e58c04be842d9" + integrity sha512-iB0FG0HcpUnayfa8pn4guqEQ4Y1nrroi/jffdtQgFkrNt0sD3fMSwwC0AbmECqj3tDLl0e1slBR0RENll+ZF0g== dependencies: oboe "2.1.3" underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" -web3-providers-ws@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.34.tgz#7de70f1b83f2de36476772156becfef6e3516eb3" - integrity sha1-fecPG4Py3jZHZ3IVa+z+9uNRbrM= +web3-providers-ws@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz#5d38603fd450243a26aae0ff7f680644e77fa240" + integrity sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ== dependencies: underscore "1.8.3" - web3-core-helpers "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.35" websocket "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" -web3-shh@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.34.tgz#975061d71eaec42ccee576f7bd8f70f03844afe0" - integrity sha1-l1Bh1x6uxCzO5Xb3vY9w8DhEr+A= +web3-shh@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.35.tgz#7e4a585f8beee0c1927390937c6537748a5d1a58" + integrity sha512-8qSonk/x0xabERS9Sr6AIADN/Ty+5KwARkkGIfSYHKqFpdMDz+76F7cUCxtoCZoS8K04xgZlDKYe0TJXLYA0Fw== dependencies: - web3-core "1.0.0-beta.34" - web3-core-method "1.0.0-beta.34" - web3-core-subscriptions "1.0.0-beta.34" - web3-net "1.0.0-beta.34" + web3-core "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-net "1.0.0-beta.35" -web3-utils@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.34.tgz#9411fc39aaef39ca4e06169f762297d9ff020970" - integrity sha1-lBH8OarvOcpOBhafdiKX2f8CCXA= +web3-utils@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.35.tgz#ced9e1df47c65581c441c5f2af76b05a37a273d7" + integrity sha512-Dq6f0SOKj3BDFRgOPnE6ALbzBDCKVIW8mKWVf7tGVhTDHf+wQaWwQSC3aArFSqdExB75BPBPyDpuMTNszhljpA== dependencies: bn.js "4.11.6" eth-lib "0.1.27" @@ -8009,18 +8007,18 @@ web3@0.20.6: xhr2 "*" xmlhttprequest "*" -web3@1.0.0-beta.34: - version "1.0.0-beta.34" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.34.tgz#347e561b784098cb5563315f490479a1d91f2ab1" - integrity sha1-NH5WG3hAmMtVYzFfSQR5odkfKrE= +web3@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.35.tgz#6475095bd451a96e50a32b997ddee82279292f11" + integrity sha512-xwDmUhvTcHQvvNnOPcPZZgCxKUsI2e+GbHy7JkTK3/Rmnutazy8x7fsAXT9myw7V1qpi3GgLoZ3fkglSUbg1Mg== dependencies: - web3-bzz "1.0.0-beta.34" - web3-core "1.0.0-beta.34" - web3-eth "1.0.0-beta.34" - web3-eth-personal "1.0.0-beta.34" - web3-net "1.0.0-beta.34" - web3-shh "1.0.0-beta.34" - web3-utils "1.0.0-beta.34" + web3-bzz "1.0.0-beta.35" + web3-core "1.0.0-beta.35" + web3-eth "1.0.0-beta.35" + web3-eth-personal "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-shh "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" web3@^0.16.0: version "0.16.0" @@ -8227,14 +8225,14 @@ xhr-request@^1.0.1: url-set-query "^1.0.0" xhr "^2.0.4" -xhr2-cookies@^1.1.0: +xhr2-cookies@1.1.0, xhr2-cookies@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= dependencies: cookiejar "^2.1.1" -xhr2@*, xhr2@0.1.4: +xhr2@*: version "0.1.4" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= From 75a086f7efd0f14ab106c2fe20bbab6b1ba8ef67 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 24 Jan 2019 15:07:14 +0530 Subject: [PATCH 3/9] wip --- test/zb_signed_transfer_manager.js | 305 +++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 test/zb_signed_transfer_manager.js diff --git a/test/zb_signed_transfer_manager.js b/test/zb_signed_transfer_manager.js new file mode 100644 index 000000000..3202ad595 --- /dev/null +++ b/test/zb_signed_transfer_manager.js @@ -0,0 +1,305 @@ +import latestTime from "./helpers/latestTime"; +import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; +import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; +import { signDataVerifyTransfer } from "./helpers/signData"; +import { pk } from "./helpers/testprivateKey"; +import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; +import { catchRevert } from "./helpers/exceptions"; +import { setUpPolymathNetwork, deployGPMAndVerifyed, deployDummySTOAndVerifyed, deploySignedTMAndVerifyed} from "./helpers/createInstances"; + +const DummySTO = artifacts.require("./DummySTO.sol"); +const SecurityToken = artifacts.require("./SecurityToken.sol"); +const GeneralTransferManager = artifacts.require("./GeneralTransferManager"); +const GeneralPermissionManager = artifacts.require("./GeneralPermissionManager"); +const SignedTransferManager = artifacts.require("./SignedTransferManager"); + +const Web3 = require("web3"); +const BigNumber = require("bignumber.js"); +let BN = Web3.utils.BN; +const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port + +contract("SignedTransferManager", accounts => { + // Accounts Variable declaration + let account_polymath; + let account_issuer; + let token_owner; + let token_owner_pk; + let account_investor1; + let account_investor2; + let account_investor3; + let account_investor4; + + // investor Details + let fromTime = latestTime(); + let toTime = latestTime(); + let expiryTime = toTime + duration.days(15); + + let message = "Transaction Should Fail!"; + + // Contract Instance Declaration + let I_GeneralPermissionManagerFactory; + let I_GeneralTransferManagerFactory; + let I_SecurityTokenRegistryProxy; + let I_GeneralPermissionManager; + let I_GeneralTransferManager; + let I_ModuleRegistryProxy; + let I_ModuleRegistry; + let I_FeatureRegistry; + let I_SecurityTokenRegistry; + let I_DummySTOFactory; + let I_STFactory; + let I_SecurityToken; + let I_STRProxied; + let I_MRProxied; + let I_DummySTO; + let I_PolyToken; + let I_PolymathRegistry; + let I_SignedTransferManagerFactory; + let P_SignedTransferManagerFactory; + let I_SignedTransferManager; + + // SecurityToken Details + const name = "Team"; + const symbol = "sap"; + const tokenDetails = "This is equity type of issuance"; + const decimals = 18; + const contact = "team@polymath.network"; + + // Module key + const delegateManagerKey = 1; + const transferManagerKey = 2; + const stoKey = 3; + + // Initial fee for ticker registry and security token registry + const initRegFee = web3.utils.toWei("250"); + + // Dummy STO details + const startTime = latestTime() + duration.seconds(5000); // Start time will be 5000 seconds more than the latest time + const endTime = startTime + duration.days(80); // Add 80 days more + const cap = web3.utils.toWei("10", "ether"); + const someString = "A string which is not used"; + const STOParameters = ["uint256", "uint256", "uint256", "string"]; + + let currentTime; + + before(async () => { + // Accounts setup + currentTime = new BN(await latestTime()); + account_polymath = accounts[0]; + account_issuer = accounts[1]; + + token_owner = account_issuer; + token_owner_pk = pk.account_1; + + account_investor1 = accounts[8]; + account_investor2 = accounts[9]; + account_investor3 = accounts[6]; + account_investor4 = accounts[7]; + + // Step 1: Deploy the genral PM ecosystem + let instances = await setUpPolymathNetwork(account_polymath, token_owner); + + [ + I_PolymathRegistry, + I_PolyToken, + I_FeatureRegistry, + I_ModuleRegistry, + I_ModuleRegistryProxy, + I_MRProxied, + I_GeneralTransferManagerFactory, + I_STFactory, + I_SecurityTokenRegistry, + I_SecurityTokenRegistryProxy, + I_STRProxied + ] = instances; + + // STEP 2: Deploy the GeneralPermissionManagerFactory + [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + // STEP 3: Deploy the SignedTransferManagerFactory + [I_SignedTransferManagerFactory] = await deploySignedTMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + // STEP 4: Deploy the Paid SignedTransferManagerFactory + [P_SignedTransferManagerFactory] = await deploySignedTMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500", "ether")); + + // Printing all the contract addresses + console.log(` + --------------------- Polymath Network Smart Contracts: --------------------- + PolymathRegistry: ${I_PolymathRegistry.address} + SecurityTokenRegistryProxy: ${I_SecurityTokenRegistryProxy.address} + SecurityTokenRegistry: ${I_SecurityTokenRegistry.address} + ModuleRegistryProxy: ${I_ModuleRegistryProxy.address} + ModuleRegistry: ${I_ModuleRegistry.address} + FeatureRegistry: ${I_FeatureRegistry.address} + + ManualApprovalTransferManagerFactory: ${I_SignedTransferManagerFactory.address} + + + ----------------------------------------------------------------------------- + `); + }); + + describe("Generate the SecurityToken", async () => { + it("Should register the ticker before the generation of the security token", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + let tx = await I_STRProxied.registerTicker(token_owner, symbol, contact, { from: token_owner }); + assert.equal(tx.logs[0].args._owner, token_owner); + assert.equal(tx.logs[0].args._ticker, symbol.toUpperCase()); + }); + + it("Should generate the new security token with the same symbol as registered above", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); + + // Verify the successful generation of the security token + assert.equal(tx.logs[2].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); + + I_SecurityToken = await SecurityToken.at(tx.logs[2].args._securityTokenAddress); + + 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(), 2); + assert.equal(web3.utils.toAscii(log.args._name).replace(/\u0000/g, ""), "GeneralTransferManager"); + }); + + it("Should intialize the auto attached modules", async () => { + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; + I_GeneralTransferManager = await GeneralTransferManager.at(moduleData); + }); + }); + + + describe("signed transfer manager tests", async () => { + + it("Should Buy the tokens", async () => { + // Add the Investor in to the whitelist + + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor1, + currentTime, + currentTime, + currentTime.add(new BN(duration.days(10))), + true, + { + from: account_issuer + } + ); + + assert.equal( + tx.logs[0].args._investor.toLowerCase(), + account_investor1.toLowerCase(), + "Failed in adding the investor in whitelist" + ); + + // Jump time + await increaseTime(5000); + + // Mint some tokens + await I_SecurityToken.mint(account_investor1, new BN(web3.utils.toWei("2", "ether")), { from: token_owner }); + + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toString(), new BN(web3.utils.toWei("2", "ether")).toString()); + }); + + + it("Should successfully attach the SignedTransferManager with the security token", async () => { + const tx = await I_SecurityToken.addModule(I_SignedTransferManagerFactory.address, new BN(0),new BN(0),new BN(0), { from: token_owner }); + assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "SignedTransferManager doesn't get deployed"); + assert.equal( + web3.utils.toUtf8(tx.logs[2].args._name), + "SignedTransferManager", + "SignedTransferManager module was not added" + ); + console.log(tx.logs[2].args); + I_SignedTransferManager = await SignedTransferManager.at(tx.logs[2].args._module); + }); + + it("should fail to transfer because transaction is not verified yet.", async () => { + await catchRevert(I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), { from: account_investor1 })); + }); + + it("should successfully add multiple signers to signersList", async () => { + await I_SignedTransferManager.updateSigners([account_investor3, account_investor4, token_owner], [true, true, true], {from: token_owner}); + + assert.equal(await I_SignedTransferManager.signers(account_investor3), true); + assert.equal(await I_SignedTransferManager.signers(account_investor4), true); + assert.equal(await I_SignedTransferManager.signers(token_owner), true); + }); + + it("should fail to change signers stats without permission", async () => { + await catchRevert(I_SignedTransferManager.updateSigners([account_investor3], [false], {from: account_investor2})); + }); + + + it("should be able to invalid siganture if sender is the signer and is in the signer list", async () => { + + console.log("1"); + + const sig = await signDataVerifyTransfer( + I_SignedTransferManager.address, + account_investor1, + account_investor2, + web3.utils.toWei("2", "ether"), + token_owner + ); + + console.log("token owner is "+ token_owner); + console.log(sig); + + await I_SignedTransferManager.invalidSignature(account_investor1, account_investor2, web3.utils.toWei("2", "ether"), sig, {from: token_owner}); + console.log("sd"); + assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); + }); + + it("should allow transfer with valid sig", async () => { + + console.log("owner is a signer status is " + await I_SignedTransferManager.signers(token_owner, {from: token_owner})); + + const sig = await signDataVerifyTransfer( + I_SignedTransferManager.address, + account_investor1, + account_investor2, + web3.utils.toWei("1", "ether"), + token_owner + ); + + // let tx = await I_SignedTransferManager.verifyTransfer(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner}); + console.log("owner token balance is " + (await I_SecurityToken.balanceOf(account_investor1)).toNumber()); + console.log("is this sig invalid?"+ await I_SignedTransferManager.checkSignatureIsInvalid(sig)); + + // test call security token transfer function + let tx = await I_SecurityToken.transferWithData(account_investor2, web3.utils.toWei("1", "ether"), sig, {from: account_investor1}); + console.log("3"); + assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); + }); + + it("should not allow transfer if the sig is already used", async () => { + const sig = await signDataVerifyTransfer( + I_SignedTransferManager.address, + account_investor1, + account_investor2, + web3.utils.toWei("1", "ether"), + token_owner + ); + + console.log("2"); + + await catchRevert (I_SignedTransferManager.verifyTransfer(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner})); + }); + + it("should not allow transfer if the signer is not on the signer list", async () => { + const sig = await signDataVerifyTransfer( + I_SignedTransferManager.address, + account_investor1, + account_investor2, + web3.utils.toWei("1", "ether"), + account_investor2 + ); + + let tx = await I_SignedTransferManager.verifyTransfer.call(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner}); + console.log("output is "+tx.toNumber()); + + }); + + }); +}); + From 2c2c4996e9897763300a548b67f3e57b95b5345f Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 24 Jan 2019 15:22:05 +0530 Subject: [PATCH 4/9] Fixed compilation --- .../Experimental/TransferManager/SignedTransferManager.sol | 4 ++-- .../TransferManager/SignedTransferManagerFactory.sol | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol index 236182e1e..b72241eca 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol @@ -63,7 +63,7 @@ contract SignedTransferManager is TransferManager { * @param _signers address array of signers * @param _signersStats bool array of signers stats */ - function updateSigners(address[] memory _signers, bool[] memory _signersStats) external withPerm(ADMIN) { + function updateSigners(address[] calldata _signers, bool[] calldata _signersStats) external withPerm(ADMIN) { require(_signers.length == _signersStats.length, "Array length mismatch"); IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); for(uint256 i=0; i<_signers.length; i++) { @@ -118,7 +118,7 @@ contract SignedTransferManager is TransferManager { * Signer needs to be in the signers mapping */ function invalidateSignature(address _from, address _to, uint256 _amount, bytes calldata _data) external { - require(_checkSigner(signer), "Unauthorized Signer"); + require(_checkSigner(msg.sender), "Unauthorized Signer"); require(!_checkSignatureIsInvalid(_data), "Signature already invalid"); bytes32 hash = keccak256(abi.encodePacked(this, _from, _to, _amount)); diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol index 1617a4884..d38d82758 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol @@ -10,9 +10,8 @@ contract SignedTransferManagerFactory is ModuleFactory { /** * @notice Constructor - * @param _polyAddress Address of the polytoken */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + constructor (uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_setupCost, _usageCost, _subscriptionCost) { version = "1.0.0"; From 6c99e9eef1c1820d35216b6bbafc790bd86279ef Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 24 Jan 2019 17:01:49 +0530 Subject: [PATCH 5/9] Added tests --- test/helpers/createInstances.js | 14 ++++ test/helpers/signData.js | 9 ++- test/zb_signed_transfer_manager.js | 102 +++++++++++------------------ 3 files changed, 61 insertions(+), 64 deletions(-) diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index d8d9b93da..332767d8d 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -41,6 +41,7 @@ const STRGetter = artifacts.require("./STRGetter.sol"); const MockWrongTypeFactory = artifacts.require("./MockWrongTypeFactory.sol"); const DataStoreLogic = artifacts.require('./DataStore.sol'); const DataStoreFactory = artifacts.require('./DataStoreFactory.sol'); +const SignedTransferManagerFactory = artifacts.require("./SignedTransferManagerFactory"); const Web3 = require("web3"); let BN = Web3.utils.BN; @@ -88,6 +89,7 @@ let I_SecurityTokenRegistryProxy; let I_STRProxied; let I_MRProxied; let I_STRGetter; +let I_SignedTransferManagerFactory; // Initial fee for ticker registry and security token registry const initRegFee = new BN(web3.utils.toWei("250")); @@ -494,3 +496,15 @@ export async function deployMockWrongTypeRedemptionAndVerifyed(accountPolymath, await registerAndVerifyByMR(I_MockWrongTypeBurnFactory.address, accountPolymath, MRProxyInstance); return Promise.all(new Array(I_MockWrongTypeBurnFactory)); } + +export async function deploySignedTMAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { + I_SignedTransferManagerFactory = await SignedTransferManagerFactory.new(setupCost, 0, 0, { from: accountPolymath }); + assert.notEqual( + I_SignedTransferManagerFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "SignedTransferManagerFactory contract was not deployed" + ); + + await registerAndVerifyByMR(I_SignedTransferManagerFactory.address, accountPolymath, MRProxyInstance); + return new Array(I_SignedTransferManagerFactory); +} \ No newline at end of file diff --git a/test/helpers/signData.js b/test/helpers/signData.js index f75572450..581ebcea9 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -18,6 +18,13 @@ function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, rest return ethUtil.ecsign(new Buffer(packedData.slice(2), "hex"), new Buffer(pk, "hex")); } +function getSignTMSig(tmAddress, fromAddress, toAddress, amount, pk) { + let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'address', v: fromAddress}, {t: 'address', v: toAddress}, {t: 'uint256', v: new BN(amount)}); + let sign = web3.eth.accounts.sign(hash, pk); + return sign.signature; +} + module.exports = { - signData + signData, + getSignTMSig }; diff --git a/test/zb_signed_transfer_manager.js b/test/zb_signed_transfer_manager.js index 3202ad595..10859d1ab 100644 --- a/test/zb_signed_transfer_manager.js +++ b/test/zb_signed_transfer_manager.js @@ -1,11 +1,11 @@ import latestTime from "./helpers/latestTime"; import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; -import { signDataVerifyTransfer } from "./helpers/signData"; +import { getSignTMSig } from "./helpers/signData"; import { pk } from "./helpers/testprivateKey"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; -import { setUpPolymathNetwork, deployGPMAndVerifyed, deployDummySTOAndVerifyed, deploySignedTMAndVerifyed} from "./helpers/createInstances"; +import { setUpPolymathNetwork, deployGPMAndVerifyed, deploySignedTMAndVerifyed} from "./helpers/createInstances"; const DummySTO = artifacts.require("./DummySTO.sol"); const SecurityToken = artifacts.require("./SecurityToken.sol"); @@ -29,13 +29,6 @@ contract("SignedTransferManager", accounts => { let account_investor3; let account_investor4; - // investor Details - let fromTime = latestTime(); - let toTime = latestTime(); - let expiryTime = toTime + duration.days(15); - - let message = "Transaction Should Fail!"; - // Contract Instance Declaration let I_GeneralPermissionManagerFactory; let I_GeneralTransferManagerFactory; @@ -73,13 +66,6 @@ contract("SignedTransferManager", accounts => { // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); - // Dummy STO details - const startTime = latestTime() + duration.seconds(5000); // Start time will be 5000 seconds more than the latest time - const endTime = startTime + duration.days(80); // Add 80 days more - const cap = web3.utils.toWei("10", "ether"); - const someString = "A string which is not used"; - const STOParameters = ["uint256", "uint256", "uint256", "string"]; - let currentTime; before(async () => { @@ -209,7 +195,6 @@ contract("SignedTransferManager", accounts => { "SignedTransferManager", "SignedTransferManager module was not added" ); - console.log(tx.logs[2].args); I_SignedTransferManager = await SignedTransferManager.at(tx.logs[2].args._module); }); @@ -220,9 +205,9 @@ contract("SignedTransferManager", accounts => { it("should successfully add multiple signers to signersList", async () => { await I_SignedTransferManager.updateSigners([account_investor3, account_investor4, token_owner], [true, true, true], {from: token_owner}); - assert.equal(await I_SignedTransferManager.signers(account_investor3), true); - assert.equal(await I_SignedTransferManager.signers(account_investor4), true); - assert.equal(await I_SignedTransferManager.signers(token_owner), true); + assert.equal(await I_SignedTransferManager.checkSigner(account_investor3), true); + assert.equal(await I_SignedTransferManager.checkSigner(account_investor4), true); + assert.equal(await I_SignedTransferManager.checkSigner(token_owner), true); }); it("should fail to change signers stats without permission", async () => { @@ -230,76 +215,67 @@ contract("SignedTransferManager", accounts => { }); - it("should be able to invalid siganture if sender is the signer and is in the signer list", async () => { - - console.log("1"); + it("should allow to invalidate siganture if sender is the signer and is in the signer list", async () => { + let oneeth = new BN(web3.utils.toWei("1", "ether")); + let signer = web3.eth.accounts.create(); + await web3.eth.personal.importRawKey(signer.privateKey, ""); + await web3.eth.personal.unlockAccount(signer.address, "", 6000); + await web3.eth.sendTransaction({ from: token_owner, to: signer.address, value: oneeth }); - const sig = await signDataVerifyTransfer( + await I_SignedTransferManager.updateSigners([signer.address], [true], {from: token_owner}); + + const sig = await getSignTMSig( I_SignedTransferManager.address, account_investor1, account_investor2, - web3.utils.toWei("2", "ether"), - token_owner + oneeth, + signer.privateKey ); - console.log("token owner is "+ token_owner); - console.log(sig); - - await I_SignedTransferManager.invalidSignature(account_investor1, account_investor2, web3.utils.toWei("2", "ether"), sig, {from: token_owner}); - console.log("sd"); + assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), false); + await I_SignedTransferManager.invalidateSignature(account_investor1, account_investor2, oneeth, sig, {from: signer.address}); assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); }); it("should allow transfer with valid sig", async () => { + let signer = web3.eth.accounts.create(); + await I_SignedTransferManager.updateSigners([signer.address], [true], {from: token_owner}); + let oneeth = new BN(web3.utils.toWei("1", "ether")); - console.log("owner is a signer status is " + await I_SignedTransferManager.signers(token_owner, {from: token_owner})); - - const sig = await signDataVerifyTransfer( + const sig = await getSignTMSig( I_SignedTransferManager.address, account_investor1, account_investor2, - web3.utils.toWei("1", "ether"), - token_owner + oneeth, + signer.privateKey ); - // let tx = await I_SignedTransferManager.verifyTransfer(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner}); - console.log("owner token balance is " + (await I_SecurityToken.balanceOf(account_investor1)).toNumber()); - console.log("is this sig invalid?"+ await I_SignedTransferManager.checkSignatureIsInvalid(sig)); - - // test call security token transfer function - let tx = await I_SecurityToken.transferWithData(account_investor2, web3.utils.toWei("1", "ether"), sig, {from: account_investor1}); - console.log("3"); + let balance11 = await I_SecurityToken.balanceOf(account_investor1); + let balance21 = await I_SecurityToken.balanceOf(account_investor2); + + await I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1}); + assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); - }); + assert.equal(balance11.sub(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor1)).toString()); + assert.equal(balance21.add(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor2)).toString()); - it("should not allow transfer if the sig is already used", async () => { - const sig = await signDataVerifyTransfer( - I_SignedTransferManager.address, - account_investor1, - account_investor2, - web3.utils.toWei("1", "ether"), - token_owner - ); - - console.log("2"); - - await catchRevert (I_SignedTransferManager.verifyTransfer(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner})); + await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1})); }); it("should not allow transfer if the signer is not on the signer list", async () => { - const sig = await signDataVerifyTransfer( + let signer = web3.eth.accounts.create(); + let oneeth = new BN(web3.utils.toWei("1", "ether")); + + const sig = await getSignTMSig( I_SignedTransferManager.address, account_investor1, account_investor2, - web3.utils.toWei("1", "ether"), - account_investor2 + oneeth, + signer.privateKey ); - let tx = await I_SignedTransferManager.verifyTransfer.call(account_investor1, account_investor2, web3.utils.toWei("1", "ether"), sig, false, {from: token_owner}); - console.log("output is "+tx.toNumber()); - + await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1})); }); - }); }); From ea444a0755d74dd97dba197ff052c4eb304a533b Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Fri, 25 Jan 2019 13:42:38 +0530 Subject: [PATCH 6/9] Added more params to hash input --- .../TransferManager/SignedTransferManager.sol | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol index b72241eca..908fb26be 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol @@ -50,8 +50,15 @@ contract SignedTransferManager is TransferManager { * @notice function to check if a signature is still valid * @param _data signature */ - function checkSignatureIsInvalid(bytes calldata _data) external view returns(bool) { - return _checkSignatureIsInvalid(_data); + function checkSignatureValidity(bytes calldata _data) external view returns(bool) { + address targetAddress; + uint256 nonce; + uint256 expiry; + bytes memory signature; + (targetAddress, nonce, expiry, signature) = abi.decode(_data, (address, uint256, uint256, bytes)); + if (targetAddress != address(this) || expiry < now || signature.length == 0 || _checkSignatureIsInvalid(signature)) + return false; + return true; } function checkSigner(address _signer) external view returns(bool) { @@ -88,18 +95,26 @@ contract SignedTransferManager is TransferManager { require (_isTransfer == false || msg.sender == securityToken, "Sender is not ST"); - if (_data.length == 0 || _checkSignatureIsInvalid(_data)) { + if (_data.length == 0) return Result.NA; - } - bytes32 hash = keccak256(abi.encodePacked(this, _from, _to, _amount)); + address targetAddress; + uint256 nonce; + uint256 expiry; + bytes memory signature; + (targetAddress, nonce, expiry, signature) = abi.decode(_data, (address, uint256, uint256, bytes)); + + if (address(this) != targetAddress || signature.length == 0 || _checkSignatureIsInvalid(signature) || expiry < now) + return Result.NA; + + bytes32 hash = keccak256(abi.encodePacked(targetAddress, nonce, expiry, _from, _to, _amount)); bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); - address signer = _recoverSignerAdd(prependedHash, _data); + address signer = _recoverSignerAdd(prependedHash, signature); if (!_checkSigner(signer)) { return Result.NA; } else if(_isTransfer) { - _invalidateSignature(_data); + _invalidateSignature(signature); return Result.VALID; } else { return Result.VALID; @@ -119,14 +134,22 @@ contract SignedTransferManager is TransferManager { */ function invalidateSignature(address _from, address _to, uint256 _amount, bytes calldata _data) external { require(_checkSigner(msg.sender), "Unauthorized Signer"); - require(!_checkSignatureIsInvalid(_data), "Signature already invalid"); + + address targetAddress; + uint256 nonce; + uint256 expiry; + bytes memory signature; + (targetAddress, nonce, expiry, signature) = abi.decode(_data, (address, uint256, uint256, bytes)); + + require(!_checkSignatureIsInvalid(signature), "Signature already invalid"); + require(targetAddress != address(this), "Signature not for this module"); - bytes32 hash = keccak256(abi.encodePacked(this, _from, _to, _amount)); + bytes32 hash = keccak256(abi.encodePacked(targetAddress, nonce, expiry, _from, _to, _amount)); bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); - require(_recoverSignerAdd(prependedHash, _data) == msg.sender, "Incorrect Signer"); + require(_recoverSignerAdd(prependedHash, signature) == msg.sender, "Incorrect Signer"); - _invalidateSignature(_data); + _invalidateSignature(signature); } /** From f3dc1b38acb1946604932d742ad187a20c4321e2 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Fri, 25 Jan 2019 13:42:53 +0530 Subject: [PATCH 7/9] code comments for data store --- contracts/datastore/DataStore.sol | 1 + contracts/tokens/STFactory.sol | 1 + 2 files changed, 2 insertions(+) diff --git a/contracts/datastore/DataStore.sol b/contracts/datastore/DataStore.sol index 29d2e2b1d..c722d49d1 100644 --- a/contracts/datastore/DataStore.sol +++ b/contracts/datastore/DataStore.sol @@ -43,6 +43,7 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _securityToken address of the security token */ function setSecurityToken(address _securityToken) external onlyOwner { + //NB When dataStore is generated, the security token address is automatically set via the constructor in DataStoreProxy. if(address(securityToken) != address(0)) { require(msg.sender == IOwnable(address(securityToken)).owner(), "Unauthorized"); } diff --git a/contracts/tokens/STFactory.sol b/contracts/tokens/STFactory.sol index d00e7e192..8c78c04ff 100644 --- a/contracts/tokens/STFactory.sol +++ b/contracts/tokens/STFactory.sol @@ -41,6 +41,7 @@ contract STFactory is ISTFactory { _polymathRegistry ); newSecurityToken.addModule(transferManagerFactory, "", 0, 0); + //NB When dataStore is generated, the security token address is automatically set via the constructor in DataStoreProxy. newSecurityToken.changeDataStore(dataStoreFactory.generateDataStore(address(newSecurityToken))); newSecurityToken.transferOwnership(_issuer); return address(newSecurityToken); From 772d2f29ef619e738aed39ece54fce9c1eba66cd Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Fri, 25 Jan 2019 14:10:15 +0530 Subject: [PATCH 8/9] Updated tests --- .../TransferManager/SignedTransferManager.sol | 2 +- test/helpers/signData.js | 11 ++--- test/zb_signed_transfer_manager.js | 40 +++++++++++++------ 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol index 908fb26be..ea7edffe9 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol @@ -142,7 +142,7 @@ contract SignedTransferManager is TransferManager { (targetAddress, nonce, expiry, signature) = abi.decode(_data, (address, uint256, uint256, bytes)); require(!_checkSignatureIsInvalid(signature), "Signature already invalid"); - require(targetAddress != address(this), "Signature not for this module"); + require(targetAddress == address(this), "Signature not for this module"); bytes32 hash = keccak256(abi.encodePacked(targetAddress, nonce, expiry, _from, _to, _amount)); bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); diff --git a/test/helpers/signData.js b/test/helpers/signData.js index 581ebcea9..cb551102e 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -18,13 +18,14 @@ function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, rest return ethUtil.ecsign(new Buffer(packedData.slice(2), "hex"), new Buffer(pk, "hex")); } -function getSignTMSig(tmAddress, fromAddress, toAddress, amount, pk) { - let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'address', v: fromAddress}, {t: 'address', v: toAddress}, {t: 'uint256', v: new BN(amount)}); - let sign = web3.eth.accounts.sign(hash, pk); - return sign.signature; +function getSignTMData(tmAddress, nonce, expiry, fromAddress, toAddress, amount, pk) { + let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'uint256', v: new BN(nonce)}, {t: 'uint256', v: new BN(expiry)}, {t: 'address', v: fromAddress}, {t: 'address', v: toAddress}, {t: 'uint256', v: new BN(amount)}); + let signature = (web3.eth.accounts.sign(hash, pk)).signature; + let data = web3.eth.abi.encodeParameters(['address', 'uint256', 'uint256', 'bytes'], [tmAddress, new BN(nonce).toString(), new BN(expiry).toString(), signature]); + return data; } module.exports = { signData, - getSignTMSig + getSignTMData }; diff --git a/test/zb_signed_transfer_manager.js b/test/zb_signed_transfer_manager.js index 10859d1ab..e13b99f46 100644 --- a/test/zb_signed_transfer_manager.js +++ b/test/zb_signed_transfer_manager.js @@ -1,7 +1,7 @@ import latestTime from "./helpers/latestTime"; import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; -import { getSignTMSig } from "./helpers/signData"; +import { getSignTMData } from "./helpers/signData"; import { pk } from "./helpers/testprivateKey"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; @@ -224,26 +224,33 @@ contract("SignedTransferManager", accounts => { await I_SignedTransferManager.updateSigners([signer.address], [true], {from: token_owner}); - const sig = await getSignTMSig( + let nonce = new BN(10); + let expiry = new BN(currentTime.add(new BN(duration.days(100)))); + let data = await getSignTMData( I_SignedTransferManager.address, + nonce, + expiry, account_investor1, account_investor2, oneeth, signer.privateKey ); - assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), false); - await I_SignedTransferManager.invalidateSignature(account_investor1, account_investor2, oneeth, sig, {from: signer.address}); - assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); + assert.equal(await I_SignedTransferManager.checkSignatureValidity(data), true); + await I_SignedTransferManager.invalidateSignature(account_investor1, account_investor2, oneeth, data, {from: signer.address}); + assert.equal(await I_SignedTransferManager.checkSignatureValidity(data), false); }); it("should allow transfer with valid sig", async () => { let signer = web3.eth.accounts.create(); await I_SignedTransferManager.updateSigners([signer.address], [true], {from: token_owner}); let oneeth = new BN(web3.utils.toWei("1", "ether")); - - const sig = await getSignTMSig( + let nonce = new BN(10); + let expiry = new BN(currentTime.add(new BN(duration.days(100)))); + let data = await getSignTMData( I_SignedTransferManager.address, + nonce, + expiry, account_investor1, account_investor2, oneeth, @@ -253,28 +260,35 @@ contract("SignedTransferManager", accounts => { let balance11 = await I_SecurityToken.balanceOf(account_investor1); let balance21 = await I_SecurityToken.balanceOf(account_investor2); - await I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1}); + assert.equal(await I_SignedTransferManager.checkSignatureValidity(data), true); + + await I_SecurityToken.transferWithData(account_investor2, oneeth, data, {from: account_investor1}); + + assert.equal(await I_SignedTransferManager.checkSignatureValidity(data), false); + await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, data, {from: account_investor1})); - assert.equal(await I_SignedTransferManager.checkSignatureIsInvalid(sig), true); assert.equal(balance11.sub(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor1)).toString()); assert.equal(balance21.add(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor2)).toString()); - await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1})); + }); it("should not allow transfer if the signer is not on the signer list", async () => { let signer = web3.eth.accounts.create(); let oneeth = new BN(web3.utils.toWei("1", "ether")); - - const sig = await getSignTMSig( + let nonce = new BN(10); + let expiry = new BN(currentTime.add(new BN(duration.days(100)))); + let data = await getSignTMData( I_SignedTransferManager.address, + nonce, + expiry, account_investor1, account_investor2, oneeth, signer.privateKey ); - await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, sig, {from: account_investor1})); + await catchRevert(I_SecurityToken.transferWithData(account_investor2, oneeth, data, {from: account_investor1})); }); }); }); From 5934f5429b37a37ccda686506fe8e5659316eaa4 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 31 Jan 2019 09:08:50 -0400 Subject: [PATCH 9/9] Signing: Use library and improve tests --- .../TransferManager/SignedTransferManager.sol | 43 +----- .../SignedTransferManagerFactory.sol | 4 +- .../GeneralTransferManager.sol | 16 +- test/h_general_transfer_manager.js | 138 ++++++++++-------- test/helpers/signData.js | 13 +- test/zb_signed_transfer_manager.js | 17 +-- 6 files changed, 111 insertions(+), 120 deletions(-) diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol index ea7edffe9..94931675d 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManager.sol @@ -4,12 +4,14 @@ import "../../TransferManager/TransferManager.sol"; import "../../../interfaces/IDataStore.sol"; import "../../../interfaces/ISecurityToken.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; /** * @title Transfer Manager module for verifing transations with a signed message */ contract SignedTransferManager is TransferManager { using SafeMath for uint256; + using ECDSA for bytes32; bytes32 constant public ADMIN = "ADMIN"; @@ -25,7 +27,7 @@ contract SignedTransferManager is TransferManager { event SignersUpdated(address[] _signers, bool[] _signersStats); // Emit when a signature has been deemed invalid - event SignatureInvalidated(bytes _data); + event SignatureUsed(bytes _data); /** @@ -108,8 +110,7 @@ contract SignedTransferManager is TransferManager { return Result.NA; bytes32 hash = keccak256(abi.encodePacked(targetAddress, nonce, expiry, _from, _to, _amount)); - bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); - address signer = _recoverSignerAdd(prependedHash, signature); + address signer = hash.toEthSignedMessageHash().recover(signature); if (!_checkSigner(signer)) { return Result.NA; @@ -134,7 +135,7 @@ contract SignedTransferManager is TransferManager { */ function invalidateSignature(address _from, address _to, uint256 _amount, bytes calldata _data) external { require(_checkSigner(msg.sender), "Unauthorized Signer"); - + address targetAddress; uint256 nonce; uint256 expiry; @@ -145,41 +146,11 @@ contract SignedTransferManager is TransferManager { require(targetAddress == address(this), "Signature not for this module"); bytes32 hash = keccak256(abi.encodePacked(targetAddress, nonce, expiry, _from, _to, _amount)); - bytes32 prependedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); - - require(_recoverSignerAdd(prependedHash, signature) == msg.sender, "Incorrect Signer"); + require(hash.toEthSignedMessageHash().recover(signature) == msg.sender, "Incorrect Signer"); _invalidateSignature(signature); } - /** - * @notice used to recover signers' address from signature - */ - function _recoverSignerAdd(bytes32 _hash, bytes memory _data) internal pure returns(address) { - - if (_data.length != 65) { - return address(0); - } - - bytes32 r; - bytes32 s; - uint8 v; - - assembly { - r := mload(add(_data, 32)) - s := mload(add(_data, 64)) - v := and(mload(add(_data, 65)), 255) - } - if (v < 27) { - v += 27; - } - if (v != 27 && v != 28) { - - } - - return ecrecover(_hash, v, r, s); - } - /** * @notice Return the permissions flag that are associated with ManualApproval transfer manager */ @@ -202,6 +173,6 @@ contract SignedTransferManager is TransferManager { function _invalidateSignature(bytes memory _data) internal { IDataStore dataStore = IDataStore(ISecurityToken(securityToken).dataStore()); dataStore.setBool(keccak256(abi.encodePacked(INVALID_SIG, _data)), true); - emit SignatureInvalidated(_data); + emit SignatureUsed(_data); } } diff --git a/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol index d38d82758..bf23eedf8 100644 --- a/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol +++ b/contracts/modules/Experimental/TransferManager/SignedTransferManagerFactory.sol @@ -38,7 +38,7 @@ contract SignedTransferManagerFactory is ModuleFactory { function deploy(bytes calldata /* _data */) external returns(address) { address polyToken = _takeFee(); SignedTransferManager signedTransferManager = new SignedTransferManager(msg.sender, polyToken); - emit GenerateModuleFromFactory(address(signedTransferManager), getName(), address(this), msg.sender, now); + emit GenerateModuleFromFactory(address(signedTransferManager), getName(), address(this), msg.sender, setupCost, now); return address(signedTransferManager); } @@ -100,7 +100,7 @@ contract SignedTransferManagerFactory is ModuleFactory { */ function getTags() public view returns(bytes32[] memory) { bytes32[] memory availableTags = new bytes32[](2); - availableTags[0] = "General"; + availableTags[0] = "Signed"; availableTags[1] = "Transfer Restriction"; return availableTags; } diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index b4889dd36..746b994c2 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -4,12 +4,14 @@ import "./TransferManager.sol"; import "../../storage/GeneralTransferManagerStorage.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../../interfaces/ISecurityToken.sol"; +import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManager { using SafeMath for uint256; + using ECDSA for bytes32; // Emit when Issuance address get changed event ChangeIssuanceAddress(address _issuanceAddress); @@ -257,9 +259,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage * @param _validFrom is the time that this signature is valid from * @param _validTo is the time that this signature is valid until * @param _nonce nonce of signature (avoid replay attack) - * @param _v issuer signature - * @param _r issuer signature - * @param _s issuer signature + * @param _signature issuer signature */ function modifyWhitelistSigned( address _investor, @@ -270,9 +270,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage uint256 _validFrom, uint256 _validTo, uint256 _nonce, - uint8 _v, - bytes32 _r, - bytes32 _s + bytes memory _signature ) public { @@ -285,17 +283,17 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage bytes32 hash = keccak256( abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _validFrom, _validTo, _nonce) ); - _checkSig(hash, _v, _r, _s); + _checkSig(hash, _signature); _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** * @notice Used to verify the signature */ - function _checkSig(bytes32 _hash, uint8 _v, bytes32 _r, bytes32 _s) internal view { + function _checkSig(bytes32 _hash, bytes memory _signature) internal view { //Check that the signature is valid //sig should be signing - _investor, _fromTime, _toTime & _expiryTime and be signed by the issuer address - address signer = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)), _v, _r, _s); + address signer = _hash.toEthSignedMessageHash().recover(_signature); require(signer == Ownable(securityToken).owner() || signer == signingAddress, "Incorrect signer"); } diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 83f297ae7..03c22b23f 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -1,7 +1,7 @@ import latestTime from "./helpers/latestTime"; import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; -import { signData } from "./helpers/signData"; +import { getSignGTMData, signData } from "./helpers/signData"; import { pk } from "./helpers/testprivateKey"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; @@ -84,6 +84,7 @@ contract("GeneralTransferManager", async (accounts) => { let currentTime; const address_zero = "0x0000000000000000000000000000000000000000"; const one_address = "0x0000000000000000000000000000000000000001"; + let signer; before(async () => { currentTime = new BN(await latestTime()); @@ -108,6 +109,12 @@ contract("GeneralTransferManager", async (accounts) => { account_affiliates1 = accounts[3]; account_affiliates2 = accounts[4]; + let oneeth = new BN(web3.utils.toWei("1", "ether")); + signer = web3.eth.accounts.create(); + await web3.eth.personal.importRawKey(signer.privateKey, ""); + await web3.eth.personal.unlockAccount(signer.address, "", 6000); + await web3.eth.sendTransaction({ from: token_owner, to: signer.address, value: oneeth }); + // Step 1: Deploy the genral PM ecosystem let instances = await setUpPolymathNetwork(account_polymath, token_owner); @@ -444,13 +451,29 @@ contract("GeneralTransferManager", async (accounts) => { await catchRevert(I_DummySTO.generateTokens(account_investor2, new BN(web3.utils.toWei("1", "ether")), { from: token_owner })); }); + it("Should provide the permission and change the signing address", async () => { + let log = await I_GeneralPermissionManager.addDelegate(account_delegate, web3.utils.fromAscii("My details"), { from: token_owner }); + assert.equal(log.logs[0].args._delegate, account_delegate); + + await I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, web3.utils.fromAscii("FLAGS"), true, { + from: token_owner + }); + + assert.isTrue( + await I_GeneralPermissionManager.checkPermission.call(account_delegate, I_GeneralTransferManager.address, web3.utils.fromAscii("FLAGS")) + ); + console.log(JSON.stringify(signer)); + let tx = await I_GeneralTransferManager.changeSigningAddress(signer.address, { from: account_delegate }); + assert.equal(tx.logs[0].args._signingAddress, signer.address); + }); + it("Should buy the tokens -- Failed due to incorrect signature input", async () => { // Add the Investor in to the whitelist //tmAddress, investorAddress, fromTime, toTime, validFrom, validTo, pk let validFrom = await latestTime(); let validTo = await latestTime() + duration.days(5); let nonce = 5; - const sig = signData( + const sig = getSignGTMData( account_investor2, account_investor2, fromTime, @@ -460,13 +483,9 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - token_owner_pk + signer.privateKey ); - const r = `0x${sig.r.toString("hex")}`; - const s = `0x${sig.s.toString("hex")}`; - const v = sig.v; - await catchRevert( I_GeneralTransferManager.modifyWhitelistSigned( account_investor2, @@ -477,9 +496,7 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - v, - r, - s, + sig, { from: account_investor2, gas: 6000000 @@ -494,7 +511,7 @@ contract("GeneralTransferManager", async (accounts) => { let validFrom = await latestTime() - 100; let validTo = await latestTime() - 1; let nonce = 5; - const sig = signData( + const sig = getSignGTMData( I_GeneralTransferManager.address, account_investor2, fromTime, @@ -504,13 +521,9 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - token_owner_pk + signer.privateKey ); - const r = `0x${sig.r.toString("hex")}`; - const s = `0x${sig.s.toString("hex")}`; - const v = sig.v; - await catchRevert( I_GeneralTransferManager.modifyWhitelistSigned( account_investor2, @@ -521,9 +534,7 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - v, - r, - s, + sig, { from: account_investor2, gas: 6000000 @@ -538,7 +549,7 @@ contract("GeneralTransferManager", async (accounts) => { let validFrom = await latestTime(); let validTo = await latestTime() + 60 * 60; let nonce = 5; - const sig = signData( + const sig = getSignGTMData( account_investor2, account_investor2, fromTime, @@ -551,10 +562,6 @@ contract("GeneralTransferManager", async (accounts) => { "2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200" ); - const r = `0x${sig.r.toString("hex")}`; - const s = `0x${sig.s.toString("hex")}`; - const v = sig.v; - await catchRevert( I_GeneralTransferManager.modifyWhitelistSigned( account_investor2, @@ -565,9 +572,7 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - v, - r, - s, + sig, { from: account_investor2, gas: 6000000 @@ -576,13 +581,13 @@ contract("GeneralTransferManager", async (accounts) => { ); }); - it("Should Buy the tokens", async () => { + it("Should Buy the tokens with signers signature", async () => { // Add the Investor in to the whitelist //tmAddress, investorAddress, fromTime, toTime, validFrom, validTo, pk let validFrom = await latestTime(); let validTo = await latestTime() + duration.days(5); let nonce = 5; - const sig = signData( + const sig = getSignGTMData( I_GeneralTransferManager.address, account_investor2, currentTime.toNumber(), @@ -592,13 +597,9 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - token_owner_pk + signer.privateKey ); - const r = `0x${sig.r.toString("hex")}`; - const s = `0x${sig.s.toString("hex")}`; - const v = sig.v; - let tx = await I_GeneralTransferManager.modifyWhitelistSigned( account_investor2, currentTime.toNumber(), @@ -608,9 +609,7 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - v, - r, - s, + sig, { from: account_investor2, gas: 6000000 @@ -638,7 +637,7 @@ contract("GeneralTransferManager", async (accounts) => { let validFrom = await latestTime(); let validTo = await latestTime() + duration.days(5); let nonce = 5; - const sig = signData( + const sig = getSignGTMData( I_GeneralTransferManager.address, account_investor2, currentTime.toNumber(), @@ -648,13 +647,9 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - token_owner_pk + signer.privateKey ); - const r = `0x${sig.r.toString("hex")}`; - const s = `0x${sig.s.toString("hex")}`; - const v = sig.v; - await catchRevert( I_GeneralTransferManager.modifyWhitelistSigned( account_investor2, @@ -665,9 +660,7 @@ contract("GeneralTransferManager", async (accounts) => { validFrom, validTo, nonce, - v, - r, - s, + sig, { from: account_investor2, gas: 6000000 @@ -676,6 +669,43 @@ contract("GeneralTransferManager", async (accounts) => { ); }); + it("Should sign with token owner key", async () => { + // Add the Investor in to the whitelist + //tmAddress, investorAddress, fromTime, toTime, validFrom, validTo, pk + let validFrom = await latestTime(); + let validTo = await latestTime() + duration.days(5); + let nonce = 6; + const sig = getSignGTMData( + I_GeneralTransferManager.address, + account_investor2, + currentTime.toNumber(), + currentTime.add(new BN(duration.days(100))).toNumber(), + expiryTime + duration.days(200), + true, + validFrom, + validTo, + nonce, + "0x" + token_owner_pk + ); + + await I_GeneralTransferManager.modifyWhitelistSigned( + account_investor2, + currentTime.toNumber(), + currentTime.add(new BN(duration.days(100))).toNumber(), + expiryTime + duration.days(200), + true, + validFrom, + validTo, + nonce, + sig, + { + from: account_investor2, + gas: 6000000 + } + ) + + }); + it("Should fail in changing the signing address", async () => { await catchRevert(I_GeneralTransferManager.changeSigningAddress(account_polymath, { from: account_investor4 })); }); @@ -686,22 +716,6 @@ contract("GeneralTransferManager", async (accounts) => { assert.equal(web3.utils.toAscii(perm[1]).replace(/\u0000/g, ""), "FLAGS"); }); - it("Should provide the permission and change the signing address", async () => { - let log = await I_GeneralPermissionManager.addDelegate(account_delegate, web3.utils.fromAscii("My details"), { from: token_owner }); - assert.equal(log.logs[0].args._delegate, account_delegate); - - await I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, web3.utils.fromAscii("FLAGS"), true, { - from: token_owner - }); - - assert.isTrue( - await I_GeneralPermissionManager.checkPermission.call(account_delegate, I_GeneralTransferManager.address, web3.utils.fromAscii("FLAGS")) - ); - - let tx = await I_GeneralTransferManager.changeSigningAddress(account_polymath, { from: account_delegate }); - assert.equal(tx.logs[0].args._signingAddress, account_polymath); - }); - it("Should fail to pull fees as no budget set", async () => { await catchRevert(I_GeneralTransferManager.takeFee(new BN(web3.utils.toWei("1", "ether")), { from: account_polymath })); }); diff --git a/test/helpers/signData.js b/test/helpers/signData.js index cb551102e..3acbc6d4c 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -13,19 +13,28 @@ function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, rest ) .slice(2); packedData = new Buffer(packedData, "hex"); + console.log("PackedData 1: " + packedData); packedData = Buffer.concat([new Buffer(`\x19Ethereum Signed Message:\n${packedData.length.toString()}`), packedData]); packedData = web3.utils.sha3(`0x${packedData.toString("hex")}`, { encoding: "hex" }); + console.log("PackedData 2: " + packedData); return ethUtil.ecsign(new Buffer(packedData.slice(2), "hex"), new Buffer(pk, "hex")); } -function getSignTMData(tmAddress, nonce, expiry, fromAddress, toAddress, amount, pk) { +function getSignSTMData(tmAddress, nonce, expiry, fromAddress, toAddress, amount, pk) { let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'uint256', v: new BN(nonce)}, {t: 'uint256', v: new BN(expiry)}, {t: 'address', v: fromAddress}, {t: 'address', v: toAddress}, {t: 'uint256', v: new BN(amount)}); let signature = (web3.eth.accounts.sign(hash, pk)).signature; let data = web3.eth.abi.encodeParameters(['address', 'uint256', 'uint256', 'bytes'], [tmAddress, new BN(nonce).toString(), new BN(expiry).toString(), signature]); return data; } +function getSignGTMData(tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce, pk) { + let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'address', v: investorAddress}, {t: 'uint256', v: new BN(fromTime)}, {t: 'uint256', v: new BN(toTime)}, {t: 'uint256', v: new BN(expiryTime)}, {t: 'bool', v: restricted}, {t: 'uint256', v: new BN(validFrom)}, {t: 'uint256', v: new BN(validTo)}, {t: 'uint256', v: new BN(nonce)}); + let signature = (web3.eth.accounts.sign(hash, pk)); + return signature.signature; +} + module.exports = { signData, - getSignTMData + getSignSTMData, + getSignGTMData }; diff --git a/test/zb_signed_transfer_manager.js b/test/zb_signed_transfer_manager.js index e13b99f46..a35baba07 100644 --- a/test/zb_signed_transfer_manager.js +++ b/test/zb_signed_transfer_manager.js @@ -1,7 +1,7 @@ import latestTime from "./helpers/latestTime"; import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; -import { getSignTMData } from "./helpers/signData"; +import { getSignSTMData } from "./helpers/signData"; import { pk } from "./helpers/testprivateKey"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; @@ -117,7 +117,7 @@ contract("SignedTransferManager", accounts => { FeatureRegistry: ${I_FeatureRegistry.address} ManualApprovalTransferManagerFactory: ${I_SignedTransferManagerFactory.address} - + ----------------------------------------------------------------------------- `); @@ -133,7 +133,7 @@ contract("SignedTransferManager", accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); - + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token @@ -223,10 +223,10 @@ contract("SignedTransferManager", accounts => { await web3.eth.sendTransaction({ from: token_owner, to: signer.address, value: oneeth }); await I_SignedTransferManager.updateSigners([signer.address], [true], {from: token_owner}); - + let nonce = new BN(10); let expiry = new BN(currentTime.add(new BN(duration.days(100)))); - let data = await getSignTMData( + let data = await getSignSTMData( I_SignedTransferManager.address, nonce, expiry, @@ -247,7 +247,7 @@ contract("SignedTransferManager", accounts => { let oneeth = new BN(web3.utils.toWei("1", "ether")); let nonce = new BN(10); let expiry = new BN(currentTime.add(new BN(duration.days(100)))); - let data = await getSignTMData( + let data = await getSignSTMData( I_SignedTransferManager.address, nonce, expiry, @@ -270,7 +270,7 @@ contract("SignedTransferManager", accounts => { assert.equal(balance11.sub(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor1)).toString()); assert.equal(balance21.add(oneeth).toString(), (await I_SecurityToken.balanceOf(account_investor2)).toString()); - + }); it("should not allow transfer if the signer is not on the signer list", async () => { @@ -278,7 +278,7 @@ contract("SignedTransferManager", accounts => { let oneeth = new BN(web3.utils.toWei("1", "ether")); let nonce = new BN(10); let expiry = new BN(currentTime.add(new BN(duration.days(100)))); - let data = await getSignTMData( + let data = await getSignSTMData( I_SignedTransferManager.address, nonce, expiry, @@ -292,4 +292,3 @@ contract("SignedTransferManager", accounts => { }); }); }); -