From fdb3c05ca5dd5b969bba7ae951de0b50f9f0c75e Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Thu, 2 Dec 2021 12:13:41 +0200 Subject: [PATCH 1/8] contract updates --- src/pools/Router.ts | 199 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/src/pools/Router.ts b/src/pools/Router.ts index e1606b32e..bef064c28 100644 --- a/src/pools/Router.ts +++ b/src/pools/Router.ts @@ -278,6 +278,54 @@ export class Router { return trxReceipt } + /** + * Estimate gas cost for removeSSContract method + * @param {String} address caller address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async estGasRemoveSSContract( + address: string, + tokenAddress: string + ): Promise { + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .removeSSContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + + /** + * Removes a new contract from ssContract list + * @param {String} address caller address + * @param {String} tokenAddress contract address to removed + * @return {Promise} + */ + public async removeSSContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const estGas = await this.estGasRemoveSSContract(address, tokenAddress) + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.removeSSContract(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + /** * Estimate gas cost for addFixedRateContract method * @param {String} address @@ -327,6 +375,157 @@ export class Router { return trxReceipt } + /** + * Estimate gas cost for addFixedRateContract method + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async estGasRemoveFixedRateContract( + address: string, + tokenAddress: string + ): Promise { + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .removeFixedRateContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + + /** + * Removes a contract from fixedRate list + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async removeFixedRateContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const estGas = await this.estGasRemoveFixedRateContract(address, tokenAddress) + + // Invoke removeFixedRateContract function of the contract + const trxReceipt = await this.router.methods + .removeFixedRateContract(tokenAddress) + .send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Estimate gas cost for addDispenserContract method + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async estGasAddDispenserContract( + address: string, + tokenAddress: string + ): Promise { + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .addDispenserContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + + /** + * Add a new contract to dispenser list, after is added, can be used when deploying a new pool + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async addDispenserContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const estGas = await this.estGasAddDispenserContract(address, tokenAddress) + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.addDispenserContract(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Estimate gas cost for addDispenserContract method + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async estGasRemoveDispenserContract( + address: string, + tokenAddress: string + ): Promise { + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .removeDispenserContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + + /** + * Add a new contract to dispenser list, after is added, can be used when deploying a new pool + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async removeDispenserContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const estGas = await this.estGasRemoveDispenserContract(address, tokenAddress) + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods + .removeDispenserContract(tokenAddress) + .send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + /** Get OPF Fee per token * @return {Promise} OPF fee for a specific baseToken */ From 112a552b90e448c84bf41acbd6db633eb161862d Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Thu, 2 Dec 2021 16:51:26 +0200 Subject: [PATCH 2/8] use serviceIndex instead of serviceID --- package-lock.json | 198 ++++++++++++----------------------- src/datatokens/Datatoken.ts | 16 +-- src/factories/NFTFactory.ts | 2 +- test/unit/Datatoken.test.ts | 4 +- test/unit/NFTFactory.test.ts | 6 +- 5 files changed, 80 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b78419e9..b54a9a245 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1853,38 +1853,6 @@ "node": ">=6.9.0" } }, - "node_modules/@balancer-labs/v2-asset-manager-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-asset-manager-utils/-/v2-asset-manager-utils-0.1.0.tgz", - "integrity": "sha512-TbBXKp+laIbjMqzJUqibNtJHG6Fsq51BfSxqwr6BWQc0Ysif2drRx9nbF3OCY5DNvM1J+c5LZ6mYno/uqSbgGw==", - "dependencies": { - "@balancer-labs/v2-solidity-utils": "1.0.0", - "@balancer-labs/v2-vault": "1.0.0" - } - }, - "node_modules/@balancer-labs/v2-pool-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-pool-utils/-/v2-pool-utils-1.0.0.tgz", - "integrity": "sha512-7CSdHuWqSiEsK+/v+xgnn/Bc+9qNOvCF1T0UDidlxCfa1L2djpYz8P/J+ouITcGaz/330yGTEsrkd94ZOoLE2w==", - "dependencies": { - "@balancer-labs/v2-asset-manager-utils": "0.1.0", - "@balancer-labs/v2-solidity-utils": "1.0.0", - "@balancer-labs/v2-vault": "1.0.0" - } - }, - "node_modules/@balancer-labs/v2-solidity-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-solidity-utils/-/v2-solidity-utils-1.0.0.tgz", - "integrity": "sha512-nTmxPRhErmNTIsSU18wX0sbm6CbVEs3FYpbQDw1QUzPaqg+ono+lYkqExrlf63OBJGE60QPbjTybQaLW1MNoqQ==" - }, - "node_modules/@balancer-labs/v2-vault": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-vault/-/v2-vault-1.0.0.tgz", - "integrity": "sha512-md5ri4sGamvg2K3914HMailkhcyo6PhYJmd6k8AMJvTnKG3gr2jNNBuRygtoKGRqT6hrty46/EXQG/Nn/Fk9+g==", - "dependencies": { - "@balancer-labs/v2-solidity-utils": "1.0.0" - } - }, "node_modules/@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -1951,9 +1919,9 @@ } }, "node_modules/@ensdomains/ensjs/node_modules/ethers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.1.tgz", - "integrity": "sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.2.tgz", + "integrity": "sha512-EF5W+6Wwcu6BqVwpgmyR5U2+L4c1FQzlM/02dkZOugN3KF0cG9bzHZP+TDJglmPm2/IzCEJDT7KBxzayk7SAHw==", "funding": [ { "type": "individual", @@ -1980,10 +1948,10 @@ "@ethersproject/json-wallets": "5.5.0", "@ethersproject/keccak256": "5.5.0", "@ethersproject/logger": "5.5.0", - "@ethersproject/networks": "5.5.0", + "@ethersproject/networks": "5.5.1", "@ethersproject/pbkdf2": "5.5.0", "@ethersproject/properties": "5.5.0", - "@ethersproject/providers": "5.5.0", + "@ethersproject/providers": "5.5.1", "@ethersproject/random": "5.5.0", "@ethersproject/rlp": "5.5.0", "@ethersproject/sha2": "5.5.0", @@ -1993,7 +1961,7 @@ "@ethersproject/transactions": "5.5.0", "@ethersproject/units": "5.5.0", "@ethersproject/wallet": "5.5.0", - "@ethersproject/web": "5.5.0", + "@ethersproject/web": "5.5.1", "@ethersproject/wordlists": "5.5.0" } }, @@ -2588,9 +2556,9 @@ ] }, "node_modules/@ethersproject/networks": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.0.tgz", - "integrity": "sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.1.tgz", + "integrity": "sha512-tYRDM4zZtSUcKnD4UMuAlj7SeXH/k5WC4SP2u1Pn57++JdXHkRu2zwNkgNogZoxHzhm9Q6qqurDBVptHOsW49Q==", "funding": [ { "type": "individual", @@ -2643,9 +2611,9 @@ } }, "node_modules/@ethersproject/providers": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.0.tgz", - "integrity": "sha512-xqMbDnS/FPy+J/9mBLKddzyLLAQFjrVff5g00efqxPzcAwXiR+SiCGVy6eJ5iAIirBOATjx7QLhDNPGV+AEQsw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.1.tgz", + "integrity": "sha512-2zdD5sltACDWhjUE12Kucg2PcgM6V2q9JMyVvObtVGnzJu+QSmibbP+BHQyLWZUBfLApx2942+7DC5D+n4wBQQ==", "funding": [ { "type": "individual", @@ -2901,9 +2869,9 @@ } }, "node_modules/@ethersproject/web": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.0.tgz", - "integrity": "sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", + "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", "funding": [ { "type": "individual", @@ -3051,15 +3019,14 @@ "node_modules/@oceanprotocol/contracts": { "name": "hardhat-project", "version": "v1.0.0-alpha.1", - "resolved": "git+ssh://git@github.com/oceanprotocol/contracts.git#f72642e81064777242625f7a1b31af92a925f292", + "resolved": "git+ssh://git@github.com/oceanprotocol/contracts.git#9d734766e9a44ce668321bc79e2d863f91fba116", "dependencies": { - "@balancer-labs/v2-pool-utils": "^1.0.0", - "@openzeppelin/contracts": "^4.2.0", - "@openzeppelin/test-helpers": "^0.5.10", + "@openzeppelin/contracts": "^4.3.3", + "@openzeppelin/test-helpers": "^0.5.15", "dotenv": "^10.0.0", - "eth-permit": "^0.1.10", - "ethereumjs-util": "^7.0.10", - "hardhat-contract-sizer": "^2.0.3", + "eth-permit": "^0.2.1", + "ethereumjs-util": "^7.1.3", + "hardhat-contract-sizer": "^2.1.1", "solidity-bytes-utils": "^0.8.0" } }, @@ -3217,9 +3184,9 @@ } }, "node_modules/@openzeppelin/contracts": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.3.3.tgz", - "integrity": "sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.4.0.tgz", + "integrity": "sha512-dlKiZmDvJnGRLHojrDoFZJmsQVeltVeoiRN7RK+cf2FmkhASDEblE0RiaYdxPNsUZa6mRG8393b9bfyp+V5IAw==" }, "node_modules/@openzeppelin/test-helpers": { "version": "0.5.15", @@ -7465,9 +7432,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", + "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", "hasInstallScript": true, "peer": true, "funding": { @@ -10028,9 +9995,9 @@ } }, "node_modules/eth-permit": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/eth-permit/-/eth-permit-0.1.10.tgz", - "integrity": "sha512-cMAjWvGEaCQoWSlKWBqkBMQvhCtXzVlkTCnYBxGRsCxznbBZSiYuOsHpTAb4EerRwQJkRgwd3vPvcZh3OA7Siw==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/eth-permit/-/eth-permit-0.2.1.tgz", + "integrity": "sha512-+a91Il8JDsKXnib6a5CWEwBc9OOR93IYM1GRGlcnEa+NwMHkWLg4P8lyEHnUmoMVfjutoQTz8wnEWr5Y+k3QOQ==", "dependencies": { "utf8": "^3.0.0" } @@ -10788,9 +10755,9 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" }, "node_modules/fast-check": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-2.19.0.tgz", - "integrity": "sha512-qY4Rc0Nljl2aJx2qgbK3o6wPBjL9QvhKdD/VqJgaKd5ewn8l4ViqgDpUHJq/JkHTBnFKomYYvkFkOYGDVTT8bw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-2.20.0.tgz", + "integrity": "sha512-tFNjLyPnOUg6iimVxOtoWMJOIyybCo7B8gUGm1yv43jDCQ0hlPUn0fmna/XO/n1yPxn/dxQw3+IygPSbMDiiog==", "dependencies": { "pure-rand": "^5.0.0" }, @@ -26937,38 +26904,6 @@ "to-fast-properties": "^2.0.0" } }, - "@balancer-labs/v2-asset-manager-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-asset-manager-utils/-/v2-asset-manager-utils-0.1.0.tgz", - "integrity": "sha512-TbBXKp+laIbjMqzJUqibNtJHG6Fsq51BfSxqwr6BWQc0Ysif2drRx9nbF3OCY5DNvM1J+c5LZ6mYno/uqSbgGw==", - "requires": { - "@balancer-labs/v2-solidity-utils": "1.0.0", - "@balancer-labs/v2-vault": "1.0.0" - } - }, - "@balancer-labs/v2-pool-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-pool-utils/-/v2-pool-utils-1.0.0.tgz", - "integrity": "sha512-7CSdHuWqSiEsK+/v+xgnn/Bc+9qNOvCF1T0UDidlxCfa1L2djpYz8P/J+ouITcGaz/330yGTEsrkd94ZOoLE2w==", - "requires": { - "@balancer-labs/v2-asset-manager-utils": "0.1.0", - "@balancer-labs/v2-solidity-utils": "1.0.0", - "@balancer-labs/v2-vault": "1.0.0" - } - }, - "@balancer-labs/v2-solidity-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-solidity-utils/-/v2-solidity-utils-1.0.0.tgz", - "integrity": "sha512-nTmxPRhErmNTIsSU18wX0sbm6CbVEs3FYpbQDw1QUzPaqg+ono+lYkqExrlf63OBJGE60QPbjTybQaLW1MNoqQ==" - }, - "@balancer-labs/v2-vault": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@balancer-labs/v2-vault/-/v2-vault-1.0.0.tgz", - "integrity": "sha512-md5ri4sGamvg2K3914HMailkhcyo6PhYJmd6k8AMJvTnKG3gr2jNNBuRygtoKGRqT6hrty46/EXQG/Nn/Fk9+g==", - "requires": { - "@balancer-labs/v2-solidity-utils": "1.0.0" - } - }, "@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -27028,9 +26963,9 @@ }, "dependencies": { "ethers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.1.tgz", - "integrity": "sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.2.tgz", + "integrity": "sha512-EF5W+6Wwcu6BqVwpgmyR5U2+L4c1FQzlM/02dkZOugN3KF0cG9bzHZP+TDJglmPm2/IzCEJDT7KBxzayk7SAHw==", "requires": { "@ethersproject/abi": "5.5.0", "@ethersproject/abstract-provider": "5.5.1", @@ -27047,10 +26982,10 @@ "@ethersproject/json-wallets": "5.5.0", "@ethersproject/keccak256": "5.5.0", "@ethersproject/logger": "5.5.0", - "@ethersproject/networks": "5.5.0", + "@ethersproject/networks": "5.5.1", "@ethersproject/pbkdf2": "5.5.0", "@ethersproject/properties": "5.5.0", - "@ethersproject/providers": "5.5.0", + "@ethersproject/providers": "5.5.1", "@ethersproject/random": "5.5.0", "@ethersproject/rlp": "5.5.0", "@ethersproject/sha2": "5.5.0", @@ -27060,7 +26995,7 @@ "@ethersproject/transactions": "5.5.0", "@ethersproject/units": "5.5.0", "@ethersproject/wallet": "5.5.0", - "@ethersproject/web": "5.5.0", + "@ethersproject/web": "5.5.1", "@ethersproject/wordlists": "5.5.0" } } @@ -27500,9 +27435,9 @@ "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==" }, "@ethersproject/networks": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.0.tgz", - "integrity": "sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.1.tgz", + "integrity": "sha512-tYRDM4zZtSUcKnD4UMuAlj7SeXH/k5WC4SP2u1Pn57++JdXHkRu2zwNkgNogZoxHzhm9Q6qqurDBVptHOsW49Q==", "requires": { "@ethersproject/logger": "^5.5.0" } @@ -27525,9 +27460,9 @@ } }, "@ethersproject/providers": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.0.tgz", - "integrity": "sha512-xqMbDnS/FPy+J/9mBLKddzyLLAQFjrVff5g00efqxPzcAwXiR+SiCGVy6eJ5iAIirBOATjx7QLhDNPGV+AEQsw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.1.tgz", + "integrity": "sha512-2zdD5sltACDWhjUE12Kucg2PcgM6V2q9JMyVvObtVGnzJu+QSmibbP+BHQyLWZUBfLApx2942+7DC5D+n4wBQQ==", "requires": { "@ethersproject/abstract-provider": "^5.5.0", "@ethersproject/abstract-signer": "^5.5.0", @@ -27671,9 +27606,9 @@ } }, "@ethersproject/web": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.0.tgz", - "integrity": "sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", + "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", "requires": { "@ethersproject/base64": "^5.5.0", "@ethersproject/bytes": "^5.5.0", @@ -27777,16 +27712,15 @@ } }, "@oceanprotocol/contracts": { - "version": "git+ssh://git@github.com/oceanprotocol/contracts.git#f72642e81064777242625f7a1b31af92a925f292", + "version": "git+ssh://git@github.com/oceanprotocol/contracts.git#9d734766e9a44ce668321bc79e2d863f91fba116", "from": "@oceanprotocol/contracts@github:oceanprotocol/contracts#v4main_postaudit", "requires": { - "@balancer-labs/v2-pool-utils": "^1.0.0", - "@openzeppelin/contracts": "^4.2.0", - "@openzeppelin/test-helpers": "^0.5.10", + "@openzeppelin/contracts": "^4.3.3", + "@openzeppelin/test-helpers": "^0.5.15", "dotenv": "^10.0.0", - "eth-permit": "^0.1.10", - "ethereumjs-util": "^7.0.10", - "hardhat-contract-sizer": "^2.0.3", + "eth-permit": "^0.2.1", + "ethereumjs-util": "^7.1.3", + "hardhat-contract-sizer": "^2.1.1", "solidity-bytes-utils": "^0.8.0" } }, @@ -27935,9 +27869,9 @@ } }, "@openzeppelin/contracts": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.3.3.tgz", - "integrity": "sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.4.0.tgz", + "integrity": "sha512-dlKiZmDvJnGRLHojrDoFZJmsQVeltVeoiRN7RK+cf2FmkhASDEblE0RiaYdxPNsUZa6mRG8393b9bfyp+V5IAw==" }, "@openzeppelin/test-helpers": { "version": "0.5.15", @@ -31420,9 +31354,9 @@ } }, "core-js-pure": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", + "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", "peer": true }, "core-util-is": { @@ -33401,9 +33335,9 @@ } }, "eth-permit": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/eth-permit/-/eth-permit-0.1.10.tgz", - "integrity": "sha512-cMAjWvGEaCQoWSlKWBqkBMQvhCtXzVlkTCnYBxGRsCxznbBZSiYuOsHpTAb4EerRwQJkRgwd3vPvcZh3OA7Siw==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/eth-permit/-/eth-permit-0.2.1.tgz", + "integrity": "sha512-+a91Il8JDsKXnib6a5CWEwBc9OOR93IYM1GRGlcnEa+NwMHkWLg4P8lyEHnUmoMVfjutoQTz8wnEWr5Y+k3QOQ==", "requires": { "utf8": "^3.0.0" } @@ -34111,9 +34045,9 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" }, "fast-check": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-2.19.0.tgz", - "integrity": "sha512-qY4Rc0Nljl2aJx2qgbK3o6wPBjL9QvhKdD/VqJgaKd5ewn8l4ViqgDpUHJq/JkHTBnFKomYYvkFkOYGDVTT8bw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-2.20.0.tgz", + "integrity": "sha512-tFNjLyPnOUg6iimVxOtoWMJOIyybCo7B8gUGm1yv43jDCQ0hlPUn0fmna/XO/n1yPxn/dxQw3+IygPSbMDiiog==", "requires": { "pure-rand": "^5.0.0" } diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index 302285672..6f9f8fb79 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -19,7 +19,7 @@ interface Roles { export interface OrderParams { consumer: string amount: string - serviceId: number + serviceIndex: number consumeFeeAddress: string consumeFeeToken: string consumeFeeAmount: string @@ -818,7 +818,7 @@ export class Datatoken { * @param {String} address User address which calls * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered - * @param {Number} serviceId Service index in the metadata + * @param {Number} serviceIndex Service index in the metadata * @param {String} mpFeeAddress Consume marketplace fee address * @param {String} feeToken address of the token marketplace wants to add fee on top * @param {String} feeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI @@ -830,7 +830,7 @@ export class Datatoken { address: string, consumer: string, amount: string, - serviceId: number, + serviceIndex: number, mpFeeAddress: string, feeToken: string, feeAmount: string, @@ -847,7 +847,7 @@ export class Datatoken { .startOrder( consumer, this.web3.utils.toWei(amount), - serviceId, + serviceIndex, mpFeeAddress, feeToken, this.web3.utils.toWei(feeAmount) @@ -864,7 +864,7 @@ export class Datatoken { * @param {String} address User address which calls * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered - * @param {Number} serviceId Service index in the metadata + * @param {Number} serviceIndex Service index in the metadata * @param {String} mpFeeAddress Consume marketplace fee address * @param {String} feeToken address of the token marketplace wants to add fee on top * @param {String} feeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI @@ -875,7 +875,7 @@ export class Datatoken { address: string, consumer: string, amount: string, - serviceId: number, + serviceIndex: number, mpFeeAddress: string, feeToken: string, feeAmount: string @@ -888,7 +888,7 @@ export class Datatoken { address, consumer, amount, - serviceId, + serviceIndex, mpFeeAddress, feeToken, feeAmount, @@ -899,7 +899,7 @@ export class Datatoken { .startOrder( consumer, this.web3.utils.toWei(amount), - serviceId, + serviceIndex, mpFeeAddress, feeToken, this.web3.utils.toWei(feeAmount) diff --git a/src/factories/NFTFactory.ts b/src/factories/NFTFactory.ts index 7ab20af53..89d57beae 100644 --- a/src/factories/NFTFactory.ts +++ b/src/factories/NFTFactory.ts @@ -22,7 +22,7 @@ export interface TokenOrder { tokenAddress: string consumer: string amount: string | number - serviceId: number + serviceIndex: number consumeFeeAddress: string consumeFeeToken: string // address of the token marketplace wants to add fee on top consumeFeeAmount: number diff --git a/test/unit/Datatoken.test.ts b/test/unit/Datatoken.test.ts index ac52e4e50..b7709aa8c 100644 --- a/test/unit/Datatoken.test.ts +++ b/test/unit/Datatoken.test.ts @@ -282,7 +282,7 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceId: 1, + serviceIndex: 1, consumeFeeAddress: user1, consumeFeeToken: '0x0000000000000000000000000000000000000000', consumeFeeAmount: '0' @@ -301,7 +301,7 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceId: 1, + serviceIndex: 1, consumeFeeAddress: user1, consumeFeeToken: '0x0000000000000000000000000000000000000000', consumeFeeAmount: '0' diff --git a/test/unit/NFTFactory.test.ts b/test/unit/NFTFactory.test.ts index 21430e7c5..89ce6ce71 100644 --- a/test/unit/NFTFactory.test.ts +++ b/test/unit/NFTFactory.test.ts @@ -311,7 +311,7 @@ describe('NFT Factory test', () => { it('#startMultipleTokenOrder- should succed to start multiple orders', async () => { const consumer = user2 // could be different user const dtAmount = web3.utils.toWei('1') - const serviceId = 1 // dummy index + const serviceIndex = 1 // dummy index const consumeFeeAddress = user3 // marketplace fee Collector const consumeFeeAmount = 0 // fee to be collected on top, requires approval const consumeFeeToken = contracts.daiAddress // token address for the feeAmount, in this case DAI @@ -348,7 +348,7 @@ describe('NFT Factory test', () => { tokenAddress: dtAddress, consumer: consumer, amount: dtAmount, - serviceId: serviceId, + serviceIndex: serviceIndex, consumeFeeAddress: consumeFeeAddress, consumeFeeToken: consumeFeeToken, consumeFeeAmount: consumeFeeAmount @@ -357,7 +357,7 @@ describe('NFT Factory test', () => { tokenAddress: dtAddress2, consumer: consumer, amount: dtAmount, - serviceId: serviceId, + serviceIndex: serviceIndex, consumeFeeAddress: consumeFeeAddress, consumeFeeToken: consumeFeeToken, consumeFeeAmount: consumeFeeAmount From 9d2c0d86ed1ee3bfeccf015e2d3bb726d230ecb9 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Mon, 6 Dec 2021 14:40:33 +0200 Subject: [PATCH 3/8] add supprot for allow swapFee change on sideStaking contract --- src/datatokens/Datatoken.ts | 11 +++++ src/pools/ssContracts/SideStaking.ts | 70 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index 6f9f8fb79..7182a96bd 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -1202,6 +1202,17 @@ export class Datatoken { return nftAddress } + /** Returns true if address has deployERC20 role + * @param {String} dtAddress Datatoken adress + * @param {String} dtAddress Datatoken adress + * @return {Promise} + */ + public async isERC20Deployer(dtAddress: string, adddress: string): Promise { + const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) + const isERC20Deployer = await dtContract.methods.isERC20Deployer(adddress).call() + return isERC20Deployer + } + /** * Get Address Balance for datatoken * @param {String} dtAddress Datatoken adress diff --git a/src/pools/ssContracts/SideStaking.ts b/src/pools/ssContracts/SideStaking.ts index c53b57400..7bca7abfc 100644 --- a/src/pools/ssContracts/SideStaking.ts +++ b/src/pools/ssContracts/SideStaking.ts @@ -337,6 +337,76 @@ export class SideStaking { return result } + /** + * Estimate gas cost for getVesting + * @param {String} account + * @param {String} ssAddress side staking contract address + * @param {String} datatokenAddress datatokenAddress + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estSetPoolSwapFee( + account: string, + ssAddress: string, + datatokenAddress: string, + poolAddress: string, + swapFee: number, + contractInstance?: Contract + ): Promise { + const sideStaking = + contractInstance || new this.web3.eth.Contract(this.ssABI as AbiItem[], ssAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await sideStaking.methods + .setPoolSwapFee(datatokenAddress, poolAddress, swapFee) + .estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + + /** Send vested tokens available to the publisher address, can be called by anyone + * + * @param {String} account + * @param {String} ssAddress side staking contract address + * @param {String} datatokenAddress datatokenAddress + * @return {TransactionReceipt} + */ + async setPoolSwapFee( + account: string, + ssAddress: string, + datatokenAddress: string, + poolAddress: string, + swapFee: number + ): Promise { + const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress) + let result = null + + const estGas = await this.estSetPoolSwapFee( + account, + ssAddress, + datatokenAddress, + poolAddress, + swapFee, + sideStaking + ) + try { + result = await sideStaking.methods + .setPoolSwapFee(datatokenAddress, poolAddress, swapFee) + .send({ + from: account, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + } catch (e) { + LoggerInstance.error('ERROR: Failed to join swap pool amount out') + } + return result + } + /** * Get Router address set in side staking contract * @param {String} ssAddress side staking contract address From 96ec95cfa23f984329a2836a76be94e2a8a06ef9 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Mon, 6 Dec 2021 19:04:17 +0200 Subject: [PATCH 4/8] updated contract fees strategy wip unit tests --- src/datatokens/Datatoken.ts | 33 +--- src/factories/NFTFactory.ts | 3 - src/interfaces/FixedRateInterface.ts | 2 + src/interfaces/PoolInterface.ts | 20 +++ src/pools/balancer/Pool.ts | 220 +++++++++++++++------------ 5 files changed, 148 insertions(+), 130 deletions(-) diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index 7182a96bd..b9df04742 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -20,9 +20,6 @@ export interface OrderParams { consumer: string amount: string serviceIndex: number - consumeFeeAddress: string - consumeFeeToken: string - consumeFeeAmount: string } export interface DispenserParams { @@ -831,9 +828,6 @@ export class Datatoken { consumer: string, amount: string, serviceIndex: number, - mpFeeAddress: string, - feeToken: string, - feeAmount: string, contractInstance?: Contract ): Promise { const dtContract = @@ -844,14 +838,7 @@ export class Datatoken { let estGas try { estGas = await dtContract.methods - .startOrder( - consumer, - this.web3.utils.toWei(amount), - serviceIndex, - mpFeeAddress, - feeToken, - this.web3.utils.toWei(feeAmount) - ) + .startOrder(consumer, this.web3.utils.toWei(amount), serviceIndex) .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) } catch (e) { estGas = gasLimitDefault @@ -875,13 +862,9 @@ export class Datatoken { address: string, consumer: string, amount: string, - serviceIndex: number, - mpFeeAddress: string, - feeToken: string, - feeAmount: string + serviceIndex: number ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) - if (!mpFeeAddress) mpFeeAddress = '0x0000000000000000000000000000000000000000' try { const estGas = await this.estGasStartOrder( dtAddress, @@ -889,21 +872,11 @@ export class Datatoken { consumer, amount, serviceIndex, - mpFeeAddress, - feeToken, - feeAmount, dtContract ) const trxReceipt = await dtContract.methods - .startOrder( - consumer, - this.web3.utils.toWei(amount), - serviceIndex, - mpFeeAddress, - feeToken, - this.web3.utils.toWei(feeAmount) - ) + .startOrder(consumer, this.web3.utils.toWei(amount), serviceIndex) .send({ from: address, gas: estGas + 1, diff --git a/src/factories/NFTFactory.ts b/src/factories/NFTFactory.ts index 89d57beae..c0642424e 100644 --- a/src/factories/NFTFactory.ts +++ b/src/factories/NFTFactory.ts @@ -23,9 +23,6 @@ export interface TokenOrder { consumer: string amount: string | number serviceIndex: number - consumeFeeAddress: string - consumeFeeToken: string // address of the token marketplace wants to add fee on top - consumeFeeAmount: number } export interface NFTCreateData { diff --git a/src/interfaces/FixedRateInterface.ts b/src/interfaces/FixedRateInterface.ts index 7e3c5364f..bc60d0670 100644 --- a/src/interfaces/FixedRateInterface.ts +++ b/src/interfaces/FixedRateInterface.ts @@ -15,4 +15,6 @@ export interface FreOrderParams { exchangeContract: string exchangeId: string maxBaseTokenAmount: string + swapMarketFee: number + marketFeeAddress: string } diff --git a/src/interfaces/PoolInterface.ts b/src/interfaces/PoolInterface.ts index 2fda2dfc7..29c32ad92 100644 --- a/src/interfaces/PoolInterface.ts +++ b/src/interfaces/PoolInterface.ts @@ -18,3 +18,23 @@ export interface CurrentFees { tokens: string[] amounts: string[] } + +export interface TokenInOutMarket { + tokenIn: string + tokenOut: string + marketFeeAddress: string +} + +export interface AmountsInMaxFee { + tokenAmountIn: string + minAmountOut: string + maxPrice: string + swapMarketFee: string +} + +export interface AmountsOutMaxFee { + tokenAmountOut: string + maxAmountIn: string + maxPrice: string + swapMarketFee: string +} diff --git a/src/pools/balancer/Pool.ts b/src/pools/balancer/Pool.ts index b21bfd04f..ce20bb0c0 100644 --- a/src/pools/balancer/Pool.ts +++ b/src/pools/balancer/Pool.ts @@ -8,7 +8,13 @@ import PoolTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/bal import defaultPool from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json' import defaultERC20ABI from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json' import Decimal from 'decimal.js' -import { CurrentFees } from '../../interfaces' +import { + CurrentFees, + TokenInOutMarket, + AmountsInOutMaxFee, + AmountsInMaxFee, + AmountsOutMaxFee +} from '../../interfaces' const BN = require('bn.js') const MaxUint256 = @@ -639,7 +645,7 @@ export class Pool { } /** - * collectOPF - collect market fees - can be called by the marketFeeCollector + * collectOPF - collect market fees - can be called by the publishMarketCollector * @param {String} address * @param {String} poolAddress * @param {String} to address that will receive fees @@ -733,50 +739,6 @@ export class Pool { return result } - /** - * Estimate gas cost for swapExactAmountIn - * @param {String} address - * @param {String} poolAddress - * @param {String} tokenIn - * @param {String} tokenAmountIn will be converted to wei - * @param {String} tokenOut - * @param {String} minAmountOut will be converted to wei - * @param {String} maxPrice will be converted to wei - * @param {Contract} contractInstance optional contract instance - * @return {Promise} - */ - public async estSwapExactAmountIn( - address: string, - poolAddress: string, - tokenIn: string, - tokenAmountIn: string, - tokenOut: string, - minAmountOut: string, - maxPrice: string, - contractInstance?: Contract - ): Promise { - const poolContract = - contractInstance || - new this.web3.eth.Contract(this.poolABI as AbiItem[], poolAddress) - - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await poolContract.methods - .swapExactAmountIn( - tokenIn, - tokenAmountIn, - tokenOut, - minAmountOut, - maxPrice || MaxUint256 - ) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } - return estGas - } - async amountToUnits(token: string, amount: string): Promise { try { const tokenContract = new this.web3.eth.Contract( @@ -812,6 +774,53 @@ export class Pool { } } + /** + * Estimate gas cost for swapExactAmountIn + * @param {String} address + * @param {String} poolAddress + * @param {String} tokenIn + * @param {String} tokenAmountIn will be converted to wei + * @param {String} tokenOut + * @param {String} minAmountOut will be converted to wei + * @param {String} maxPrice will be converted to wei + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estSwapExactAmountIn( + address: string, + poolAddress: string, + tokenInOutMarket: TokenInOutMarket, + amountsInOutMaxFee: AmountsInMaxFee, + contractInstance?: Contract + ): Promise { + const poolContract = + contractInstance || + new this.web3.eth.Contract(this.poolABI as AbiItem[], poolAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await poolContract.methods + .swapExactAmountIn( + [ + tokenInOutMarket.tokenIn, + tokenInOutMarket.tokenOut, + tokenInOutMarket.marketFeeAddress + ], + [ + amountsInOutMaxFee.tokenAmountIn, + amountsInOutMaxFee.minAmountOut, + this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + amountsInOutMaxFee.swapMarketFee + ] + ) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * swapExactAmountIn - Trades an exact tokenAmountIn of tokenIn taken from the caller by the pool, in exchange for at least minAmountOut of tokenOut given to the caller from the pool, with a maximum marginal price of maxPrice. Returns (tokenAmountOut, spotPriceAfter), where tokenAmountOut is the amount of token that came out of the pool, and spotPriceAfter is the new marginal spot price, ie, the result of getSpotPrice after the call. (These values are what are limited by the arguments; you are guaranteed tokenAmountOut >= minAmountOut and spotPriceAfter <= maxPrice). * @param {String} address @@ -826,39 +835,44 @@ export class Pool { async swapExactAmountIn( address: string, poolAddress: string, - tokenIn: string, - tokenAmountIn: string, - tokenOut: string, - minAmountOut: string, - maxPrice?: string + tokenInOutMarket: TokenInOutMarket, + amountsInOutMaxFee: AmountsInOutMaxFee ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) - const amountInFormatted = await this.amountToUnits(tokenIn, tokenAmountIn) + amountsInOutMaxFee.tokenAmountIn = await this.amountToUnits( + tokenInOutMarket.tokenIn, + amountsInOutMaxFee.tokenAmountIn + ) - const minAmountOutFormatted = await this.amountToUnits(tokenOut, minAmountOut) + amountsInOutMaxFee.minAmountOut = await this.amountToUnits( + tokenInOutMarket.tokenOut, + amountsInOutMaxFee.minAmountOut + ) let result = null const estGas = await this.estSwapExactAmountIn( address, poolAddress, - tokenIn, - amountInFormatted, - tokenOut, - minAmountOutFormatted.toString(), - maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 + tokenInOutMarket, + amountsInOutMaxFee ) - // console.log(minAmountOutFormatted, 'minamoutnoutformatted') try { result = await pool.methods .swapExactAmountIn( - tokenIn, - amountInFormatted, - tokenOut, - minAmountOutFormatted, - maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 + [ + tokenInOutMarket.tokenIn, + tokenInOutMarket.tokenOut, + tokenInOutMarket.marketFeeAddress + ], + [ + amountsInOutMaxFee.tokenAmountIn, + amountsInOutMaxFee.minAmountOut, + this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + amountsInOutMaxFee.swapMarketFee + ] ) .send({ from: address, @@ -887,11 +901,8 @@ export class Pool { public async estSwapExactAmountOut( address: string, poolAddress: string, - tokenIn: string, - maxAmountIn: string, - tokenOut: string, - amountOut: string, - maxPrice?: string, + tokenInOutMarket: TokenInOutMarket, + amountsInOutMaxFee: AmountsOutMaxFee, contractInstance?: Contract ): Promise { const poolContract = @@ -903,11 +914,17 @@ export class Pool { try { estGas = await poolContract.methods .swapExactAmountOut( - tokenIn, - maxAmountIn, - tokenOut, - amountOut, - maxPrice || MaxUint256 + [ + tokenInOutMarket.tokenIn, + tokenInOutMarket.tokenOut, + tokenInOutMarket.marketFeeAddress + ], + [ + amountsInOutMaxFee.maxAmountIn, + amountsInOutMaxFee.tokenAmountOut, + this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + amountsInOutMaxFee.swapMarketFee + ] ) .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) } catch (e) { @@ -930,35 +947,41 @@ export class Pool { async swapExactAmountOut( account: string, poolAddress: string, - tokenIn: string, - maxAmountIn: string, - tokenOut: string, - amountOut: string, - maxPrice?: string + tokenInOutMarket: TokenInOutMarket, + amountsInOutMaxFee: AmountsOutMaxFee ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let result = null - const maxAmountInFormatted = await this.amountToUnits(tokenIn, maxAmountIn) - const amountOutFormatted = await this.amountToUnits(tokenOut, amountOut) + amountsInOutMaxFee.maxAmountIn = await this.amountToUnits( + tokenInOutMarket.tokenIn, + amountsInOutMaxFee.maxAmountIn + ) + amountsInOutMaxFee.tokenAmountOut = await this.amountToUnits( + tokenInOutMarket.tokenOut, + amountsInOutMaxFee.tokenAmountOut + ) const estGas = await this.estSwapExactAmountOut( account, poolAddress, - tokenIn, - maxAmountInFormatted, - tokenOut, - amountOutFormatted, - maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 + tokenInOutMarket, + amountsInOutMaxFee ) try { result = await pool.methods .swapExactAmountOut( - tokenIn, - maxAmountInFormatted, - tokenOut, - amountOutFormatted, - maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 + [ + tokenInOutMarket.tokenIn, + tokenInOutMarket.tokenOut, + tokenInOutMarket.marketFeeAddress + ], + [ + amountsInOutMaxFee.maxAmountIn, + amountsInOutMaxFee.tokenAmountOut, + this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + amountsInOutMaxFee.swapMarketFee + ] ) .send({ from: account, @@ -1452,7 +1475,8 @@ export class Pool { async getSpotPrice( poolAddress: string, tokenIn: string, - tokenOut: string + tokenOut: string, + swapMarketFe: number ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let decimalsTokenIn = 18 @@ -1479,7 +1503,7 @@ export class Pool { let price = null try { - price = await pool.methods.getSpotPrice(tokenIn, tokenOut).call() + price = await pool.methods.getSpotPrice(tokenIn, tokenOut, swapMarketFe).call() price = new BigNumber(price.toString()) } catch (e) { this.logger.error('ERROR: Failed to get spot price of swapping tokenIn to tokenOut') @@ -1506,7 +1530,8 @@ export class Pool { poolAddress: string, tokenIn: string, tokenOut: string, - tokenAmountOut: string + tokenAmountOut: string, + swapMarketFee: string ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) @@ -1516,7 +1541,7 @@ export class Pool { try { const result = await pool.methods - .getAmountInExactOut(tokenIn, tokenOut, amountOutFormatted) + .getAmountInExactOut(tokenIn, tokenOut, amountOutFormatted, swapMarketFee) .call() amount = await this.unitsToAmount(tokenIn, result) } catch (e) { @@ -1529,7 +1554,8 @@ export class Pool { poolAddress: string, tokenIn: string, tokenOut: string, - tokenAmountIn: string + tokenAmountIn: string, + swapMarketFee: string ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) @@ -1539,7 +1565,7 @@ export class Pool { try { const result = await pool.methods - .getAmountOutExactIn(tokenIn, tokenOut, amountInFormatted) + .getAmountOutExactIn(tokenIn, tokenOut, amountInFormatted, swapMarketFee) .call() amount = await this.unitsToAmount(tokenOut, result) From ee6e935c0c88f20c7b7d29c6de9b7afe71534dbb Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Mon, 6 Dec 2021 23:25:48 +0200 Subject: [PATCH 5/8] updated unit tests --- src/datatokens/Datatoken.ts | 6 - src/interfaces/FixedRateInterface.ts | 2 +- src/pools/balancer/Pool.ts | 66 +++---- test/unit/Datatoken.test.ts | 26 +-- test/unit/NFTFactory.test.ts | 14 +- test/unit/pools/balancer/Pool.test.ts | 163 +++++++++++++----- .../pools/ssContracts/SideStaking.test.ts | 62 +++++-- 7 files changed, 218 insertions(+), 121 deletions(-) diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index b9df04742..812a96693 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -816,9 +816,6 @@ export class Datatoken { * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered * @param {Number} serviceIndex Service index in the metadata - * @param {String} mpFeeAddress Consume marketplace fee address - * @param {String} feeToken address of the token marketplace wants to add fee on top - * @param {String} feeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI * @param {Contract} contractInstance optional contract instance * @return {Promise} */ @@ -852,9 +849,6 @@ export class Datatoken { * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered * @param {Number} serviceIndex Service index in the metadata - * @param {String} mpFeeAddress Consume marketplace fee address - * @param {String} feeToken address of the token marketplace wants to add fee on top - * @param {String} feeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI * @return {Promise} string */ public async startOrder( diff --git a/src/interfaces/FixedRateInterface.ts b/src/interfaces/FixedRateInterface.ts index bc60d0670..a9f556662 100644 --- a/src/interfaces/FixedRateInterface.ts +++ b/src/interfaces/FixedRateInterface.ts @@ -15,6 +15,6 @@ export interface FreOrderParams { exchangeContract: string exchangeId: string maxBaseTokenAmount: string - swapMarketFee: number + swapMarketFee: string marketFeeAddress: string } diff --git a/src/pools/balancer/Pool.ts b/src/pools/balancer/Pool.ts index ce20bb0c0..f431b3eb6 100644 --- a/src/pools/balancer/Pool.ts +++ b/src/pools/balancer/Pool.ts @@ -11,7 +11,6 @@ import Decimal from 'decimal.js' import { CurrentFees, TokenInOutMarket, - AmountsInOutMaxFee, AmountsInMaxFee, AmountsOutMaxFee } from '../../interfaces' @@ -778,11 +777,8 @@ export class Pool { * Estimate gas cost for swapExactAmountIn * @param {String} address * @param {String} poolAddress - * @param {String} tokenIn - * @param {String} tokenAmountIn will be converted to wei - * @param {String} tokenOut - * @param {String} minAmountOut will be converted to wei - * @param {String} maxPrice will be converted to wei + * @param {TokenInOutMarket} tokenInOutMarket + * @param {AmountsInMaxFee} amountsInOutMaxFee * @param {Contract} contractInstance optional contract instance * @return {Promise} */ @@ -811,7 +807,7 @@ export class Pool { amountsInOutMaxFee.tokenAmountIn, amountsInOutMaxFee.minAmountOut, this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), - amountsInOutMaxFee.swapMarketFee + this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) @@ -822,21 +818,22 @@ export class Pool { } /** - * swapExactAmountIn - Trades an exact tokenAmountIn of tokenIn taken from the caller by the pool, in exchange for at least minAmountOut of tokenOut given to the caller from the pool, with a maximum marginal price of maxPrice. Returns (tokenAmountOut, spotPriceAfter), where tokenAmountOut is the amount of token that came out of the pool, and spotPriceAfter is the new marginal spot price, ie, the result of getSpotPrice after the call. (These values are what are limited by the arguments; you are guaranteed tokenAmountOut >= minAmountOut and spotPriceAfter <= maxPrice). + * swapExactAmountIn - Trades an exact tokenAmountIn of tokenIn taken from the caller by the pool, + * in exchange for at least minAmountOut of tokenOut given to the caller from the pool, with a maximum marginal price of maxPrice. + * Returns (tokenAmountOut, spotPriceAfter), where tokenAmountOut is the amount of token that came out of the pool, + * and spotPriceAfter is the new marginal spot price, ie, the result of getSpotPrice after the call. + * (These values are what are limited by the arguments; you are guaranteed tokenAmountOut >= minAmountOut and spotPriceAfter <= maxPrice). * @param {String} address * @param {String} poolAddress - * @param {String} tokenIn - * @param {String} tokenAmountIn will be converted to wei - * @param {String} tokenOut - * @param {String} minAmountOut will be converted to wei - * @param {String} maxPrice will be converted to wei + * @param {TokenInOutMarket} tokenInOutMarket + * @param {AmountsInMaxFee} amountsInOutMaxFee * @return {TransactionReceipt} */ async swapExactAmountIn( address: string, poolAddress: string, tokenInOutMarket: TokenInOutMarket, - amountsInOutMaxFee: AmountsInOutMaxFee + amountsInOutMaxFee: AmountsInMaxFee ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) @@ -871,7 +868,7 @@ export class Pool { amountsInOutMaxFee.tokenAmountIn, amountsInOutMaxFee.minAmountOut, this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), - amountsInOutMaxFee.swapMarketFee + this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) .send({ @@ -890,11 +887,8 @@ export class Pool { * Estimate gas cost for swapExactAmountOut * @param {String} address * @param {String} poolAddress - * @param {String} tokenIn - * @param {String} tokenAmountIn will be converted to wei - * @param {String} tokenOut - * @param {String} minAmountOut will be converted to wei - * @param {String} maxPrice will be converted to wei + * @param {TokenInOutMarket} tokenInOutMarket + * @param {AmountsOutMaxFee} amountsInOutMaxFee * @param {Contract} contractInstance optional contract instance * @return {Promise} */ @@ -923,7 +917,7 @@ export class Pool { amountsInOutMaxFee.maxAmountIn, amountsInOutMaxFee.tokenAmountOut, this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), - amountsInOutMaxFee.swapMarketFee + this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) @@ -937,11 +931,8 @@ export class Pool { * swapExactAmountOut * @param {String} account * @param {String} poolAddress - * @param {String} tokenIn - * @param {String} maxAmountIn will be converted to wei - * @param {String} tokenOut - * @param {String} amountOut will be converted to wei - * @param {String} maxPrice will be converted to wei + * @param {TokenInOutMarket} tokenInOutMarket + * @param {AmountsOutMaxFee} amountsInOutMaxFee * @return {TransactionReceipt} */ async swapExactAmountOut( @@ -980,7 +971,7 @@ export class Pool { amountsInOutMaxFee.maxAmountIn, amountsInOutMaxFee.tokenAmountOut, this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), - amountsInOutMaxFee.swapMarketFee + this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) .send({ @@ -1470,13 +1461,14 @@ export class Pool { * @param {String} poolAddress * @param {String} tokenIn * @param {String} tokenOut + * @param {String} swapMarketFe * @return {String} */ async getSpotPrice( poolAddress: string, tokenIn: string, tokenOut: string, - swapMarketFe: number + swapMarketFee: string ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let decimalsTokenIn = 18 @@ -1503,7 +1495,9 @@ export class Pool { let price = null try { - price = await pool.methods.getSpotPrice(tokenIn, tokenOut, swapMarketFe).call() + price = await pool.methods + .getSpotPrice(tokenIn, tokenOut, this.web3.utils.toWei(swapMarketFee)) + .call() price = new BigNumber(price.toString()) } catch (e) { this.logger.error('ERROR: Failed to get spot price of swapping tokenIn to tokenOut') @@ -1541,7 +1535,12 @@ export class Pool { try { const result = await pool.methods - .getAmountInExactOut(tokenIn, tokenOut, amountOutFormatted, swapMarketFee) + .getAmountInExactOut( + tokenIn, + tokenOut, + amountOutFormatted, + this.web3.utils.toWei(swapMarketFee) + ) .call() amount = await this.unitsToAmount(tokenIn, result) } catch (e) { @@ -1565,7 +1564,12 @@ export class Pool { try { const result = await pool.methods - .getAmountOutExactIn(tokenIn, tokenOut, amountInFormatted, swapMarketFee) + .getAmountOutExactIn( + tokenIn, + tokenOut, + amountInFormatted, + this.web3.utils.toWei(swapMarketFee) + ) .call() amount = await this.unitsToAmount(tokenOut, result) diff --git a/test/unit/Datatoken.test.ts b/test/unit/Datatoken.test.ts index b7709aa8c..990d35135 100644 --- a/test/unit/Datatoken.test.ts +++ b/test/unit/Datatoken.test.ts @@ -253,16 +253,7 @@ describe('Datatoken', () => { 'User2 does not hold 0 datatokens' ) - const order = await datatoken.startOrder( - datatokenAddress, - user1, - user2, - '1', - 1, - user3, - '0x0000000000000000000000000000000000000000', - '0' - ) + const order = await datatoken.startOrder(datatokenAddress, user1, user2, '1', 1) assert(order !== null) assert( @@ -282,10 +273,7 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceIndex: 1, - consumeFeeAddress: user1, - consumeFeeToken: '0x0000000000000000000000000000000000000000', - consumeFeeAmount: '0' + serviceIndex: 1 } const buyFromDispenseTx = await datatoken.buyFromDispenserAndOrder( @@ -301,15 +289,15 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceIndex: 1, - consumeFeeAddress: user1, - consumeFeeToken: '0x0000000000000000000000000000000000000000', - consumeFeeAmount: '0' + serviceIndex: 1 } + const fre: FreOrderParams = { exchangeContract: fixedRateAddress, exchangeId: exchangeId, - maxBaseTokenAmount: '1' + maxBaseTokenAmount: '1', + swapMarketFee: this.web3.utils.toWei('0.1'), + marketFeeAddress: '0x0000000000000000000000000000000000000000' } const buyTx = await datatoken.buyFromFreAndOrder(datatokenAddress, user1, order, fre) diff --git a/test/unit/NFTFactory.test.ts b/test/unit/NFTFactory.test.ts index 89ce6ce71..3fbfa7269 100644 --- a/test/unit/NFTFactory.test.ts +++ b/test/unit/NFTFactory.test.ts @@ -14,7 +14,7 @@ import MockERC20 from '@oceanprotocol/contracts/artifacts/contracts/utils/mock/M import PoolTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/balancer/BPool.sol/BPool.json' import { LoggerInstance } from '../../src/utils' // import { NFTDataToken } from '../../../src/datatokens/NFTDatatoken' -import { NFTFactory, NFTCreateData } from '../../src/factories/NFTFactory' +import { NFTFactory, NFTCreateData, TokenOrder } from '../../src/factories/NFTFactory' import { FreCreationParams, Erc20CreateParams, @@ -343,24 +343,18 @@ describe('NFT Factory test', () => { expect(await dtContract.methods.balanceOf(user2).call()).to.equal(dtAmount) expect(await dtContract2.methods.balanceOf(user2).call()).to.equal(dtAmount) - const orders = [ + const orders: TokenOrder[] = [ { tokenAddress: dtAddress, consumer: consumer, amount: dtAmount, - serviceIndex: serviceIndex, - consumeFeeAddress: consumeFeeAddress, - consumeFeeToken: consumeFeeToken, - consumeFeeAmount: consumeFeeAmount + serviceIndex: serviceIndex }, { tokenAddress: dtAddress2, consumer: consumer, amount: dtAmount, - serviceIndex: serviceIndex, - consumeFeeAddress: consumeFeeAddress, - consumeFeeToken: consumeFeeToken, - consumeFeeAmount: consumeFeeAmount + serviceIndex: serviceIndex } ] diff --git a/test/unit/pools/balancer/Pool.test.ts b/test/unit/pools/balancer/Pool.test.ts index cf670a674..16200932c 100644 --- a/test/unit/pools/balancer/Pool.test.ts +++ b/test/unit/pools/balancer/Pool.test.ts @@ -20,11 +20,16 @@ import { Pool } from '../../../../src/pools/balancer/Pool' import { PoolCreationParams, Erc20CreateParams, - CurrentFees + CurrentFees, + TokenInOutMarket, + AmountsInMaxFee, + AmountsOutMaxFee } from '../../../../src/interfaces' const { keccak256 } = require('@ethersproject/keccak256') const web3 = new Web3('http://127.0.0.1:8545') const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' +const MaxUint256 = + '115792089237316195423570985008687907853269984665640564039457584007913129639934' describe('Pool unit test', () => { let factoryOwner: string @@ -272,13 +277,22 @@ describe('Pool unit test', () => { ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0') await pool.approve(user2, contracts.daiAddress, poolAddress, '10') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.daiAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsInMaxFee = { + tokenAmountIn: '10', + minAmountOut: '1', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountIn( user2, poolAddress, - contracts.daiAddress, - '10', - erc20Token, - '1' + tokenInOutMarket, + amountsInOutMaxFee ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal( tx.events.LOG_SWAP.returnValues.tokenAmountOut @@ -290,13 +304,22 @@ describe('Pool unit test', () => { expect(await daiContract.methods.balanceOf(user2).call()).to.equal( web3.utils.toWei('990') ) + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.daiAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsOutMaxFee = { + maxAmountIn: '100', + tokenAmountOut: '50', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountOut( user2, poolAddress, - contracts.daiAddress, - '100', - erc20Token, - '50' + tokenInOutMarket, + amountsInOutMaxFee ) assert(tx != null) }) @@ -428,7 +451,8 @@ describe('Pool unit test', () => { poolAddress, erc20Token, contracts.daiAddress, - exactDAIOut + exactDAIOut, + '0.1' ) assert(amountIn != null) @@ -438,7 +462,8 @@ describe('Pool unit test', () => { const spotPrice = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.daiAddress + contracts.daiAddress, + '0.1' ) // amount of DAI In will be slightly bigger than spotPrice @@ -452,7 +477,8 @@ describe('Pool unit test', () => { poolAddress, erc20Token, contracts.daiAddress, - exactDTIn + exactDTIn, + '0.1' ) assert(amountOut != null) @@ -460,7 +486,8 @@ describe('Pool unit test', () => { const spotPrice = await pool.getSpotPrice( poolAddress, contracts.daiAddress, - erc20Token + erc20Token, + '0.1' ) // amount of DAI received will be slightly less than spotPrice assert(amountOut < spotPrice) @@ -468,10 +495,12 @@ describe('Pool unit test', () => { it('#getSpotPrice- should get the spot price', async () => { assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.daiAddress)) != null + (await pool.getSpotPrice(poolAddress, erc20Token, contracts.daiAddress, '0.1')) != + null ) assert( - (await pool.getSpotPrice(poolAddress, contracts.daiAddress, erc20Token)) != null + (await pool.getSpotPrice(poolAddress, contracts.daiAddress, erc20Token, '0.1')) != + null ) }) @@ -494,7 +523,8 @@ describe('Pool unit test', () => { const spotPriceBefore = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.daiAddress + contracts.daiAddress, + '0.1' ) // contracts.accounts[0] is the marketFeeCollector @@ -508,8 +538,12 @@ describe('Pool unit test', () => { // Spot price hasn't changed after fee collection assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.daiAddress)) === - spotPriceBefore + (await pool.getSpotPrice( + poolAddress, + erc20Token, + contracts.daiAddress, + '0.1' + )) === spotPriceBefore ) }) @@ -526,7 +560,8 @@ describe('Pool unit test', () => { const spotPriceBefore = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.daiAddress + contracts.daiAddress, + '0.1' ) // some fee are available in DAI assert((await pool.getCommunityFees(poolAddress, contracts.daiAddress)) > '0') @@ -545,8 +580,12 @@ describe('Pool unit test', () => { ) // Spot price hasn't changed after fee collection assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.daiAddress)) === - spotPriceBefore + (await pool.getSpotPrice( + poolAddress, + erc20Token, + contracts.daiAddress, + '0.1' + )) === spotPriceBefore ) }) @@ -785,13 +824,22 @@ describe('Pool unit test', () => { expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0') await pool.approve(user2, contracts.usdcAddress, poolAddress, '10') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.usdcAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsInMaxFee = { + tokenAmountIn: '10', + minAmountOut: '1', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountIn( user2, poolAddress, - contracts.usdcAddress, - '10', - erc20Token, - '1' + tokenInOutMarket, + amountsInOutMaxFee ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal( tx.events.LOG_SWAP.returnValues.tokenAmountOut @@ -803,13 +851,22 @@ describe('Pool unit test', () => { (await pool.amountToUnits(contracts.usdcAddress, '990')).toString() ) await pool.approve(user2, contracts.usdcAddress, poolAddress, '100') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.usdcAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsOutMaxFee = { + maxAmountIn: '100', + tokenAmountOut: '50', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountOut( user2, poolAddress, - contracts.usdcAddress, - '100', - erc20Token, - '50' + tokenInOutMarket, + amountsInOutMaxFee ) assert(tx != null) // console.log(tx.events) @@ -944,7 +1001,8 @@ describe('Pool unit test', () => { poolAddress, erc20Token, contracts.usdcAddress, - exactUSDCOut + exactUSDCOut, + '0.1' ) assert(amountIn != null) @@ -952,7 +1010,8 @@ describe('Pool unit test', () => { const spotPrice = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.usdcAddress + contracts.usdcAddress, + '0.1' ) // amount of USDC In will be slightly bigger than spotPrice assert(amountIn > spotPrice) @@ -965,7 +1024,8 @@ describe('Pool unit test', () => { poolAddress, erc20Token, contracts.usdcAddress, - exactDTIn + exactDTIn, + '0.1' ) assert(amountOut != null) @@ -973,7 +1033,8 @@ describe('Pool unit test', () => { const spotPrice = await pool.getSpotPrice( poolAddress, contracts.usdcAddress, - erc20Token + erc20Token, + '0.1' ) // amount of USDC received will be slightly less than spotPrice assert(amountOut < spotPrice) @@ -981,10 +1042,20 @@ describe('Pool unit test', () => { it('#getSpotPrice- should get the spot price', async () => { assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.usdcAddress)) != null + (await pool.getSpotPrice( + poolAddress, + erc20Token, + contracts.usdcAddress, + '0.1' + )) != null ) assert( - (await pool.getSpotPrice(poolAddress, contracts.usdcAddress, erc20Token)) != null + (await pool.getSpotPrice( + poolAddress, + contracts.usdcAddress, + erc20Token, + '0.1' + )) != null ) }) @@ -1007,7 +1078,8 @@ describe('Pool unit test', () => { const spotPriceBefore = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.usdcAddress + contracts.usdcAddress, + '0.1' ) // contracts.accounts[0] is the marketFeeCollector assert((await pool.getMarketFeeCollector(poolAddress)) === contracts.accounts[0]) @@ -1020,8 +1092,12 @@ describe('Pool unit test', () => { // Spot price hasn't changed after fee collection assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.usdcAddress)) === - spotPriceBefore + (await pool.getSpotPrice( + poolAddress, + erc20Token, + contracts.usdcAddress, + '0.1' + )) === spotPriceBefore ) }) @@ -1048,7 +1124,8 @@ describe('Pool unit test', () => { const spotPriceBefore = await pool.getSpotPrice( poolAddress, erc20Token, - contracts.usdcAddress + contracts.usdcAddress, + '0.1' ) // some fee are available in USDC assert((await pool.getCommunityFees(poolAddress, contracts.usdcAddress)) > '0') @@ -1067,8 +1144,12 @@ describe('Pool unit test', () => { ) // Spot price hasn't changed after fee collection assert( - (await pool.getSpotPrice(poolAddress, erc20Token, contracts.usdcAddress)) === - spotPriceBefore + (await pool.getSpotPrice( + poolAddress, + erc20Token, + contracts.usdcAddress, + '0.1' + )) === spotPriceBefore ) }) diff --git a/test/unit/pools/ssContracts/SideStaking.test.ts b/test/unit/pools/ssContracts/SideStaking.test.ts index 9385ec03d..2aaa1cb92 100644 --- a/test/unit/pools/ssContracts/SideStaking.test.ts +++ b/test/unit/pools/ssContracts/SideStaking.test.ts @@ -19,10 +19,18 @@ import { LoggerInstance } from '../../../../src/utils' import { NFTFactory, NFTCreateData } from '../../../../src/factories/NFTFactory' import { Pool } from '../../../../src/pools/balancer/Pool' import { SideStaking } from '../../../../src/pools/ssContracts/SideStaking' -import { Erc20CreateParams, PoolCreationParams } from '../../../../src/interfaces' +import { + Erc20CreateParams, + PoolCreationParams, + TokenInOutMarket, + AmountsInMaxFee, + AmountsOutMaxFee +} from '../../../../src/interfaces' const { keccak256 } = require('@ethersproject/keccak256') const web3 = new Web3('http://127.0.0.1:8545') const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' +const MaxUint256 = + '115792089237316195423570985008687907853269984665640564039457584007913129639934' describe('SideStaking unit test', () => { let factoryOwner: string @@ -291,13 +299,23 @@ describe('SideStaking unit test', () => { ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0') await pool.approve(user2, contracts.daiAddress, poolAddress, '10') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.daiAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsInMaxFee = { + tokenAmountIn: '10', + minAmountOut: '1', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } + const tx = await pool.swapExactAmountIn( user2, poolAddress, - contracts.daiAddress, - '10', - erc20Token, - '1' + tokenInOutMarket, + amountsInOutMaxFee ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal( tx.events.LOG_SWAP.returnValues.tokenAmountOut @@ -309,13 +327,22 @@ describe('SideStaking unit test', () => { expect(await daiContract.methods.balanceOf(user2).call()).to.equal( web3.utils.toWei('990') ) + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.daiAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsOutMaxFee = { + maxAmountIn: '100', + tokenAmountOut: '50', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountOut( user2, poolAddress, - contracts.daiAddress, - '100', - erc20Token, - '50' + tokenInOutMarket, + amountsInOutMaxFee ) assert(tx != null) }) @@ -536,13 +563,22 @@ describe('SideStaking unit test', () => { expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0') await pool.approve(user2, contracts.usdcAddress, poolAddress, '10') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.usdcAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsInMaxFee = { + tokenAmountIn: '10', + minAmountOut: '1', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountIn( user2, poolAddress, - contracts.usdcAddress, - '10', - erc20Token, - '1' + tokenInOutMarket, + amountsInOutMaxFee ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal( tx.events.LOG_SWAP.returnValues.tokenAmountOut From 075fbe2d9bd37006698ef803f4cf00eec362766b Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 7 Dec 2021 10:43:44 +0200 Subject: [PATCH 6/8] added provider fees --- package-lock.json | 28 ++++++------- src/datatokens/Datatoken.ts | 42 +++++++++++++++++-- src/factories/NFTFactory.ts | 3 ++ test/unit/Datatoken.test.ts | 23 ++++++++-- test/unit/NFTFactory.test.ts | 12 ++++-- .../pools/ssContracts/SideStaking.test.ts | 17 ++++++-- 6 files changed, 97 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index b54a9a245..f3551dc43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3019,7 +3019,7 @@ "node_modules/@oceanprotocol/contracts": { "name": "hardhat-project", "version": "v1.0.0-alpha.1", - "resolved": "git+ssh://git@github.com/oceanprotocol/contracts.git#9d734766e9a44ce668321bc79e2d863f91fba116", + "resolved": "git+ssh://git@github.com/oceanprotocol/contracts.git#0129022423d8b0b6a7506b96bb45b9bf4f125ca5", "dependencies": { "@openzeppelin/contracts": "^4.3.3", "@openzeppelin/test-helpers": "^0.5.15", @@ -3618,9 +3618,9 @@ } }, "node_modules/@truffle/contract": { - "version": "4.3.42", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.42.tgz", - "integrity": "sha512-CWbKz3L6ldAoh0JX14nNzOyXxWsLiGX5PYpswrwOy0Uk4JYpbVtpSzoQxJbnDTfLUciowfCdG/4QMZ+zo2WVqA==", + "version": "4.3.43", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.43.tgz", + "integrity": "sha512-F06lBURJ3Mow4fov/9O2rI2giVUhlCskpfESjLSuYnE5ZEDwTiNF99P2iv66EhUqNg6JkUFd9RlDZE5bDnZzJA==", "dependencies": { "@ensdomains/ensjs": "^2.0.1", "@truffle/blockchain-utils": "^0.0.31", @@ -7432,9 +7432,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.19.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", - "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.3.tgz", + "integrity": "sha512-N3JruInmCyt7EJj5mAq3csCgGYgiSqu7p7TQp2KOztr180/OAIxyIvL1FCjzgmQk/t3Yniua50Fsak7FShI9lA==", "hasInstallScript": true, "peer": true, "funding": { @@ -27712,7 +27712,7 @@ } }, "@oceanprotocol/contracts": { - "version": "git+ssh://git@github.com/oceanprotocol/contracts.git#9d734766e9a44ce668321bc79e2d863f91fba116", + "version": "git+ssh://git@github.com/oceanprotocol/contracts.git#0129022423d8b0b6a7506b96bb45b9bf4f125ca5", "from": "@oceanprotocol/contracts@github:oceanprotocol/contracts#v4main_postaudit", "requires": { "@openzeppelin/contracts": "^4.3.3", @@ -28241,9 +28241,9 @@ } }, "@truffle/contract": { - "version": "4.3.42", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.42.tgz", - "integrity": "sha512-CWbKz3L6ldAoh0JX14nNzOyXxWsLiGX5PYpswrwOy0Uk4JYpbVtpSzoQxJbnDTfLUciowfCdG/4QMZ+zo2WVqA==", + "version": "4.3.43", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.43.tgz", + "integrity": "sha512-F06lBURJ3Mow4fov/9O2rI2giVUhlCskpfESjLSuYnE5ZEDwTiNF99P2iv66EhUqNg6JkUFd9RlDZE5bDnZzJA==", "requires": { "@ensdomains/ensjs": "^2.0.1", "@truffle/blockchain-utils": "^0.0.31", @@ -31354,9 +31354,9 @@ } }, "core-js-pure": { - "version": "3.19.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", - "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.3.tgz", + "integrity": "sha512-N3JruInmCyt7EJj5mAq3csCgGYgiSqu7p7TQp2KOztr180/OAIxyIvL1FCjzgmQk/t3Yniua50Fsak7FShI9lA==", "peer": true }, "core-util-is": { diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index 812a96693..040336ec1 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -20,6 +20,9 @@ export interface OrderParams { consumer: string amount: string serviceIndex: number + providerFeeAddress: string + providerFeeToken: string + providerFeeAmount: string } export interface DispenserParams { @@ -816,6 +819,9 @@ export class Datatoken { * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered * @param {Number} serviceIndex Service index in the metadata + * @param {String} providerFeeAddress Consume marketplace fee address + * @param {String} providerFeeToken address of the token marketplace wants to add fee on top + * @param {String} providerFeeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI * @param {Contract} contractInstance optional contract instance * @return {Promise} */ @@ -825,6 +831,9 @@ export class Datatoken { consumer: string, amount: string, serviceIndex: number, + providerFeeAddress: string, + providerFeeToken: string, + providerFeeAmount: string, contractInstance?: Contract ): Promise { const dtContract = @@ -835,7 +844,14 @@ export class Datatoken { let estGas try { estGas = await dtContract.methods - .startOrder(consumer, this.web3.utils.toWei(amount), serviceIndex) + .startOrder( + consumer, + this.web3.utils.toWei(amount), + serviceIndex, + providerFeeAddress, + providerFeeToken, + this.web3.utils.toWei(providerFeeAmount) + ) .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) } catch (e) { estGas = gasLimitDefault @@ -849,6 +865,10 @@ export class Datatoken { * @param {String} consumer Consumer Address * @param {String} amount Amount of tokens that is going to be transfered * @param {Number} serviceIndex Service index in the metadata + * @param {String} providerFeeAddress Consume marketplace fee address + * @param {String} providerFeeToken address of the token marketplace wants to add fee on top + * @param {String} providerFeeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI + * @return {Promise} string */ public async startOrder( @@ -856,9 +876,15 @@ export class Datatoken { address: string, consumer: string, amount: string, - serviceIndex: number + serviceIndex: number, + providerFeeAddress: string, + providerFeeToken: string, + providerFeeAmount: string ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) + if (!providerFeeAddress) + providerFeeAddress = '0x0000000000000000000000000000000000000000' + try { const estGas = await this.estGasStartOrder( dtAddress, @@ -866,11 +892,21 @@ export class Datatoken { consumer, amount, serviceIndex, + providerFeeAddress, + providerFeeToken, + providerFeeAmount, dtContract ) const trxReceipt = await dtContract.methods - .startOrder(consumer, this.web3.utils.toWei(amount), serviceIndex) + .startOrder( + consumer, + this.web3.utils.toWei(amount), + serviceIndex, + providerFeeAddress, + providerFeeToken, + this.web3.utils.toWei(providerFeeAmount) + ) .send({ from: address, gas: estGas + 1, diff --git a/src/factories/NFTFactory.ts b/src/factories/NFTFactory.ts index c0642424e..55adf5e1e 100644 --- a/src/factories/NFTFactory.ts +++ b/src/factories/NFTFactory.ts @@ -23,6 +23,9 @@ export interface TokenOrder { consumer: string amount: string | number serviceIndex: number + providerFeeAddress: string + providerFeeToken: string + providerFeeAmount: string } export interface NFTCreateData { diff --git a/test/unit/Datatoken.test.ts b/test/unit/Datatoken.test.ts index 990d35135..da9569627 100644 --- a/test/unit/Datatoken.test.ts +++ b/test/unit/Datatoken.test.ts @@ -253,7 +253,16 @@ describe('Datatoken', () => { 'User2 does not hold 0 datatokens' ) - const order = await datatoken.startOrder(datatokenAddress, user1, user2, '1', 1) + const order = await datatoken.startOrder( + datatokenAddress, + user1, + user2, + '1', + 1, + user3, + '0x0000000000000000000000000000000000000000', + '0' + ) assert(order !== null) assert( @@ -273,7 +282,10 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceIndex: 1 + serviceIndex: 1, + providerFeeAddress: user1, + providerFeeToken: '0x0000000000000000000000000000000000000000', + providerFeeAmount: '0' } const buyFromDispenseTx = await datatoken.buyFromDispenserAndOrder( @@ -289,14 +301,17 @@ describe('Datatoken', () => { const order: OrderParams = { consumer: user1, amount: '1', - serviceIndex: 1 + serviceIndex: 1, + providerFeeAddress: user1, + providerFeeToken: '0x0000000000000000000000000000000000000000', + providerFeeAmount: '0' } const fre: FreOrderParams = { exchangeContract: fixedRateAddress, exchangeId: exchangeId, maxBaseTokenAmount: '1', - swapMarketFee: this.web3.utils.toWei('0.1'), + swapMarketFee: web3.utils.toWei('0.1'), marketFeeAddress: '0x0000000000000000000000000000000000000000' } diff --git a/test/unit/NFTFactory.test.ts b/test/unit/NFTFactory.test.ts index 3fbfa7269..73f42244a 100644 --- a/test/unit/NFTFactory.test.ts +++ b/test/unit/NFTFactory.test.ts @@ -313,7 +313,7 @@ describe('NFT Factory test', () => { const dtAmount = web3.utils.toWei('1') const serviceIndex = 1 // dummy index const consumeFeeAddress = user3 // marketplace fee Collector - const consumeFeeAmount = 0 // fee to be collected on top, requires approval + const consumeFeeAmount = '0' // fee to be collected on top, requires approval const consumeFeeToken = contracts.daiAddress // token address for the feeAmount, in this case DAI // we reuse a DT created in a previous test @@ -348,13 +348,19 @@ describe('NFT Factory test', () => { tokenAddress: dtAddress, consumer: consumer, amount: dtAmount, - serviceIndex: serviceIndex + serviceIndex: serviceIndex, + providerFeeAddress: consumeFeeAddress, + providerFeeToken: consumeFeeToken, + providerFeeAmount: consumeFeeAmount }, { tokenAddress: dtAddress2, consumer: consumer, amount: dtAmount, - serviceIndex: serviceIndex + serviceIndex: serviceIndex, + providerFeeAddress: consumeFeeAddress, + providerFeeToken: consumeFeeToken, + providerFeeAmount: consumeFeeAmount } ] diff --git a/test/unit/pools/ssContracts/SideStaking.test.ts b/test/unit/pools/ssContracts/SideStaking.test.ts index 2aaa1cb92..e7cfeeaea 100644 --- a/test/unit/pools/ssContracts/SideStaking.test.ts +++ b/test/unit/pools/ssContracts/SideStaking.test.ts @@ -590,13 +590,22 @@ describe('SideStaking unit test', () => { (await pool.amountToUnits(contracts.usdcAddress, '990')).toString() ) await pool.approve(user2, contracts.usdcAddress, poolAddress, '100') + const tokenInOutMarket: TokenInOutMarket = { + tokenIn: contracts.usdcAddress, + tokenOut: erc20Token, + marketFeeAddress: '0x0000000000000000000000000000000000000000' + } + const amountsInOutMaxFee: AmountsOutMaxFee = { + maxAmountIn: '100', + tokenAmountOut: '50', + maxPrice: MaxUint256, + swapMarketFee: '0.1' + } const tx = await pool.swapExactAmountOut( user2, poolAddress, - contracts.usdcAddress, - '100', - erc20Token, - '50' + tokenInOutMarket, + amountsInOutMaxFee ) assert(tx != null) // console.log(tx.events) From 7092803c55fdbc5cab8f67a0116e6354ecfaf3bd Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 7 Dec 2021 16:57:21 +0200 Subject: [PATCH 7/8] fixed swap unit tests --- src/interfaces/PoolInterface.ts | 4 +-- src/pools/balancer/Pool.ts | 29 +++++++++++++++---- test/unit/pools/balancer/Pool.test.ts | 15 ++++------ .../pools/ssContracts/SideStaking.test.ts | 14 +++------ 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/interfaces/PoolInterface.ts b/src/interfaces/PoolInterface.ts index 29c32ad92..8f4b9d9b7 100644 --- a/src/interfaces/PoolInterface.ts +++ b/src/interfaces/PoolInterface.ts @@ -28,13 +28,13 @@ export interface TokenInOutMarket { export interface AmountsInMaxFee { tokenAmountIn: string minAmountOut: string - maxPrice: string swapMarketFee: string + maxPrice?: string } export interface AmountsOutMaxFee { tokenAmountOut: string maxAmountIn: string - maxPrice: string swapMarketFee: string + maxPrice?: string } diff --git a/src/pools/balancer/Pool.ts b/src/pools/balancer/Pool.ts index f431b3eb6..3a351f212 100644 --- a/src/pools/balancer/Pool.ts +++ b/src/pools/balancer/Pool.ts @@ -509,7 +509,7 @@ export class Pool { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let weight = null try { - const result = await pool.methods.marketFees(token).call() + const result = await pool.methods.publishMarketFee(token).call() weight = await this.unitsToAmount(token, result) } catch (e) { this.logger.error(`ERROR: Failed to get market fees for a token: ${e.message}`) @@ -793,6 +793,10 @@ export class Pool { contractInstance || new this.web3.eth.Contract(this.poolABI as AbiItem[], poolAddress) + const maxPrice = amountsInOutMaxFee.maxPrice + ? this.web3.utils.toWei(amountsInOutMaxFee.maxPrice) + : MaxUint256 + const gasLimitDefault = this.GASLIMIT_DEFAULT let estGas try { @@ -806,7 +810,7 @@ export class Pool { [ amountsInOutMaxFee.tokenAmountIn, amountsInOutMaxFee.minAmountOut, - this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + maxPrice, this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) @@ -856,6 +860,10 @@ export class Pool { amountsInOutMaxFee ) + const maxPrice = amountsInOutMaxFee.maxPrice + ? this.web3.utils.toWei(amountsInOutMaxFee.maxPrice) + : MaxUint256 + try { result = await pool.methods .swapExactAmountIn( @@ -867,7 +875,7 @@ export class Pool { [ amountsInOutMaxFee.tokenAmountIn, amountsInOutMaxFee.minAmountOut, - this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + maxPrice, this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) @@ -904,6 +912,11 @@ export class Pool { new this.web3.eth.Contract(this.poolABI as AbiItem[], poolAddress) const gasLimitDefault = this.GASLIMIT_DEFAULT + + const maxPrice = amountsInOutMaxFee.maxPrice + ? this.web3.utils.toWei(amountsInOutMaxFee.maxPrice) + : MaxUint256 + let estGas try { estGas = await poolContract.methods @@ -916,7 +929,7 @@ export class Pool { [ amountsInOutMaxFee.maxAmountIn, amountsInOutMaxFee.tokenAmountOut, - this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + maxPrice, this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) @@ -948,10 +961,12 @@ export class Pool { tokenInOutMarket.tokenIn, amountsInOutMaxFee.maxAmountIn ) + amountsInOutMaxFee.tokenAmountOut = await this.amountToUnits( tokenInOutMarket.tokenOut, amountsInOutMaxFee.tokenAmountOut ) + const estGas = await this.estSwapExactAmountOut( account, poolAddress, @@ -959,6 +974,10 @@ export class Pool { amountsInOutMaxFee ) + const maxPrice = amountsInOutMaxFee.maxPrice + ? this.web3.utils.toWei(amountsInOutMaxFee.maxPrice) + : MaxUint256 + try { result = await pool.methods .swapExactAmountOut( @@ -970,7 +989,7 @@ export class Pool { [ amountsInOutMaxFee.maxAmountIn, amountsInOutMaxFee.tokenAmountOut, - this.web3.utils.toWei(amountsInOutMaxFee.maxPrice), + maxPrice, this.web3.utils.toWei(amountsInOutMaxFee.swapMarketFee) ] ) diff --git a/test/unit/pools/balancer/Pool.test.ts b/test/unit/pools/balancer/Pool.test.ts index 16200932c..585a000de 100644 --- a/test/unit/pools/balancer/Pool.test.ts +++ b/test/unit/pools/balancer/Pool.test.ts @@ -28,8 +28,6 @@ import { const { keccak256 } = require('@ethersproject/keccak256') const web3 = new Web3('http://127.0.0.1:8545') const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' -const MaxUint256 = - '115792089237316195423570985008687907853269984665640564039457584007913129639934' describe('Pool unit test', () => { let factoryOwner: string @@ -277,15 +275,15 @@ describe('Pool unit test', () => { ) expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0') await pool.approve(user2, contracts.daiAddress, poolAddress, '10') + const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.daiAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsInMaxFee = { tokenAmountIn: '10', minAmountOut: '1', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountIn( @@ -307,12 +305,11 @@ describe('Pool unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.daiAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsOutMaxFee = { maxAmountIn: '100', tokenAmountOut: '50', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountOut( @@ -827,12 +824,11 @@ describe('Pool unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.usdcAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsInMaxFee = { tokenAmountIn: '10', minAmountOut: '1', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountIn( @@ -854,12 +850,11 @@ describe('Pool unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.usdcAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsOutMaxFee = { maxAmountIn: '100', tokenAmountOut: '50', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountOut( diff --git a/test/unit/pools/ssContracts/SideStaking.test.ts b/test/unit/pools/ssContracts/SideStaking.test.ts index e7cfeeaea..2cf1f3c9e 100644 --- a/test/unit/pools/ssContracts/SideStaking.test.ts +++ b/test/unit/pools/ssContracts/SideStaking.test.ts @@ -29,8 +29,6 @@ import { const { keccak256 } = require('@ethersproject/keccak256') const web3 = new Web3('http://127.0.0.1:8545') const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' -const MaxUint256 = - '115792089237316195423570985008687907853269984665640564039457584007913129639934' describe('SideStaking unit test', () => { let factoryOwner: string @@ -302,12 +300,11 @@ describe('SideStaking unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.daiAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsInMaxFee = { tokenAmountIn: '10', minAmountOut: '1', - maxPrice: MaxUint256, swapMarketFee: '0.1' } @@ -330,12 +327,11 @@ describe('SideStaking unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.daiAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsOutMaxFee = { maxAmountIn: '100', tokenAmountOut: '50', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountOut( @@ -566,12 +562,11 @@ describe('SideStaking unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.usdcAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsInMaxFee = { tokenAmountIn: '10', minAmountOut: '1', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountIn( @@ -593,12 +588,11 @@ describe('SideStaking unit test', () => { const tokenInOutMarket: TokenInOutMarket = { tokenIn: contracts.usdcAddress, tokenOut: erc20Token, - marketFeeAddress: '0x0000000000000000000000000000000000000000' + marketFeeAddress: contracts.accounts[0] } const amountsInOutMaxFee: AmountsOutMaxFee = { maxAmountIn: '100', tokenAmountOut: '50', - maxPrice: MaxUint256, swapMarketFee: '0.1' } const tx = await pool.swapExactAmountOut( From 35c59f0b7bc1241a2b3a11ad61baa04114373bdd Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 7 Dec 2021 20:12:44 +0200 Subject: [PATCH 8/8] fixeded unit tests --- src/interfaces/RouterInterface.ts | 59 +++++++++++++++++++++++++++++++ src/interfaces/index.ts | 1 + src/pools/Router.ts | 22 ++++-------- src/pools/balancer/Pool.ts | 4 +-- test/unit/pools/Router.test.ts | 14 +++++--- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 src/interfaces/RouterInterface.ts diff --git a/src/interfaces/RouterInterface.ts b/src/interfaces/RouterInterface.ts new file mode 100644 index 000000000..6c5a3139e --- /dev/null +++ b/src/interfaces/RouterInterface.ts @@ -0,0 +1,59 @@ +export interface Operation { + /** + * used only for FixedRate or Dispenser, but needs to be filled even for pool + * @type {string} + */ + exchangeIds: string + /** + * pool Address + * @type {string} + */ + source: string + /** + * operation: + * 0 - swapExactAmountIn + * 1 - swapExactAmountOut + * 2 - FixedRateExchange + * 3 - Dispenser + * @type {number} + */ + operation: number + /** + * token in address + * @type {string} + */ + tokenIn: string + /** + * when swapExactAmountIn is EXACT amount IN + * expressed in Wei + * @type {string | number} + */ + amountsIn: string | number + /** + * token out address + * @type {string} + */ + tokenOut: string + /** + * when swapExactAmountIn is MIN amount OUT + * expressed in Wei + * @type {string | number} + */ + amountsOut: string | number + /** + * max price (only for pools) + * expressed in Wei + * @type {string | number} + */ + maxPrice: string | number + /** + * swap fee amount + * @type {string} + */ + swapMarketFee: string + /** + * market fee address to receive fees + * @type {string} + */ + marketFeeAddress: string +} diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 185f4770d..447a29d40 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -2,3 +2,4 @@ export * from './FixedRateInterface' export * from './PoolInterface' export * from './Erc20Interface' export * from './DispenserInterface' +export * from './RouterInterface' diff --git a/src/pools/Router.ts b/src/pools/Router.ts index bef064c28..e71c063a4 100644 --- a/src/pools/Router.ts +++ b/src/pools/Router.ts @@ -3,18 +3,8 @@ import Web3 from 'web3' import { TransactionReceipt } from 'web3-core' import { AbiItem } from 'web3-utils' import defaultRouter from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json' -import { LoggerInstance, getFairGasPrice } from '../utils' - -interface Operations { - exchangeIds: string - source: string - operation: number - tokenIn: string - amountsIn: string | number - tokenOut: string - amountsOut: string | number - maxPrice: string | number -} +import { getFairGasPrice } from '../utils' +import { Operation } from '../interfaces/RouterInterface' /** * Provides an interface for FactoryRouter contract @@ -49,10 +39,10 @@ export class Router { /** * Estimate gas cost for buyDTBatch method * @param {String} address - * @param {Operations} operations Operations objects array + * @param {Operation} operations Operations objects array * @return {Promise} Transaction receipt */ - public async estGasBuyDTBatch(address: string, operations: Operations[]): Promise { + public async estGasBuyDTBatch(address: string, operations: Operation[]): Promise { const gasLimitDefault = this.GASLIMIT_DEFAULT let estGas try { @@ -68,12 +58,12 @@ export class Router { /** * BuyDTBatch * @param {String} address - * @param {Operations} operations Operations objects array + * @param {Operation} operations Operations objects array * @return {Promise} Transaction receipt */ public async buyDTBatch( address: string, - operations: Operations[] + operations: Operation[] ): Promise { const estGas = await this.estGasBuyDTBatch(address, operations) diff --git a/src/pools/balancer/Pool.ts b/src/pools/balancer/Pool.ts index 3a351f212..768ec0d74 100644 --- a/src/pools/balancer/Pool.ts +++ b/src/pools/balancer/Pool.ts @@ -353,7 +353,7 @@ export class Pool { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let result = null try { - result = await pool.methods._marketCollector().call() + result = await pool.methods._publishMarketCollector().call() } catch (e) { this.logger.error(`ERROR: Failed to get marketFeeCollector address: ${e.message}`) } @@ -509,7 +509,7 @@ export class Pool { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) let weight = null try { - const result = await pool.methods.publishMarketFee(token).call() + const result = await pool.methods.publishMarketFees(token).call() weight = await this.unitsToAmount(token, result) } catch (e) { this.logger.error(`ERROR: Failed to get market fees for a token: ${e.message}`) diff --git a/test/unit/pools/Router.test.ts b/test/unit/pools/Router.test.ts index 480f0116f..c373e4018 100644 --- a/test/unit/pools/Router.test.ts +++ b/test/unit/pools/Router.test.ts @@ -16,7 +16,7 @@ import { LoggerInstance } from '../../../src/utils' import { NFTFactory, NFTCreateData } from '../../../src/factories/NFTFactory' import { Router } from '../../../src/pools/Router' import { BigNumber } from 'bignumber.js' -import { Erc20CreateParams, PoolCreationParams } from '../../../src/interfaces' +import { Erc20CreateParams, PoolCreationParams, Operation } from '../../../src/interfaces' const { keccak256 } = require('@ethersproject/keccak256') const web3 = new Web3('http://127.0.0.1:8545') const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' @@ -292,7 +292,7 @@ describe('Router unit test', () => { // 1 - swapExactAmountOut // 2 - FixedRateExchange // 3 - Dispenser - const operations1 = { + const operations1: Operation = { exchangeIds: keccak256('0x00'), // used only for FixedRate or Dispenser, but needs to be filled even for pool source: pool1, // pool Address operation: 0, // swapExactAmountIn @@ -300,10 +300,12 @@ describe('Router unit test', () => { amountsIn: web3.utils.toWei('1'), // when swapExactAmountIn is EXACT amount IN tokenOut: erc20Token, amountsOut: web3.utils.toWei('0.1'), // when swapExactAmountIn is MIN amount OUT - maxPrice: web3.utils.toWei('10') // max price (only for pools) + maxPrice: web3.utils.toWei('10'), // max price (only for pools), + swapMarketFee: web3.utils.toWei('0.1'), + marketFeeAddress: contracts.accounts[0] } - const operations2 = { + const operations2: Operation = { exchangeIds: keccak256('0x00'), // used only for FixedRate or Dispenser, but needs to be filled even for pool source: pool2, // pool Address operation: 0, // swapExactAmountIn @@ -311,7 +313,9 @@ describe('Router unit test', () => { amountsIn: web3.utils.toWei('1'), // when swapExactAmountIn is EXACT amount IN tokenOut: erc20Token2, amountsOut: web3.utils.toWei('0.1'), // when swapExactAmountIn is MIN amount OUT - maxPrice: web3.utils.toWei('10') // max price (only for pools) + maxPrice: web3.utils.toWei('10'), // max price (only for pools) + swapMarketFee: web3.utils.toWei('0.1'), + marketFeeAddress: contracts.accounts[0] } await router.buyDTBatch(user2, [operations1, operations2])