diff --git a/package-lock.json b/package-lock.json index bc00856..9991825 100644 --- a/package-lock.json +++ b/package-lock.json @@ -661,6 +661,23 @@ "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.6.2.tgz", "integrity": "sha512-kUVUvrqttndeprLoXjI5arWHeiP3uh4XODAKbG+ZaWHCVQeelxCbnXBeWxZ2BPHdXgH0xR9dU1b916JhDhbgAA==" }, + "@studydefi/money-legos": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@studydefi/money-legos/-/money-legos-2.3.5.tgz", + "integrity": "sha512-Whfsw+Ka5PCX8u7za0DOnb3j7DqPQ0QW2SjtjrC4drP+MRpq6ANdxTLgAqYU2e5BZ3/DrDZ6MGTajMCPKXoxZw==", + "dev": true, + "requires": { + "@openzeppelin/contracts": "^2.5.0" + }, + "dependencies": { + "@openzeppelin/contracts": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-2.5.1.tgz", + "integrity": "sha512-qIy6tLx8rtybEsIOAlrM4J/85s2q2nPkDqj/Rx46VakBZ0LwtFhXIVub96LXHczQX0vaqmAueDqNPXtbSXSaYQ==", + "dev": true + } + } + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", diff --git a/package.json b/package.json index 946081a..4f1376c 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "devDependencies": { "@openzeppelin/test-helpers": "^0.5.6", + "@studydefi/money-legos": "^2.3.5", "ganache-cli": "^6.10.0-beta.2", "sol-merger": "^2.0.1", "solidity-coverage": "0.5.11", diff --git a/test/CurveProtocol.js b/test/CurveProtocol.js index 53c8bf0..29325fd 100644 --- a/test/CurveProtocol.js +++ b/test/CurveProtocol.js @@ -25,10 +25,14 @@ const swapToken = '0xC25a3A3b969415c80451098fa907EC722572917F' const tokenContract = new web3.eth.Contract(erc20, swapToken) contract('Curve Protocol', async accounts => { + let account, contract; + + beforeEach(async function() { + account = accounts[0] + contract = await CurveProtocol.deployed() + }); it('should send ether to the user address', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() const ethBalanceBefore = await balance.current(userAddress); // Send 0.1 eth to userAddress to have gas to send an ERC20 tx. await web3.eth.sendTransaction({ @@ -41,8 +45,6 @@ contract('Curve Protocol', async accounts => { }); it('should transfer DAI to CurveProtocol', async () => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() // Get 100 DAI for first 5 accounts // daiAddress is passed to ganache-cli with flag `--unlock` // so we can use the `transfer` method @@ -58,14 +60,11 @@ contract('Curve Protocol', async accounts => { }); it('should approve DAI to CurveProtocol', async() => { - let account = accounts[0] - let contract = await CurveProtocol.deployed() - await daiContract.methods - .approve(contract.address, ether('100').toString()) - .send({ from: account, gasLimit: 800000 }); - const daiAllowance = await daiContract.methods.allowance(account, contract.address).call() - expect(+daiAllowance).to.be.at.least(+ether('100')) + .approve(contract.address, ether('100').toString()) + .send({ from: account, gasLimit: 800000 }); + const daiAllowance = await daiContract.methods.allowance(account, contract.address).call() + expect(+daiAllowance).to.be.at.least(+ether('100')) }); /* Deprecated as CurveProtocol is not ICurve and exchange has been implemented into sell method @@ -84,7 +83,7 @@ contract('Curve Protocol', async accounts => { }); */ - /* Deprecated as CurveProtocol is not ICurve and calc_token_amount has been implemented into withdraw method + /* Deprecated as CurveProtocol is not ICurve and calc_token_amount has been implemented into withdraw method it('should add liquidity', async () => { let account = accounts[0] let contract = await CurveProtocol.deployed() @@ -106,9 +105,9 @@ contract('Curve Protocol', async accounts => { let burnAmount = receipt.logs[0].args.burnAmount.toString() let tokenBalanceAfter = await tokenContract.methods.balanceOf(contract.address).call() - //weird Ganache errors sometimes "cannot decode event" +//weird Ganache errors sometimes "cannot decode event" console.log(+tokenBalance, +tokenBalanceAfter, +burnAmount) - //expect(BN(tokenBalance)).to.be.a.bignumber.equal(BN(tokenBalanceAfter).add(burnAmount)) +//expect(BN(tokenBalance)).to.be.a.bignumber.equal(BN(tokenBalanceAfter).add(burnAmount)) }) @@ -121,9 +120,9 @@ contract('Curve Protocol', async accounts => { let withdrawnAmount = receipt.logs[0].args.withdrawnAmount.toString() let daiBalanceAfter = await daiContract.methods.balanceOf(contract.address).call() - //weird Ganache errors sometimes "cannot decode event" +//weird Ganache errors sometimes "cannot decode event" console.log(+daiBalance, +daiBalanceAfter, +withdrawnAmount) - //expect(BN(daiBalance)).to.be.a.bignumber.equal(BN(daiBalanceAfter).sub(withdrawnAmount)); +//expect(BN(daiBalance)).to.be.a.bignumber.equal(BN(daiBalanceAfter).sub(withdrawnAmount)); }) */ }); diff --git a/test/CurveSBTCProtocol.js b/test/CurveSBTCProtocol.js new file mode 100644 index 0000000..63a8771 --- /dev/null +++ b/test/CurveSBTCProtocol.js @@ -0,0 +1,77 @@ +const { + BN, // Big Number support + expectEvent, // Assertions for emitted events + expectRevert, // Assertions for transactions that should fail + balance, + ether +} = require('@openzeppelin/test-helpers'); + +const CurveSBTCProtocol = artifacts.require('CurveSBTCProtocol'); +const erc20 = require("@studydefi/money-legos/erc20"); +const uniswap = require("@studydefi/money-legos/uniswap"); +const sbtcABI = require("./abi/sbtc.json"); + +contract('CurveSBTCProtocol', async accounts => { + const [sender, receiver] = accounts; + let contract; + + beforeEach(async function () { + contract = await CurveSBTCProtocol.deployed() + + let wbtcContract = new web3.eth.Contract(erc20.wbtc.abi, erc20.wbtc.address); + + let uniswapFactory = new web3.eth.Contract( + uniswap.factory.abi, + uniswap.factory.address + ); + + const wbtcExchangeAddress = await uniswapFactory.methods.getExchange( + erc20.wbtc.address, + ).call(); + + const wbtcExchange = new web3.eth.Contract( + uniswap.exchange.abi, + wbtcExchangeAddress + ); + + const wbtcBefore = await wbtcContract.methods.balanceOf(sender).call(); + + await wbtcExchange.methods.ethToTokenSwapInput( + 1, // min amount of token retrieved + 2525644800, // random timestamp in the future (year 2050) + ).send( + { + gas: 4000000, + value: ether("5"), + from: sender + } + ); + + let wbtcAfter = await wbtcContract.methods.balanceOf(sender).call(); + + expect(wbtcAfter - wbtcBefore).to.be.at.least(10000000); + }); + + it('can sell WBTC for SBTC', async function () { + const sbtcContract = new web3.eth.Contract(sbtcABI, "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6"); + + const sbtcBefore = await sbtcContract.methods.balanceOf(sender).call(); + + const tx = await contract.sell( + "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6", + erc20.wbtc.address, + 10000000, + ( 0.09 / 0.1 * 1e18 ).toString(), + 0, + 0, + { + gas: 4000000, + from: sender + } + ); + console.log(tx); + + const sbtcAfter = await sbtcContract.methods.balanceOf(sender).call(); + expect(sbtcAfter - sbtcBefore).to.be.at.least(ether("0.09")); + }); +}); diff --git a/test/abi/sbtc.json b/test/abi/sbtc.json new file mode 100644 index 0000000..c227105 --- /dev/null +++ b/test/abi/sbtc.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"}],"name":"setTarget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"callData","type":"bytes"},{"name":"numTopics","type":"uint256"},{"name":"topic1","type":"bytes32"},{"name":"topic2","type":"bytes32"},{"name":"topic3","type":"bytes32"},{"name":"topic4","type":"bytes32"}],"name":"_emit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"useDELEGATECALL","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"value","type":"bool"}],"name":"setUseDELEGATECALL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"target","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newTarget","type":"address"}],"name":"TargetUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"}]