From 7c89800b7f632a5e031081430be49b422ad6557c Mon Sep 17 00:00:00 2001 From: 0age <0age@protonmail.com> Date: Tue, 7 Jan 2020 20:49:09 -0500 Subject: [PATCH 1/5] modify DSWv6 to split out sai vs. cSai migration --- .../DharmaSmartWalletImplementationV6.sol | 167 +++++++++++------- ...maSmartWalletImplementationV6Interface.sol | 7 + package.json | 12 +- scripts/test/deployMockExternal.js | 79 ++++++++- 4 files changed, 194 insertions(+), 71 deletions(-) rename {extra-contracts => contracts}/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol (94%) create mode 100644 interfaces/DharmaSmartWalletImplementationV6Interface.sol diff --git a/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol similarity index 94% rename from extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol rename to contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol index 1563b20..40859fb 100644 --- a/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol +++ b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol @@ -10,9 +10,9 @@ import "../../../interfaces/DharmaSmartWalletImplementationV0Interface.sol"; import "../../../interfaces/DharmaSmartWalletImplementationV1Interface.sol"; import "../../../interfaces/DharmaSmartWalletImplementationV3Interface.sol"; import "../../../interfaces/DharmaSmartWalletImplementationV4Interface.sol"; +import "../../../interfaces/DharmaSmartWalletImplementationV6Interface.sol"; import "../../../interfaces/CTokenInterface.sol"; import "../../../interfaces/USDCV1Interface.sol"; -import "../../../interfaces/ComptrollerInterface.sol"; import "../../../interfaces/DharmaKeyRegistryInterface.sol"; import "../../../interfaces/DharmaEscapeHatchRegistryInterface.sol"; import "../../../interfaces/ERC1271.sol"; @@ -25,10 +25,11 @@ import "../../../interfaces/SaiToDaiMigrator.sol"; * @notice The V6 implementation for the Dharma smart wallet is a non-custodial, * meta-transaction-enabled wallet with helper functions to facilitate lending * funds using CompoundV2, and with a security backstop provided by Dharma Labs - * prior to making withdrawals. It adds support for Multi-collateral Dai, moving - * all Sai (both on the wallet and in Compound) into the new cDai contract. It - * contains methods to support account recovery, escape hatch functionality, and - * generic actions, including in an atomic batch. The smart wallet instances + * prior to making withdrawals. It adds support for Multi-collateral Dai, with + * the addition of functions for migrating Sai to Dai as well as for migrating + * cSai to cDai while leaving any existing Sai in place to simplify accounting. + * It contains methods to support account recovery, escape hatch functionality, + * and generic actions, including in an atomic batch. The smart wallet instances * utilizing this implementation are deployed through the Dharma Smart Wallet * Factory via `CREATE2`, which allows for their address to be known ahead of * time, and any Dai or USDC that has already been sent into that address will @@ -39,7 +40,8 @@ contract DharmaSmartWalletImplementationV6 is DharmaSmartWalletImplementationV0Interface, DharmaSmartWalletImplementationV1Interface, DharmaSmartWalletImplementationV3Interface, - DharmaSmartWalletImplementationV4Interface { + DharmaSmartWalletImplementationV4Interface, + DharmaSmartWalletImplementationV6Interface { using Address for address; using ECDSA for bytes32; // WARNING: DO NOT REMOVE OR REORDER STORAGE WHEN WRITING NEW IMPLEMENTATIONS! @@ -115,10 +117,6 @@ contract DharmaSmartWalletImplementationV6 is 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet ); - ComptrollerInterface internal constant _COMPTROLLER = ComptrollerInterface( - 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B // mainnet - ); - // Compound returns a value of 0 to indicate success, or lack of an error. uint256 internal constant _COMPOUND_SUCCESS = 0; @@ -134,10 +132,10 @@ contract DharmaSmartWalletImplementationV6 is /** * @notice In the initializer, set up the initial user signing key, set - * approval on the cDAI and cUSDC contracts, and deposit any cSAI, Sai, Dai, - * or USDC already at this address to Compound. Note that this initializer is - * only callable while the smart wallet instance is still in the contract - * creation phase. + * approval on the cDAI and cUSDC contracts, and deposit any Dai or USDC + * already at this address to Compound. Note that this initializer is only + * callable while the smart wallet instance is still in the contract creation + * phase. * @param userSigningKey address The initial user signing key for the smart * wallet. */ @@ -148,9 +146,6 @@ contract DharmaSmartWalletImplementationV6 is // Set up the user's signing key and emit a corresponding event. _setUserSigningKey(userSigningKey); - // Attempt to redeem any cSAI for Sai, then to convert any Sai into Dai. - _migrateSaiToDai(); - // Approve the cDAI contract to transfer Dai on behalf of this contract. if (_setFullApproval(AssetType.DAI)) { // Get the current Dai balance on this contract. @@ -171,23 +166,32 @@ contract DharmaSmartWalletImplementationV6 is } /** - * @notice Redeem any cSAI for Sai, convert any Sai to Dai, and deposit all - * Dai and USDC currently residing at this address to Compound. Note that - * "repay" is not currently implemented, but the function is still named - * `repayAndDeposit` so that infrastructure around calling this function will - * not need to be altered for a future smart wallet version. If some step of - * this function fails, the function itself will still succeed, but an - * `ExternalError` with information on what went wrong will be emitted. + * @notice Deposit all Dai and USDC currently residing at this address to + * Compound. Note that "repay" is not currently implemented, but the function + * is still named `repayAndDeposit` so that infrastructure around calling this + * function will not need to be altered for a future smart wallet version. If + * some step of this function fails, the function itself will still succeed, + * but an `ExternalError` with information on what went wrong will be emitted. */ function repayAndDeposit() external { - // Attempt to redeem any cSAI for Sai, then to convert any Sai into Dai. - _migrateSaiToDai(); - // Get the current Dai balance on this contract. uint256 daiBalance = _DAI.balanceOf(address(this)); - // Deposit the full available Dai balance on Compound. - _depositOnCompound(AssetType.DAI, daiBalance); + // If there is any Dai balance, check for adequate approval for cDai. + if (daiBalance > 0) { + uint256 daiAllowance = _DAI.allowance(address(this), address(_CDAI)); + // If allowance is insufficient, try to set it before depositing. + if (daiAllowance < daiBalance) { + if (_setFullApproval(AssetType.DAI)) { + // Deposit the full available Dai balance on Compound. + _depositOnCompound(AssetType.DAI, daiBalance); + } + // Otherwise, just go ahead and try the Dai deposit. + } else { + // Deposit the full available Dai balance on Compound. + _depositOnCompound(AssetType.DAI, daiBalance); + } + } // Get the current USDC balance on this contract. uint256 usdcBalance = _USDC.balanceOf(address(this)); @@ -830,6 +834,54 @@ contract DharmaSmartWalletImplementationV6 is _setUserSigningKey(newUserSigningKey); } + /** + * @notice Convert all available Sai for Dai. If the conversion fails, or if + * the realized exchange rate is less than 1:1, the call will revert. Note + * that cSai is not included as part of this operation. + */ + function migrateSaiToDai() external { + // Swap the current Sai balance on this contract for Dai. + _swapSaiForDai(_SAI.balanceOf(address(this))); + } + + /** + * @notice Redeem all available cSAI for Sai, swap that Sai for Dai, and use + * that Dai to mint cDai. If any step in the process fails, the call will + * revert and prior steps will be rolled back. Also note that existing Sai and + * Dai are not included as part of this operation. + */ + function migrateCSaiToCDai() external { + // Get the current cSai balance for this account. + uint256 redeemAmount = _CSAI.balanceOf(address(this)); + + // Only perform the call to redeem if there is a non-zero balance. + if (redeemAmount > 0) { + // Get the current Sai balance on this contract. + uint256 currentSaiBalance = _SAI.balanceOf(address(this)); + + // Redeem underlying balance from cSai and revert if unsuccessful. + require( + _CSAI.redeem(redeemAmount) == _COMPOUND_SUCCESS, "cSai redeem failed." + ); + + // Calculate difference between pre-redeem and post-redeem Sai balances. + uint256 saiBalance = _SAI.balanceOf(address(this)) - currentSaiBalance; + + // Swap any Sai for Dai and get the newly-swapped Dai balance. + uint256 daiBalance = _swapSaiForDai(saiBalance); + + // If the cDai allowance is insufficient, set it before depositing. + if (_DAI.allowance(address(this), address(_CDAI)) < daiBalance) { + require( + _DAI.approve(address(_CDAI), uint256(-1)), "Dai approval failed." + ); + } + + // Deposit the new Dai balance on Compound. + require(_CDAI.mint(daiBalance) == _COMPOUND_SUCCESS, "cDai mint failed."); + } + } + /** * @notice Retrieve the Dai and USDC balances held by the smart wallet, both * directly and held in Compound. This is not a view function since Compound @@ -1277,42 +1329,39 @@ contract DharmaSmartWalletImplementationV6 is } /** - * @notice Internal function for attempting to redeem all available cSAI for - * Sai followed by an attempt to convert all available Sai for Dai. + * @notice Internal function for converting a Sai balance to Dai. The total + * amount of received Dai must be greater than or equal to the total amount of + * swapped Sai. + * @param saiToSwap uint256 The amount of Sai to swap. + * @return The amount of Dai received as part of the swap. */ - function _migrateSaiToDai() internal { - // Attempt to redeem all cSAI for Sai on Compound. - _withdrawMaxFromCompound(AssetType.SAI); - - // Get the current Sai balance on this contract. - uint256 saiBalance = _SAI.balanceOf(address(this)); - - // If there is any Sai balance, check if migrator has adequate approval. - if (saiBalance > 0) { - uint256 saiAllowance = _SAI.allowance(address(this), address(_MIGRATOR)); + function _swapSaiForDai(uint256 saiToSwap) internal returns (uint256 dai) { + // If the balance is non-zero, check if migrator has adequate approval. + if (saiToSwap > 0) { + uint256 allowance = _SAI.allowance(address(this), address(_MIGRATOR)); + // Ensure that allowance is sufficient before calling the migrator. - bool allowanceSufficient = saiAllowance >= saiBalance; - if (!allowanceSufficient) { + if (saiToSwap > allowance) { // Approve migrator contract to transfer Sai on behalf of this wallet. - (allowanceSufficient, ) = address(_SAI).call(abi.encodeWithSelector( - _SAI.approve.selector, address(_MIGRATOR), uint256(-1) - )); + require( + _SAI.approve(address(_MIGRATOR), uint256(-1)), "Sai approval failed." + ); } - if (allowanceSufficient) { - // Call migrator contract to swap the total Sai balance for Dai. - (bool ok, ) = address(_MIGRATOR).call(abi.encodeWithSelector( - _MIGRATOR.swapSaiToDai.selector, saiBalance - )); + // Get the current Dai balance on this contract. + uint256 currentDaiBalance = _DAI.balanceOf(address(this)); - if (!ok) { - // Emit a corresponding event if the swap failed. - emit ExternalError(address(_MIGRATOR), "SAI-to-DAI swap failed."); - } - } else { - // Emit a corresponding event if the approval failed. - emit ExternalError(address(_SAI), "SAI contract reverted on approval."); - } + // Call migrator contract to swap the supplied Sai balance for Dai. + _MIGRATOR.swapSaiToDai(saiToSwap); + + // Return the difference between the pre-swap and post-swap Dai balances. + dai = _DAI.balanceOf(address(this)) - currentDaiBalance; + + // Ensure that the Sai-to-Dai exchange rate was at least 1-to-1. + require(dai >= saiToSwap, "Exchange rate cannot be below 1:1."); + } else { + // Explicitly specify a change in balance of zero if no swap occurred. + dai = 0; } } diff --git a/interfaces/DharmaSmartWalletImplementationV6Interface.sol b/interfaces/DharmaSmartWalletImplementationV6Interface.sol new file mode 100644 index 0000000..99bbdf5 --- /dev/null +++ b/interfaces/DharmaSmartWalletImplementationV6Interface.sol @@ -0,0 +1,7 @@ +pragma solidity 0.5.11; + + +interface DharmaSmartWalletImplementationV6Interface { + function migrateSaiToDai() external; + function migrateCSaiToCDai() external; +} \ No newline at end of file diff --git a/package.json b/package.json index 28d643a..e9ed673 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dharma-smart-wallet", - "version": "1.2.0", + "version": "1.3.0", "description": "An upgradeable, meta-transaction-enabled smart wallet for earning interest on stablecoins while retaining custody of funds, with an added security backstop provided by Dharma Labs.", "author": "Dharma Labs", "license": "MIT", @@ -17,14 +17,14 @@ "web3": "1.2.1" }, "scripts": { - "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", + "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "build": "./node_modules/.bin/truffle compile", "ci": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -q & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", - "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", "lint": "./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", - "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", + "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", + "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", "stop": "kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "test": "./node_modules/.bin/truffle compile && node scripts/test/ci.js" } diff --git a/scripts/test/deployMockExternal.js b/scripts/test/deployMockExternal.js index e6b3cad..00373d7 100644 --- a/scripts/test/deployMockExternal.js +++ b/scripts/test/deployMockExternal.js @@ -4618,6 +4618,15 @@ module.exports = {test: async function (provider, testingContext) { return 0 } + console.log('funding mcd deployer address...') + await web3.eth.sendTransaction({ + from: originalAddress, + to: '0xb5b06a16621616875A6C2637948bF98eA57c58fa', + value: web3.utils.toWei('1', 'ether'), + gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1, + gasPrice: 1 + }) + console.log('deploying mock price oracle contract...') const priceOracleDeployReceipt = await web3.eth.sendTransaction({ from: address, @@ -4660,9 +4669,9 @@ module.exports = {test: async function (provider, testingContext) { console.log('incrementing dai deployment nonce...') let daiDeployReceipt - for (i = 0; i < 4; i++) { + for (i = 0; i < 1; i++) { daiDeployReceipt = await web3.eth.sendTransaction({ - from: '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9', + from: '0xb5b06a16621616875A6C2637948bF98eA57c58fa', gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, gasPrice: 1, data: '0x3838533838f3' @@ -4671,6 +4680,29 @@ module.exports = {test: async function (provider, testingContext) { console.log('deploying mock Dai...') daiDeployReceipt = await web3.eth.sendTransaction({ + from: '0xb5b06a16621616875A6C2637948bF98eA57c58fa', + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: mockDaiDeploymentData + }) + + assert.strictEqual( + daiDeployReceipt.contractAddress, '0x6B175474E89094C44Da98b954EedeAC495271d0F' + ) + + console.log('incrementing sai deployment nonce...') + let saiDeployReceipt + for (i = 0; i < 4; i++) { + saiDeployReceipt = await web3.eth.sendTransaction({ + from: '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9', + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: '0x3838533838f3' + }) + } + + console.log('deploying mock Sai...') + saiDeployReceipt = await web3.eth.sendTransaction({ from: '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9', gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, gasPrice: 1, @@ -4678,11 +4710,13 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - daiDeployReceipt.contractAddress, constants.DAI_MAINNET_ADDRESS + saiDeployReceipt.contractAddress, constants.DAI_MAINNET_ADDRESS ) + // TODO: transfer mcd Dai + await runTest( - 'Transfer Dai to whale address', + 'Transfer Sai to whale address', DAI, 'transfer', 'send', @@ -4940,7 +4974,7 @@ module.exports = {test: async function (provider, testingContext) { }) } - console.log('deploying Compound cDai...') + console.log('deploying Compound cSai...') const cDaiDeploymentReceipt = await web3.eth.sendTransaction({ from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1, @@ -5073,8 +5107,31 @@ module.exports = {test: async function (provider, testingContext) { } ) + + console.log('incrementing Compound deployment nonce...') + for (i = 72; i < 90; i++) { + compoundDeployReceipt = await web3.eth.sendTransaction({ + from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: '0x3838533838f3' + }) + } + + console.log('deploying Compound cDai...') + const mcDaiDeploymentReceipt = await web3.eth.sendTransaction({ + from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', + gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1, + gasPrice: 1, + data: mockCDaiDeploymentData + }) + + assert.strictEqual( + mcDaiDeploymentReceipt.contractAddress, '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643' + ) + await runTest( - 'List cDai on Comptroller', + 'List cSai on Comptroller', UNITROLLER_COMPTROLLER, '_supportMarket', 'send', @@ -5093,6 +5150,16 @@ module.exports = {test: async function (provider, testingContext) { ] ) + await runTest( + 'List cDai on Comptroller', + UNITROLLER_COMPTROLLER, + '_supportMarket', + 'send', + [ + '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643' + ] + ) + // TODO: list increase cDAI and cUSDC collateral factor on comptroller // TODO: set prices using price oracle From ea1e9c2d33795a9ca66b1f19042b19158ac30b7b Mon Sep 17 00:00:00 2001 From: 0age <0age@protonmail.com> Date: Tue, 7 Jan 2020 21:52:44 -0500 Subject: [PATCH 2/5] update constants with relevant sai + dai elements --- scripts/test/constants.js | 13 +- scripts/test/deploy.js | 8 +- scripts/test/deployMockExternal.js | 55 ++++-- scripts/test/test.js | 276 ++++++++++++++--------------- 4 files changed, 187 insertions(+), 165 deletions(-) diff --git a/scripts/test/constants.js b/scripts/test/constants.js index e384de9..c70b7bc 100644 --- a/scripts/test/constants.js +++ b/scripts/test/constants.js @@ -97,11 +97,14 @@ module.exports = Object.freeze({ '0x767db8f19b71e367540fa372e8e81e4dcb7ca8feede0ae58a0c0bd08b7320dee' ), ETH_WHALE_ADDRESS: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', - DAI_WHALE_ADDRESS: '0x76B03EB651153a81fA1f212f2f59329B4180A46F', + SAI_WHALE_ADDRESS: '0x76B03EB651153a81fA1f212f2f59329B4180A46F', + DAI_WHALE_ADDRESS: '0x8134d518e0CeF5388136c0De43d7E12278701Ac5', USDC_WHALE_ADDRESS: '0x035e742A7E62253C606b9028eeB65178B44F1e7E', - DAI_MAINNET_ADDRESS: '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', + SAI_MAINNET_ADDRESS: '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', + DAI_MAINNET_ADDRESS: '0x6B175474E89094C44Da98b954EedeAC495271d0F', USDC_MAINNET_ADDRESS: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - CDAI_MAINNET_ADDRESS: '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC', + CSAI_MAINNET_ADDRESS: '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC', + CDAI_MAINNET_ADDRESS: '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', CUSDC_MAINNET_ADDRESS: '0x39AA39c021dfbaE8faC545936693aC917d5E7563', CETH_MAINNET_ADDRESS: '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5', MOCK_USDC_BLACKLISTED_ADDRESS: '0x6000000000000000000000000000000000000006', @@ -361,9 +364,9 @@ module.exports = Object.freeze({ '6c634300050b0032000000000000000000000000000000000000000000' ), CONTRACT_NAMES: { - '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': 'DAI', + '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': 'SAI', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': 'USDC', - '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC': 'CDAI', + '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC': 'CSAI', '0x39AA39c021dfbaE8faC545936693aC917d5E7563': 'CUSDC', '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5': 'CETH', '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B': 'Comptroller' diff --git a/scripts/test/deploy.js b/scripts/test/deploy.js index 4edfe03..dc4b26c 100644 --- a/scripts/test/deploy.js +++ b/scripts/test/deploy.js @@ -2690,20 +2690,20 @@ module.exports = {test: async function (provider, testingContext) { 'deploy' ) - let currentDaiCode; + let currentSaiCode; await runTest( 'Checking for required external contracts...', MockCodeCheck, 'code', 'call', - [constants.DAI_MAINNET_ADDRESS], + [constants.SAI_MAINNET_ADDRESS], true, value => { - currentDaiCode = value; + currentSaiCode = value; } ) - if (!currentDaiCode) { + if (!currentSaiCode) { console.log( `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` + `with ${failed} failure${failed === 1 ? '' : 's'}.` diff --git a/scripts/test/deployMockExternal.js b/scripts/test/deployMockExternal.js index 00373d7..62604f2 100644 --- a/scripts/test/deployMockExternal.js +++ b/scripts/test/deployMockExternal.js @@ -12,6 +12,10 @@ module.exports = {test: async function (provider, testingContext) { let gasUsage = {} let counts = {} + const SAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.SAI_MAINNET_ADDRESS + ) + const DAI = new web3.eth.Contract( IERC20Artifact.abi, constants.DAI_MAINNET_ADDRESS ) @@ -24,6 +28,10 @@ module.exports = {test: async function (provider, testingContext) { IERC20Artifact.abi, constants.CDAI_MAINNET_ADDRESS ) + const CSAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.CSAI_MAINNET_ADDRESS + ) + const CUSDC = new web3.eth.Contract( IERC20Artifact.abi, constants.CUSDC_MAINNET_ADDRESS ) @@ -4612,8 +4620,8 @@ module.exports = {test: async function (provider, testingContext) { } // *************************** deploy contracts *************************** // - const currentDaiCode = await web3.eth.getCode(constants.DAI_MAINNET_ADDRESS) - if (currentDaiCode !== '0x') { + const currentSaiCode = await web3.eth.getCode(constants.SAI_MAINNET_ADDRESS) + if (currentSaiCode !== '0x') { console.log('contracts already set up, skipping...') return 0 } @@ -4687,7 +4695,7 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - daiDeployReceipt.contractAddress, '0x6B175474E89094C44Da98b954EedeAC495271d0F' + daiDeployReceipt.contractAddress, constants.DAI_MAINNET_ADDRESS ) console.log('incrementing sai deployment nonce...') @@ -4710,13 +4718,11 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - saiDeployReceipt.contractAddress, constants.DAI_MAINNET_ADDRESS + saiDeployReceipt.contractAddress, constants.SAI_MAINNET_ADDRESS ) - // TODO: transfer mcd Dai - await runTest( - 'Transfer Sai to whale address', + 'Transfer Dai to whale address', DAI, 'transfer', 'send', @@ -4726,12 +4732,26 @@ module.exports = {test: async function (provider, testingContext) { ], true, receipt => {}, + '0xb5b06a16621616875A6C2637948bF98eA57c58fa' + ) + + await runTest( + 'Transfer Sai to whale address', + SAI, + 'transfer', + 'send', + [ + constants.SAI_WHALE_ADDRESS, + '8555083659983933209597798445644913612440610624038028786991485007418559037440' + ], + true, + receipt => {}, '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9' ) await runTest( 'Transfer Dai to primary address', - DAI, + SAI, 'transfer', 'send', [ @@ -4745,7 +4765,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'Dai totalSupply is reachable', - DAI, + SAI, 'totalSupply', 'call', [], @@ -4938,8 +4958,8 @@ module.exports = {test: async function (provider, testingContext) { }) } - console.log('deploying Compound cDAI IRM...') - const cDAIIRMDeploymentReceipt = await web3.eth.sendTransaction({ + console.log('deploying Compound cSAI IRM...') + const cSAIIRMDeploymentReceipt = await web3.eth.sendTransaction({ from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, gasPrice: 1, @@ -4947,7 +4967,7 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - cDAIIRMDeploymentReceipt.contractAddress, + cSAIIRMDeploymentReceipt.contractAddress, '0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a' ) @@ -4983,7 +5003,7 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - cDaiDeploymentReceipt.contractAddress, constants.CDAI_MAINNET_ADDRESS + cDaiDeploymentReceipt.contractAddress, constants.CSAI_MAINNET_ADDRESS ) for (i = 15; i < 17; i++) { @@ -5107,7 +5127,6 @@ module.exports = {test: async function (provider, testingContext) { } ) - console.log('incrementing Compound deployment nonce...') for (i = 72; i < 90; i++) { compoundDeployReceipt = await web3.eth.sendTransaction({ @@ -5119,7 +5138,7 @@ module.exports = {test: async function (provider, testingContext) { } console.log('deploying Compound cDai...') - const mcDaiDeploymentReceipt = await web3.eth.sendTransaction({ + const daiDeploymentReceipt = await web3.eth.sendTransaction({ from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1, gasPrice: 1, @@ -5127,7 +5146,7 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - mcDaiDeploymentReceipt.contractAddress, '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643' + daiDeploymentReceipt.contractAddress, constants.CDAI_MAINNET_ADDRESS ) await runTest( @@ -5136,7 +5155,7 @@ module.exports = {test: async function (provider, testingContext) { '_supportMarket', 'send', [ - CDAI.options.address + CSAI.options.address ] ) @@ -5156,7 +5175,7 @@ module.exports = {test: async function (provider, testingContext) { '_supportMarket', 'send', [ - '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643' + CDAI.options.address ] ) diff --git a/scripts/test/test.js b/scripts/test/test.js index eb2ab39..53704c9 100644 --- a/scripts/test/test.js +++ b/scripts/test/test.js @@ -112,7 +112,7 @@ module.exports = {test: async function (provider, testingContext) { constants.COMPTROLLER_MAINNET_ADDRESS ) - const CDAI_BORROW = new web3.eth.Contract( + const CSAI_BORROW = new web3.eth.Contract( [{ "constant": false, "inputs": [{"name": "borrowAmount", "type": "uint256"}], @@ -122,19 +122,19 @@ module.exports = {test: async function (provider, testingContext) { "stateMutability": "nonpayable", "type": "function" }], - constants.CDAI_MAINNET_ADDRESS + constants.CSAI_MAINNET_ADDRESS ) - const DAI = new web3.eth.Contract( - IERC20Artifact.abi, constants.DAI_MAINNET_ADDRESS + const SAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.SAI_MAINNET_ADDRESS ) const USDC = new web3.eth.Contract( IERC20Artifact.abi, constants.USDC_MAINNET_ADDRESS ) - const CDAI = new web3.eth.Contract( - IERC20Artifact.abi, constants.CDAI_MAINNET_ADDRESS + const CSAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.CSAI_MAINNET_ADDRESS ) const CUSDC = new web3.eth.Contract( @@ -1355,20 +1355,20 @@ module.exports = {test: async function (provider, testingContext) { } ) - let currentDaiCode; + let currentSaiCode; await runTest( 'Checking for required external contracts...', MockCodeCheck, 'code', 'call', - [constants.DAI_MAINNET_ADDRESS], + [constants.SAI_MAINNET_ADDRESS], true, value => { - currentDaiCode = value; + currentSaiCode = value; } ) - if (!currentDaiCode) { + if (!currentSaiCode) { console.log( `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` + `with ${failed} failure${failed === 1 ? '' : 's'}.` @@ -1459,7 +1459,7 @@ module.exports = {test: async function (provider, testingContext) { contractNames[targetWalletAddress] = 'Smart Wallet' const ethWhaleBalance = await web3.eth.getBalance(constants.ETH_WHALE_ADDRESS) - const daiWhaleBalance = await web3.eth.getBalance(constants.DAI_WHALE_ADDRESS) + const saiWhaleBalance = await web3.eth.getBalance(constants.SAI_WHALE_ADDRESS) const usdcWhaleBalance = await web3.eth.getBalance(constants.USDC_WHALE_ADDRESS) if (ethWhaleBalance === '0') { @@ -1473,15 +1473,15 @@ module.exports = {test: async function (provider, testingContext) { console.log(' ✓ Eth Whale can receive eth if needed') } - if (daiWhaleBalance === '0') { + if (saiWhaleBalance === '0') { await web3.eth.sendTransaction({ from: address, - to: constants.DAI_WHALE_ADDRESS, + to: constants.SAI_WHALE_ADDRESS, value: web3.utils.toWei('.1', 'ether'), gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1, gasPrice: 1 }) - console.log(' ✓ Dai Whale can receive eth if needed') + console.log(' ✓ Sai Whale can receive eth if needed') } if (usdcWhaleBalance === '0') { @@ -1505,8 +1505,8 @@ module.exports = {test: async function (provider, testingContext) { console.log(' ✓ Eth Whale can deposit eth into the yet-to-be-deployed smart wallet') await runTest( - 'Dai Whale can deposit dai into the yet-to-be-deployed smart wallet', - DAI, + 'Sai Whale can deposit sai into the yet-to-be-deployed smart wallet', + SAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -1515,7 +1515,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -1527,7 +1527,7 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) await runTest( @@ -1595,22 +1595,22 @@ module.exports = {test: async function (provider, testingContext) { assert.strictEqual(events[0].eventName, 'NewUserSigningKey') assert.strictEqual(events[0].returnValues.userSigningKey, address) - assert.strictEqual(events[1].address, 'DAI') + assert.strictEqual(events[1].address, 'SAI') assert.strictEqual(events[1].eventName, 'Approval') assert.strictEqual(events[1].returnValues.value, constants.FULL_APPROVAL) - assert.strictEqual(events[2].address, 'CDAI') + assert.strictEqual(events[2].address, 'CSAI') assert.strictEqual(events[2].eventName, 'AccrueInterest') - assert.strictEqual(events[3].address, 'DAI') + assert.strictEqual(events[3].address, 'SAI') assert.strictEqual(events[3].eventName, 'Transfer') assert.strictEqual(events[3].returnValues.value, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[4].address, 'CDAI') + assert.strictEqual(events[4].address, 'CSAI') assert.strictEqual(events[4].eventName, 'Mint') assert.strictEqual(events[4].returnValues.mintTokens, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[5].address, 'CDAI') + assert.strictEqual(events[5].address, 'CSAI') assert.strictEqual(events[5].eventName, 'Transfer') assert.strictEqual(events[6].address, 'USDC') @@ -1668,8 +1668,8 @@ module.exports = {test: async function (provider, testingContext) { }) await runTest( - 'Dai Whale can deposit dai into the deployed smart wallet', - DAI, + 'Sai Whale can deposit sai into the deployed smart wallet', + SAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -1678,7 +1678,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -1690,7 +1690,7 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) await runTest( @@ -1742,18 +1742,18 @@ module.exports = {test: async function (provider, testingContext) { }) }) - assert.strictEqual(events[0].address, 'CDAI') + assert.strictEqual(events[0].address, 'CSAI') assert.strictEqual(events[0].eventName, 'AccrueInterest') - assert.strictEqual(events[1].address, 'DAI') + assert.strictEqual(events[1].address, 'SAI') assert.strictEqual(events[1].eventName, 'Transfer') assert.strictEqual(events[1].returnValues.value, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[2].address, 'CDAI') + assert.strictEqual(events[2].address, 'CSAI') assert.strictEqual(events[2].eventName, 'Mint') assert.strictEqual(events[2].returnValues.mintTokens, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[3].address, 'CDAI') + assert.strictEqual(events[3].address, 'CSAI') assert.strictEqual(events[3].eventName, 'Transfer') assert.strictEqual(events[4].address, 'CUSDC') @@ -1872,7 +1872,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'UserSmartWallet secondary can call to withdraw dai', + 'UserSmartWallet secondary can call to withdraw sai', UserSmartWallet, 'withdrawDai', 'send', @@ -1999,7 +1999,7 @@ module.exports = {test: async function (provider, testingContext) { 'getNextCustomActionID', 'call', [ - 4, // DAIWithdrawal, + 4, // SAIWithdrawal, constants.FULL_APPROVAL, address, 0 @@ -2016,7 +2016,7 @@ module.exports = {test: async function (provider, testingContext) { 'getCustomActionID', 'call', [ - 4, // DAIWithdrawal, + 4, // SAIWithdrawal, constants.FULL_APPROVAL, address, 4, @@ -2103,14 +2103,14 @@ module.exports = {test: async function (provider, testingContext) { address.slice(2) // recipient ) - const daiWithdrawalSignature = signHashedPrefixedHashedHexString( + const saiWithdrawalSignature = signHashedPrefixedHashedHexString( withdrawalMessage, address ) */ await runTest( - 'UserSmartWallet cannot withdraw too much dai', + 'UserSmartWallet cannot withdraw too much sai', UserSmartWallet, 'withdrawDai', 'send', @@ -2170,7 +2170,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'UserSmartWallet cannot withdraw too little dai', + 'UserSmartWallet cannot withdraw too little sai', UserSmartWallet, 'withdrawDai', 'send', @@ -2198,12 +2198,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'UserSmartWallet can get a Dai withdrawal custom action ID', + 'UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', [ - 10, // DaiWithdrawal, + 10, // SaiWithdrawal, constants.FULL_APPROVAL, address, 0 @@ -2214,13 +2214,13 @@ module.exports = {test: async function (provider, testingContext) { } ) - let daiWithdrawalSignature = signHashedPrefixedHexString( + let saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) await runTest( - 'UserSmartWallet relay cannot call with bad signature to withdraw dai', + 'UserSmartWallet relay cannot call with bad signature to withdraw sai', UserSmartWallet, 'withdrawDai', 'send', @@ -2229,7 +2229,7 @@ module.exports = {test: async function (provider, testingContext) { address, 0, '0x', - '0xffffffff' + daiWithdrawalSignature.slice(10) + '0xffffffff' + saiWithdrawalSignature.slice(10) ], false, receipt => { @@ -2240,7 +2240,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'UserSmartWallet relay can call with signature to withdraw dai', + 'UserSmartWallet relay can call with signature to withdraw sai', UserSmartWallet, 'withdrawDai', 'send', @@ -2249,7 +2249,7 @@ module.exports = {test: async function (provider, testingContext) { address, 0, '0x', - daiWithdrawalSignature + saiWithdrawalSignature ], true, receipt => { @@ -2596,7 +2596,7 @@ module.exports = {test: async function (provider, testingContext) { 'getNextCustomActionID', 'call', [ - 4, // DAIWithdrawal, + 4, // SAIWithdrawal, constants.FULL_APPROVAL, address, 0 @@ -2613,7 +2613,7 @@ module.exports = {test: async function (provider, testingContext) { 'getCustomActionID', 'call', [ - 4, // DAIWithdrawal, + 4, // SAIWithdrawal, constants.FULL_APPROVAL, address, parseInt(originalNonce) + 1, @@ -2672,8 +2672,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'Dai Whale can deposit dai into the V5 smart wallet', - DAI, + 'Sai Whale can deposit sai into the V5 smart wallet', + SAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -2682,7 +2682,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -2694,7 +2694,7 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) await runTest( @@ -2746,19 +2746,19 @@ module.exports = {test: async function (provider, testingContext) { }) }) - assert.strictEqual(events[0].address, 'CDAI') + assert.strictEqual(events[0].address, 'CSAI') assert.strictEqual(events[0].eventName, 'AccrueInterest') - assert.strictEqual(events[1].address, 'DAI') + assert.strictEqual(events[1].address, 'SAI') assert.strictEqual(events[1].eventName, 'Transfer') //assert.strictEqual(events[1].returnValues.value, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[2].address, 'CDAI') + assert.strictEqual(events[2].address, 'CSAI') assert.strictEqual(events[2].eventName, 'Mint') //assert.strictEqual(events[2].returnValues.mintTokens, web3.utils.toWei('100', 'ether')) - assert.strictEqual(events[3].address, 'CDAI') + assert.strictEqual(events[3].address, 'CSAI') assert.strictEqual(events[3].eventName, 'Transfer') assert.strictEqual(events[4].address, 'CUSDC') @@ -2779,8 +2779,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'Dai Whale can deposit dai into the V5 smart wallet again', - DAI, + 'Sai Whale can deposit sai into the V5 smart wallet again', + SAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -2789,7 +2789,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -2801,7 +2801,7 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) await runTest( @@ -2851,8 +2851,8 @@ module.exports = {test: async function (provider, testingContext) { 'getNextGenericActionID', 'call', [ - DAI.options.address, - DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + SAI.options.address, + SAI.methods.approve(CSAI.options.address, 0).encodeABI(), 0 ], true, @@ -2877,8 +2877,8 @@ module.exports = {test: async function (provider, testingContext) { 'executeAction', 'send', [ - DAI.options.address, - DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + SAI.options.address, + SAI.methods.approve(CSAI.options.address, 0).encodeABI(), 0, executeActionUserSignature, executeActionSignature @@ -2919,8 +2919,8 @@ module.exports = {test: async function (provider, testingContext) { 'getNextGenericActionID', 'call', [ - DAI.options.address, - DAI.methods.approve(CDAI.options.address, constants.FULL_APPROVAL).encodeABI(), + SAI.options.address, + SAI.methods.approve(CSAI.options.address, constants.FULL_APPROVAL).encodeABI(), 0 ], true, @@ -2945,8 +2945,8 @@ module.exports = {test: async function (provider, testingContext) { 'executeAction', 'send', [ - DAI.options.address, - DAI.methods.approve(CDAI.options.address, constants.FULL_APPROVAL).encodeABI(), + SAI.options.address, + SAI.methods.approve(CSAI.options.address, constants.FULL_APPROVAL).encodeABI(), 0, executeActionUserSignature, executeActionSignature @@ -3189,7 +3189,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet secondary cannot call to withdraw dai without primary', + 'V5 UserSmartWallet secondary cannot call to withdraw sai without primary', UserSmartWalletV5, 'withdrawSai', 'send', @@ -3473,19 +3473,19 @@ module.exports = {test: async function (provider, testingContext) { address.slice(2) // recipient ) - const daiWithdrawalSignature = signHashedPrefixedHashedHexString( + const saiWithdrawalSignature = signHashedPrefixedHashedHexString( withdrawalMessage, address ) */ await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWalletV5, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, '1', address, 0 @@ -3496,18 +3496,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - let daiUserWithdrawalSignature = signHashedPrefixedHexString( + let saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw "dust" dai', + 'V5 UserSmartWallet relay cannot withdraw "dust" sai', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3515,8 +3515,8 @@ module.exports = {test: async function (provider, testingContext) { '1', address, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], false, receipt => {}, @@ -3524,12 +3524,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWalletV5, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, '1000000000000000', constants.NULL_ADDRESS, 0 @@ -3540,18 +3540,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - daiUserWithdrawalSignature = signHashedPrefixedHexString( + saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw dai to null address', + 'V5 UserSmartWallet relay cannot withdraw sai to null address', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3559,8 +3559,8 @@ module.exports = {test: async function (provider, testingContext) { '1000000000000000', constants.NULL_ADDRESS, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], false, receipt => {}, @@ -3568,12 +3568,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWalletV5, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, '1000000000000000', address, 0 @@ -3584,18 +3584,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - daiUserWithdrawalSignature = signHashedPrefixedHexString( + saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay can call with signature to withdraw dai', + 'V5 UserSmartWallet relay can call with signature to withdraw sai', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3603,8 +3603,8 @@ module.exports = {test: async function (provider, testingContext) { '1000000000000000', address, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], true, receipt => { @@ -3644,12 +3644,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWalletV5, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, constants.FULL_APPROVAL, address, 0 @@ -3660,18 +3660,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - daiUserWithdrawalSignature = signHashedPrefixedHexString( + saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad signature to withdraw dai', + 'V5 UserSmartWallet relay cannot call with bad signature to withdraw sai', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3679,8 +3679,8 @@ module.exports = {test: async function (provider, testingContext) { constants.FULL_APPROVAL, address, 0, - daiUserWithdrawalSignature, - '0xffffffff' + daiWithdrawalSignature.slice(10) + saiUserWithdrawalSignature, + '0xffffffff' + saiWithdrawalSignature.slice(10) ], false, receipt => { @@ -3691,7 +3691,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw dai', + 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw sai', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3699,8 +3699,8 @@ module.exports = {test: async function (provider, testingContext) { constants.FULL_APPROVAL, address, 0, - '0xffffffff' + daiUserWithdrawalSignature.slice(10), - daiWithdrawalSignature + '0xffffffff' + saiUserWithdrawalSignature.slice(10), + saiWithdrawalSignature ], false, receipt => { @@ -3711,7 +3711,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can call with signature to withdraw dai', + 'V5 UserSmartWallet relay can call with signature to withdraw sai', UserSmartWalletV5, 'withdrawDai', 'send', @@ -3719,8 +3719,8 @@ module.exports = {test: async function (provider, testingContext) { constants.FULL_APPROVAL, address, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], true, receipt => { @@ -4194,7 +4194,7 @@ module.exports = {test: async function (provider, testingContext) { 'getNextGenericAtomicBatchActionID', 'call', [ - [{to: DAI.options.address, data: DAI.methods.totalSupply().encodeABI()}], + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], 0 ], true, @@ -4221,7 +4221,7 @@ module.exports = {test: async function (provider, testingContext) { 'getGenericAtomicBatchActionID', 'call', [ - [{to: DAI.options.address, data: DAI.methods.totalSupply().encodeABI()}], + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], currentNonce, 0 ], @@ -4247,7 +4247,7 @@ module.exports = {test: async function (provider, testingContext) { 'executeActionWithAtomicBatchCalls', 'send', [ - [{to: DAI.options.address, data: DAI.methods.totalSupply().encodeABI()}], + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], 0, executeActionUserSignature, executeActionSignature @@ -4818,8 +4818,8 @@ module.exports = {test: async function (provider, testingContext) { 'getNextGenericActionID', 'call', [ - DAI.options.address, - DAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), + SAI.options.address, + SAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), 0 ], true, @@ -4844,8 +4844,8 @@ module.exports = {test: async function (provider, testingContext) { 'executeAction', 'send', [ - DAI.options.address, - DAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), + SAI.options.address, + SAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), 0, executeActionUserSignature, executeActionSignature @@ -4853,12 +4853,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, '100000000000000000000000000000000000000', // too much address, 0 @@ -4869,18 +4869,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - daiUserWithdrawalSignature = signHashedPrefixedHexString( + saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw too much dai', + 'V5 UserSmartWallet relay cannot withdraw too much sai', UserSmartWallet, 'withdrawDai', 'send', @@ -4888,8 +4888,8 @@ module.exports = {test: async function (provider, testingContext) { '100000000000000000000000000000000000000', // too much address, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], true, receipt => { @@ -4954,8 +4954,8 @@ module.exports = {test: async function (provider, testingContext) { 'call', [ [{ - to: DAI.options.address, - data: DAI.methods.transfer( + to: SAI.options.address, + data: SAI.methods.transfer( address, '100000000000000000000000000000' ).encodeABI() }], @@ -4984,8 +4984,8 @@ module.exports = {test: async function (provider, testingContext) { 'send', [ [{ - to: DAI.options.address, - data: DAI.methods.transfer( + to: SAI.options.address, + data: SAI.methods.transfer( address, '100000000000000000000000000000' ).encodeABI() }], @@ -5007,7 +5007,7 @@ module.exports = {test: async function (provider, testingContext) { [ Comptroller.options.address, Comptroller.methods.enterMarkets( - [constants.CDAI_MAINNET_ADDRESS] + [constants.CSAI_MAINNET_ADDRESS] ).encodeABI(), 0 ], @@ -5028,14 +5028,14 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeAction to enter dai market', + 'V5 UserSmartWallet can call executeAction to enter sai market', UserSmartWalletV5, 'executeAction', 'send', [ Comptroller.options.address, Comptroller.methods.enterMarkets( - [constants.CDAI_MAINNET_ADDRESS] + [constants.CSAI_MAINNET_ADDRESS] ).encodeABI(), 0, executeActionUserSignature, @@ -5044,8 +5044,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'Dai Whale can deposit dai into the smart wallet', - DAI, + 'Sai Whale can deposit sai into the smart wallet', + SAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -5054,7 +5054,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -5066,7 +5066,7 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.DAI_WHALE_ADDRESS + constants.SAI_WHALE_ADDRESS ) await runTest( @@ -5081,8 +5081,8 @@ module.exports = {test: async function (provider, testingContext) { 'getNextGenericActionID', 'call', [ - CDAI_BORROW.options.address, - CDAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), + CSAI_BORROW.options.address, + CSAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), 0 ], true, @@ -5107,8 +5107,8 @@ module.exports = {test: async function (provider, testingContext) { 'executeAction', 'send', [ - CDAI_BORROW.options.address, - CDAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), + CSAI_BORROW.options.address, + CSAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), 0, executeActionUserSignature, executeActionSignature @@ -5121,12 +5121,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Dai withdrawal custom action ID', + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', UserSmartWalletV5, 'getNextCustomActionID', 'call', [ - 4, // DaiWithdrawal, + 4, // SaiWithdrawal, constants.FULL_APPROVAL, address, 0 @@ -5137,18 +5137,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - daiWithdrawalSignature = signHashedPrefixedHexString( + saiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - daiUserWithdrawalSignature = signHashedPrefixedHexString( + saiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw max dai with an outstanding borrow', + 'V5 UserSmartWallet relay cannot withdraw max sai with an outstanding borrow', UserSmartWalletV5, 'withdrawDai', 'send', @@ -5156,8 +5156,8 @@ module.exports = {test: async function (provider, testingContext) { constants.FULL_APPROVAL, address, 0, - daiUserWithdrawalSignature, - daiWithdrawalSignature + saiUserWithdrawalSignature, + saiWithdrawalSignature ], true, receipt => { From 83f7fd4e9d382321bfc06e01efe5164c270904ac Mon Sep 17 00:00:00 2001 From: 0age <0age@protonmail.com> Date: Tue, 7 Jan 2020 23:46:11 -0500 Subject: [PATCH 3/5] port coverage from DSWv5 to DSWv6 --- .solcover.js | 4 +- .../DharmaSmartWalletImplementationV6.sol | 12 +- ...maSmartWalletImplementationV0Interface.sol | 4 +- package.json | 10 +- scripts/test/constants.js | 4 +- scripts/test/deployMockExternal.js | 11 +- scripts/test/test.js | 3302 +++++++++++++++-- 7 files changed, 3060 insertions(+), 287 deletions(-) diff --git a/.solcover.js b/.solcover.js index 3ddb169..15d2216 100644 --- a/.solcover.js +++ b/.solcover.js @@ -25,8 +25,8 @@ module.exports = { 'implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol', 'implementations/smart-wallet/DharmaSmartWalletImplementationV3.sol', 'implementations/smart-wallet/DharmaSmartWalletImplementationV4.sol', - //'implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol', - 'implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol', + 'implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol', + //'implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol', 'implementations/smart-wallet/DharmaSmartWalletImplementationVX.sol', 'mock/MockCodeCheck.sol', 'mock/RelayContract.sol', diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol index 40859fb..0692d8b 100644 --- a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol +++ b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol @@ -934,7 +934,7 @@ contract DharmaSmartWalletImplementationV6 is * multiple future actions ahead of time. * @param action uint8 The type of action, designated by it's index. Valid * custom actions in V6 include Cancel (0), SetUserSigningKey (1), - * DAIWithdrawal (4), USDCWithdrawal (5), ETHWithdrawal (6), + * DAIWithdrawal (10), USDCWithdrawal (5), ETHWithdrawal (6), * SetEscapeHatch (7), RemoveEscapeHatch (8), and DisableEscapeHatch (9). * @param amount uint256 The amount to withdraw for Withdrawal actions. This * value is ignored for non-withdrawal action types. @@ -975,7 +975,7 @@ contract DharmaSmartWalletImplementationV6 is * taken. * @param action uint8 The type of action, designated by it's index. Valid * custom actions in V6 include Cancel (0), SetUserSigningKey (1), - * DAIWithdrawal (4), USDCWithdrawal (5), ETHWithdrawal (6), + * DAIWithdrawal (10), USDCWithdrawal (5), ETHWithdrawal (6), * SetEscapeHatch (7), RemoveEscapeHatch (8), and DisableEscapeHatch (9). * @param amount uint256 The amount to withdraw for Withdrawal actions. This * value is ignored for non-withdrawal action types. @@ -1568,7 +1568,7 @@ contract DharmaSmartWalletImplementationV6 is * requirement). * @param action uint8 The type of action, designated by it's index. Valid * actions in V6 include Cancel (0), SetUserSigningKey (1), Generic (2), - * GenericAtomicBatch (3), DAIWithdrawal (4), USDCWithdrawal (5), + * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5), * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and * DisableEscapeHatch (9). * @param arguments bytes ABI-encoded arguments for the action. @@ -1819,7 +1819,7 @@ contract DharmaSmartWalletImplementationV6 is * returned from `getCustomActionID`. * @param action uint8 The type of action, designated by it's index. Valid * actions in V6 include Cancel (0), SetUserSigningKey (1), Generic (2), - * GenericAtomicBatch (3), DAIWithdrawal (4), USDCWithdrawal (5), + * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5), * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and * DisableEscapeHatch (9). * @param arguments bytes ABI-encoded arguments for the action. @@ -1871,7 +1871,7 @@ contract DharmaSmartWalletImplementationV6 is * on the supplied parameters. * @param action uint8 The type of action, designated by it's index. Valid * actions in V6 include Cancel (0), SetUserSigningKey (1), Generic (2), - * GenericAtomicBatch (3), DAIWithdrawal (4), USDCWithdrawal (5), + * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5), * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and * DisableEscapeHatch (9). * @param arguments bytes ABI-encoded arguments for the action. @@ -1975,7 +1975,7 @@ contract DharmaSmartWalletImplementationV6 is * the "arguments" input to an actionID based on that action type. * @param action uint8 The type of action, designated by it's index. Valid * custom actions in V6 include Cancel (0), SetUserSigningKey (1), - * DAIWithdrawal (4), USDCWithdrawal (5), ETHWithdrawal (6), + * DAIWithdrawal (10), USDCWithdrawal (5), ETHWithdrawal (6), * SetEscapeHatch (7), RemoveEscapeHatch (8), and DisableEscapeHatch (9). * @param amount uint256 The amount to withdraw for Withdrawal actions. This * value is ignored for all non-withdrawal action types. diff --git a/interfaces/DharmaSmartWalletImplementationV0Interface.sol b/interfaces/DharmaSmartWalletImplementationV0Interface.sol index 85f99d5..d8c24ee 100644 --- a/interfaces/DharmaSmartWalletImplementationV0Interface.sol +++ b/interfaces/DharmaSmartWalletImplementationV0Interface.sol @@ -66,10 +66,10 @@ interface DharmaSmartWalletImplementationV0Interface { ) external; function getBalances() external returns ( - uint256 saiBalance, + uint256 daiBalance, uint256 usdcBalance, uint256 etherBalance, - uint256 cSAIUnderlyingSaiBalance, + uint256 cDaiUnderlyingDaiBalance, uint256 cUSDCUnderlyingUSDCBalance, uint256 cEtherUnderlyingEtherBalance ); diff --git a/package.json b/package.json index e9ed673..0518b5b 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,14 @@ "web3": "1.2.1" }, "scripts": { - "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", + "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "build": "./node_modules/.bin/truffle compile", "ci": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -q & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", - "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", "lint": "./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", - "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", + "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", + "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", "stop": "kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "test": "./node_modules/.bin/truffle compile && node scripts/test/ci.js" } diff --git a/scripts/test/constants.js b/scripts/test/constants.js index c70b7bc..318ffa7 100644 --- a/scripts/test/constants.js +++ b/scripts/test/constants.js @@ -365,11 +365,13 @@ module.exports = Object.freeze({ ), CONTRACT_NAMES: { '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': 'SAI', + '0x6B175474E89094C44Da98b954EedeAC495271d0F': 'DAI', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': 'USDC', '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC': 'CSAI', + '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643': 'CDAI', '0x39AA39c021dfbaE8faC545936693aC917d5E7563': 'CUSDC', '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5': 'CETH', - '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B': 'Comptroller' + '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B': 'Comptroller' }, EVENT_DETAILS: { // keccak256 of NewUserSigningKey(address) -> userSigningKey diff --git a/scripts/test/deployMockExternal.js b/scripts/test/deployMockExternal.js index 62604f2..8d7ab64 100644 --- a/scripts/test/deployMockExternal.js +++ b/scripts/test/deployMockExternal.js @@ -4995,7 +4995,7 @@ module.exports = {test: async function (provider, testingContext) { } console.log('deploying Compound cSai...') - const cDaiDeploymentReceipt = await web3.eth.sendTransaction({ + const cSaiDeploymentReceipt = await web3.eth.sendTransaction({ from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1, gasPrice: 1, @@ -5003,7 +5003,7 @@ module.exports = {test: async function (provider, testingContext) { }) assert.strictEqual( - cDaiDeploymentReceipt.contractAddress, constants.CSAI_MAINNET_ADDRESS + cSaiDeploymentReceipt.contractAddress, constants.CSAI_MAINNET_ADDRESS ) for (i = 15; i < 17; i++) { @@ -5142,8 +5142,11 @@ module.exports = {test: async function (provider, testingContext) { from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6', gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1, gasPrice: 1, - data: mockCDaiDeploymentData - }) + data: mockCDaiDeploymentData.replace( + '89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + constants.DAI_MAINNET_ADDRESS.slice(2) + ) + }) assert.strictEqual( daiDeploymentReceipt.contractAddress, constants.CDAI_MAINNET_ADDRESS diff --git a/scripts/test/test.js b/scripts/test/test.js index 53704c9..8401bf3 100644 --- a/scripts/test/test.js +++ b/scripts/test/test.js @@ -22,6 +22,7 @@ const DharmaSmartWalletImplementationV0Artifact = require('../../build/contracts const DharmaSmartWalletImplementationV1Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV1.json') const DharmaSmartWalletImplementationV2Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV2.json') const DharmaSmartWalletImplementationV5Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV5.json') +const DharmaSmartWalletImplementationV6Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV6.json') const DharmaKeyRingImplementationV1Artifact = require('../../build/contracts/DharmaKeyRingImplementationV1.json') const DharmaKeyRingFactoryV1Artifact = require('../../build/contracts/DharmaKeyRingFactoryV1.json') @@ -129,6 +130,10 @@ module.exports = {test: async function (provider, testingContext) { IERC20Artifact.abi, constants.SAI_MAINNET_ADDRESS ) + const DAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.DAI_MAINNET_ADDRESS + ) + const USDC = new web3.eth.Contract( IERC20Artifact.abi, constants.USDC_MAINNET_ADDRESS ) @@ -137,6 +142,10 @@ module.exports = {test: async function (provider, testingContext) { IERC20Artifact.abi, constants.CSAI_MAINNET_ADDRESS ) + const CDAI = new web3.eth.Contract( + IERC20Artifact.abi, constants.CDAI_MAINNET_ADDRESS + ) + const CUSDC = new web3.eth.Contract( IERC20Artifact.abi, constants.CUSDC_MAINNET_ADDRESS ) @@ -183,6 +192,13 @@ module.exports = {test: async function (provider, testingContext) { DharmaSmartWalletImplementationV5Artifact.bytecode ) + const DharmaSmartWalletImplementationV6Deployer = new web3.eth.Contract( + DharmaSmartWalletImplementationV6Artifact.abi + ) + DharmaSmartWalletImplementationV6Deployer.options.data = ( + DharmaSmartWalletImplementationV6Artifact.bytecode + ) + const AdharmaKeyRingImplementationDeployer = new web3.eth.Contract( AdharmaKeyRingImplementationArtifact.abi ) @@ -1081,6 +1097,13 @@ module.exports = {test: async function (provider, testingContext) { 'deploy' ) + const DharmaSmartWalletImplementationV6 = await runTest( + `DharmaSmartWalletImplementationV6 contract deployment`, + DharmaSmartWalletImplementationV6Deployer, + '', + 'deploy' + ) + const DharmaKeyRingImplementationV1 = await runTest( `DharmaKeyRingImplementationV1 contract deployment`, DharmaKeyRingImplementationV1Deployer, @@ -1644,6 +1667,11 @@ module.exports = {test: async function (provider, testingContext) { targetWalletAddress ) + const UserSmartWalletV6 = new web3.eth.Contract( + DharmaSmartWalletImplementationV6Artifact.abi, + targetWalletAddress + ) + await runTest( 'DharmaSmartWalletFactoryV1 gets a new smart wallet address with same key', DharmaSmartWalletFactoryV1, @@ -3691,16 +3719,2825 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw sai', - UserSmartWalletV5, + 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw sai', + UserSmartWalletV5, + 'withdrawDai', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + '0xffffffff' + saiUserWithdrawalSignature.slice(10), + saiWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet relay can call with signature to withdraw sai', + UserSmartWalletV5, + 'withdrawDai', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + saiUserWithdrawalSignature, + saiWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 6, // ETHWithdrawal, + '0', // no amount + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + let ethWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + let ethUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot to withdraw ether with no amount', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '0', + address, + 0, + ethUserWithdrawalSignature, + ethWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 6, // ETHWithdrawal, + '1', + constants.NULL_ADDRESS, // no recipient + 0 + ], + true, + value => { + customActionId = value + } + ) + + ethWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + ethUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot to withdraw ether with no recipient', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + constants.NULL_ADDRESS, + 0, + ethUserWithdrawalSignature, + ethWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 6, // ETHWithdrawal, + '1', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + ethWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + ethUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot call with bad signature to withdraw eth', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + ethUserWithdrawalSignature, + '0xffffffff' + ethWithdrawalSignature.slice(10) + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw eth', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + '0xffffffff' + ethUserWithdrawalSignature.slice(10), + ethWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet relay can call with signature to withdraw ether', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + ethUserWithdrawalSignature, + ethWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 6, // ETHWithdrawal, + '1', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + ethWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + ethUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot call with bad signature to withdraw eth', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + ethUserWithdrawalSignature, + '0xffffffff' + ethWithdrawalSignature.slice(10) + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw eth', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + '0xffffffff' + ethUserWithdrawalSignature.slice(10), + ethWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet relay can call with signature to withdraw ether', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + address, + 0, + ethUserWithdrawalSignature, + ethWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet cancel reverts with bad signature', + UserSmartWalletV5, + 'cancel', + 'send', + [ + 0, + '0x' + ], + false, + receipt => {}, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet calls revert if insufficient action gas is supplied', + UserSmartWalletV5, + 'cancel', + 'send', + [ + constants.FULL_APPROVAL, + '0x' + ], + false + ) + + await runTest( + 'V5 UserSmartWallet calls succeed if sufficient non-zero action gas supplied', + UserSmartWalletV5, + 'cancel', + 'send', + [ + '1', + '0x' + ] + ) + + await runTest( + 'V5 UserSmartWallet can get a cancel custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 0, // Cancel, + '0', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + let cancelSignature = signHashedPrefixedHexString(customActionId, addressTwo) + + await runTest( + 'V5 UserSmartWallet can cancel using a signature', + UserSmartWalletV5, + 'cancel', + 'send', + [ + '0', + cancelSignature + ], + true, + receipt => {}, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet calls to atomic methods revert', + UserSmartWalletV5, + '_withdrawSaiAtomic', + 'send', + [ + '1', + address + ], + false + ) + + await runTest( + 'V5 UserSmartWallet calls to recover from random address revert', + UserSmartWalletV5, + 'recover', + 'send', + [ + address + ], + false + ) + + await runTest( + 'DharmaSmartWalletFactoryV1 can deploy a V5 smart wallet using a Dharma Key', + DharmaSmartWalletFactoryV1, + 'newSmartWallet', + 'send', + [addressTwo], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + + assert.strictEqual(events[0].eventName, 'NewUserSigningKey') + assert.strictEqual(events[0].returnValues.userSigningKey, addressTwo) + //console.log(events) + + // TODO: test more events + } + } + ) + + await runTest( + 'V5 UserSmartWallet can get a generic action ID', + UserSmartWalletV5, + 'getNextGenericActionID', + 'call', + [ + USDC.options.address, + USDC.methods.approve(CUSDC.options.address, 0).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet cannot call executeAction and target a non-contract', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + address, + USDC.methods.approve(CUSDC.options.address, 0).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ], + false + ) + + await runTest( + 'V5 UserSmartWallet cannot call executeAction and target itself', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + UserSmartWalletV5.options.address, + USDC.methods.approve(CUSDC.options.address, 0).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ], + false + ) + + await runTest( + 'V5 UserSmartWallet can call executeAction', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + USDC.options.address, + USDC.methods.approve(CUSDC.options.address, 0).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'V5 UserSmartWallet can get the next generic batch action ID', + UserSmartWalletV5, + 'getNextGenericAtomicBatchActionID', + 'call', + [ + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], + 0 + ], + true, + value => { + customActionId = value + } + ) + + await runTest( + 'UserSmartWallet can get the nonce', + UserSmartWalletV5, + 'getNonce', + 'call', + [], + true, + value => { + currentNonce = value + } + ) + + await runTest( + 'V5 UserSmartWallet generic batch action ID with nonce matches next ID', + UserSmartWalletV5, + 'getGenericAtomicBatchActionID', + 'call', + [ + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], + currentNonce, + 0 + ], + true, + value => { + assert.strictEqual(value, customActionId) + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet can call executeActionWithAtomicBatchCalls', + UserSmartWalletV5, + 'executeActionWithAtomicBatchCalls', + 'send', + [ + [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}], + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'USDC Whale can deposit usdc into the deployed smart wallet', + USDC, + 'transfer', + 'send', + [targetWalletAddress, web3.utils.toWei('100', 'lovelace')], // six decimals + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.USDC_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetWalletAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'lovelace') + ) + } + }, + constants.USDC_WHALE_ADDRESS + ) + + await runTest( + 'new user smart wallet can trigger repayAndDeposit to deposit all new funds', + UserSmartWalletV5, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + assert.strictEqual(events[0].address, 'USDC') + assert.strictEqual(events[0].eventName, 'Approval') + assert.strictEqual(events[0].returnValues.value, constants.FULL_APPROVAL) + + assert.strictEqual(events[1].address, 'CUSDC') + assert.strictEqual(events[1].eventName, 'AccrueInterest') + + assert.strictEqual(events[2].address, 'USDC') + assert.strictEqual(events[2].eventName, 'Transfer') + assert.strictEqual(events[2].returnValues.value, web3.utils.toWei('100', 'lovelace')) + + assert.strictEqual(events[3].address, 'CUSDC') + assert.strictEqual(events[3].eventName, 'Mint') + assert.strictEqual(events[3].returnValues.mintTokens, web3.utils.toWei('100', 'lovelace')) + + assert.strictEqual(events[4].address, 'CUSDC') + assert.strictEqual(events[4].eventName, 'Transfer') + } + } + ) + + const FIAT_TOKEN = new web3.eth.Contract( + [ + { + "constant": true, "inputs": [], "name": "blacklister", + "outputs": [{"name": "", "type": "address"}], "payable": false, + "stateMutability": "view", "type": "function" + }, { + "constant": false, "inputs": [{"name": "_account", "type": "address"}], + "name": "unBlacklist", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" + }, { + "constant": false, "inputs": [{"name": "_account", "type": "address"}], + "name": "blacklist", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" + }, { + "constant": true, "inputs": [{"name": "_account", "type": "address"}], + "name": "isBlacklisted", "outputs": [{"name": "", "type": "bool"}], + "payable": false, "stateMutability": "view", "type": "function" + }, { + "constant": false, "inputs": [], + "name": "pause", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" + }, { + "constant": false, "inputs": [], + "name": "unpause", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" + }, { + "constant": true, "inputs": [], "name": "pauser", + "outputs": [{"name": "", "type": "address"}], "payable": false, + "stateMutability": "view", "type": "function" + } + ], + constants.USDC_MAINNET_ADDRESS + ) + + let blacklister + await runTest( + 'Check blacklister address', + FIAT_TOKEN, + 'blacklister', + 'call', + [], + true, + value => { + blacklister = value + } + ) + + let pausear + await runTest( + 'Check pauser address', + FIAT_TOKEN, + 'pauser', + 'call', + [], + true, + value => { + pauser = value + } + ) + + await runTest( + 'blacklist mock address', + FIAT_TOKEN, + 'blacklist', + 'send', + [constants.MOCK_USDC_BLACKLISTED_ADDRESS], + true, + receipt => {}, + blacklister + ) + + let targetBlacklistAddress; + await runTest( + 'DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time', + DharmaSmartWalletFactoryV1, + 'getNextSmartWallet', + 'call', + [constants.MOCK_USDC_BLACKLISTED_ADDRESS], + true, + value => { + targetBlacklistAddress = value + } + ) + + const BlacklistedUserSmartWalletV5 = new web3.eth.Contract( + DharmaSmartWalletImplementationV5Artifact.abi, + targetBlacklistAddress + ) + + await runTest( + 'USDC Whale can deposit usdc into the yet-to-be-blacklisted smart wallet', + USDC, + 'transfer', + 'send', + [targetBlacklistAddress, web3.utils.toWei('100', 'lovelace')], // six decimals + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.USDC_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetBlacklistAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'lovelace') + ) + } + }, + constants.USDC_WHALE_ADDRESS + ) + + await runTest( + 'blacklist counterfactual deployment address', + FIAT_TOKEN, + 'blacklist', + 'send', + [targetBlacklistAddress], + true, + receipt => {}, + blacklister + ) + + await runTest( + 'DharmaSmartWalletFactoryV1 can deploy to a blacklisted address', + DharmaSmartWalletFactoryV1, + 'newSmartWallet', + 'send', + [constants.MOCK_USDC_BLACKLISTED_ADDRESS], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'blacklisted smart wallet will not approve USDC during repayAndDeposit', + BlacklistedUserSmartWalletV5, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'un-blacklist counterfactual deployment address', + FIAT_TOKEN, + 'unBlacklist', + 'send', + [targetBlacklistAddress], + true, + receipt => {}, + blacklister + ) + + await runTest( + 'pause USDC', + FIAT_TOKEN, + 'pause', + 'send', + [], + true, + receipt => {}, + pauser + ) + + await runTest( + 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + constants.FULL_APPROVAL, + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet attempt to withdraw max USDC when paused causes ExternalError', + UserSmartWalletV5, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'smart wallet will not approve USDC when paused during repayAndDeposit', + BlacklistedUserSmartWalletV5, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'unpause USDC', + FIAT_TOKEN, + 'unpause', + 'send', + [], + true, + receipt => {}, + pauser + ) + + await runTest( + 'unblacklisted, unpaused smart wallet approves USDC during repayAndDeposit', + BlacklistedUserSmartWalletV5, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'V5 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + web3.utils.toWei('50', 'lovelace'), + constants.MOCK_USDC_BLACKLISTED_ADDRESS, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay call to withdraw USDC to blacklisted address', + UserSmartWallet, + 'withdrawUSDC', + 'send', + [ + web3.utils.toWei('50', 'lovelace'), + constants.MOCK_USDC_BLACKLISTED_ADDRESS, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt.events[0]) + //console.log(receipt.events.ExternalError) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + constants.FULL_APPROVAL, + UserSmartWallet.options.address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay call to withdraw USDC to itself', + UserSmartWallet, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + UserSmartWallet.options.address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + constants.FULL_APPROVAL, + constants.MOCK_USDC_BLACKLISTED_ADDRESS, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay call to withdraw USDC to blacklisted address', + UserSmartWallet, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + constants.MOCK_USDC_BLACKLISTED_ADDRESS, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt.events[0]) + //console.log(receipt.events.ExternalError) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 6, // ETHWithdrawal, + '1', + targetWalletAddress, + 0 + ], + true, + value => { + customActionId = value + } + ) + + ethWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + ethUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot withdraw eth to a non-payable account', + UserSmartWalletV5, + 'withdrawEther', + 'send', + [ + '1', + targetWalletAddress, + 0, + ethUserWithdrawalSignature, + ethWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + let targetWalletAddressTwo; + await runTest( + 'DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time', + DharmaSmartWalletFactoryV1, + 'getNextSmartWallet', + 'call', + [targetWalletAddress], + true, + value => { + // TODO: verify against expected value + targetWalletAddressTwo = value + } + ) + + await runTest( + 'DharmaSmartWalletFactoryV1 can deploy a V5 smart wallet using a contract key', + DharmaSmartWalletFactoryV1, + 'newSmartWallet', + 'send', + [targetWalletAddress] + ) + + const UserSmartWalletV5Two = new web3.eth.Contract( + DharmaSmartWalletImplementationV5Artifact.abi, + targetWalletAddressTwo + ) + + await runTest( + 'V5 UserSmartWallet cancel reverts with bad contract signature', + UserSmartWalletV5Two, + 'cancel', + 'send', + [ + 0, + '0x' + ], + false, + receipt => {}, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a generic action ID', + UserSmartWalletV5, + 'getNextGenericActionID', + 'call', + [ + SAI.options.address, + SAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet can call executeAction', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + SAI.options.address, + SAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 4, // SaiWithdrawal, + '100000000000000000000000000000000000000', // too much + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + saiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + saiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot withdraw too much sai', + UserSmartWallet, + 'withdrawDai', + 'send', + [ + '100000000000000000000000000000000000000', // too much + address, + 0, + saiUserWithdrawalSignature, + saiWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt.events) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + '100000000000000000000000000000000000000', // too much + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + + await runTest( + 'V5 UserSmartWallet relay can call with two signatures to withdraw USDC', + UserSmartWallet, + 'withdrawUSDC', + 'send', + [ + '100000000000000000000000000000000000000', // too much + address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get next generic batch action ID', + UserSmartWalletV5, + 'getNextGenericAtomicBatchActionID', + 'call', + [ + [{ + to: SAI.options.address, + data: SAI.methods.transfer( + address, '100000000000000000000000000000' + ).encodeABI() + }], + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure', + UserSmartWalletV5, + 'executeActionWithAtomicBatchCalls', + 'send', + [ + [{ + to: SAI.options.address, + data: SAI.methods.transfer( + address, '100000000000000000000000000000' + ).encodeABI() + }], + 0, + executeActionUserSignature, + executeActionSignature + ], + true, + receipt => { + //console.log(receipt) + } + ) + + await runTest( + 'V5 UserSmartWallet can get a generic action ID', + UserSmartWalletV5, + 'getNextGenericActionID', + 'call', + [ + Comptroller.options.address, + Comptroller.methods.enterMarkets( + [constants.CSAI_MAINNET_ADDRESS] + ).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet can call executeAction to enter sai market', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + Comptroller.options.address, + Comptroller.methods.enterMarkets( + [constants.CSAI_MAINNET_ADDRESS] + ).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'Sai Whale can deposit sai into the smart wallet', + SAI, + 'transfer', + 'send', + [targetWalletAddress, web3.utils.toWei('100', 'ether')], + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.SAI_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetWalletAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'ether') + ) + } + }, + constants.SAI_WHALE_ADDRESS + ) + + await runTest( + 'V5 UserSmartWallet can trigger repayAndDeposit to deposit all new funds', + UserSmartWalletV5, + 'repayAndDeposit' + ) + + await runTest( + 'V5 UserSmartWallet can get a generic action ID', + UserSmartWalletV5, + 'getNextGenericActionID', + 'call', + [ + CSAI_BORROW.options.address, + CSAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet can call executeAction to perform a borrow', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + CSAI_BORROW.options.address, + CSAI_BORROW.methods.borrow(web3.utils.toWei('.01', 'ether')).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ], + true, + receipt => { + //console.log(receipt.events) + }, + originalAddress + ) + + await runTest( + 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', + UserSmartWalletV5, + 'getNextCustomActionID', + 'call', + [ + 4, // SaiWithdrawal, + constants.FULL_APPROVAL, + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + saiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + saiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet relay cannot withdraw max sai with an outstanding borrow', + UserSmartWalletV5, + 'withdrawDai', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + saiUserWithdrawalSignature, + saiWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt.events) + }, + originalAddress + ) + + // Initiate account recovery + await runTest( + 'smart wallet account recovery can be initiated', + DharmaAccountRecoveryManagerV2, + 'initiateAccountRecovery', + 'send', + [ + UserSmartWalletV5.options.address, + originalAddress, + 0 // extraTime in seconds + ], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'smart wallet account recovery cannot be performed right away', + DharmaAccountRecoveryManagerV2, + 'recover', + 'send', + [ + UserSmartWalletV5.options.address, + originalAddress + ], + false + ) + + // advance time by 3 days + await advanceTime((60 * 60 * 24 * 3) + 5) + + // recover account + await runTest( + 'smart wallet account recovery can be performed after three days', + DharmaAccountRecoveryManagerV2, + 'recover', + 'send', + [ + UserSmartWalletV5.options.address, + originalAddress + ], + true, + receipt => { + // TODO: verify + //console.log(receipt.events) + } + ) + + await runTest( + 'UserSmartWalletV5 can get the nonce prior to upgrade', + UserSmartWalletV5, + 'getNonce', + 'call', + [], + true, + value => { + originalNonce = value + } + ) + + // XXXXX + + + + await runTest( + 'Dharma Upgrade Beacon Controller can upgrade to V6 implementation', + DharmaUpgradeBeaconController, + 'upgrade', + 'send', + [ + DharmaUpgradeBeacon.options.address, + DharmaSmartWalletImplementationV6.options.address + ], + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Upgraded.returnValues.upgradeBeacon, + DharmaUpgradeBeacon.options.address + ) + assert.strictEqual( + receipt.events.Upgraded.returnValues.oldImplementation, + DharmaSmartWalletImplementationV5.options.address + ) + /* TODO + assert.strictEqual( + receipt.events.Upgraded.returnValues.oldImplementationCodeHash, + constants.EMPTY_HASH + ) + */ + assert.strictEqual( + receipt.events.Upgraded.returnValues.newImplementation, + DharmaSmartWalletImplementationV6.options.address + ) + /* TODO + assert.strictEqual( + receipt.events.Upgraded.returnValues.newImplementationCodeHash, + ... + ) + */ + } + } + ) + + await runTest( + 'DharmaUpgradeBeacon has the implementation set', + DharmaUpgradeBeaconController, + 'getImplementation', + 'call', + [DharmaUpgradeBeacon.options.address], + true, + value => { + assert.strictEqual(value, DharmaSmartWalletImplementationV6.options.address) + } + ) + + const UpgradeBeaconImplementationCheckV6 = await runTest( + `UpgradeBeaconImplementationCheck deployment`, + UpgradeBeaconImplementationCheckDeployer, + '', + 'deploy', + [ + DharmaUpgradeBeacon.options.address, + DharmaSmartWalletImplementationV6.options.address + ] + ) + + await runTest( + 'V6 user smart wallet can be called and still has the same dharma key set', + UserSmartWalletV6, + 'getUserSigningKey', + 'call', + [], + true, + value => { + assert.strictEqual(value, originalAddress) + } + ) + + await runTest( + 'V6 UserSmartWallet can get the new version (6)', + UserSmartWalletV6, + 'getVersion', + 'call', + [], + true, + value => { + assert.strictEqual(value, '6') + } + ) + + await runTest( + 'V6 UserSmartWallet nonce is still set to value from before upgrade', + UserSmartWalletV6, + 'getNonce', + 'call', + [], + true, + value => { + assert.strictEqual(value, originalNonce) + } + ) + + await runTest( + 'V6 UserSmartWallet can get balances', + UserSmartWalletV6, + 'getBalances', + 'call', + [], + true, + value => { + //console.log(value) + } + ) + + await runTest( + 'V6 UserSmartWallet secondary can call to cancel', + UserSmartWalletV6, + 'cancel', + 'send', + [ + 0, + '0x' + ] + ) + + await runTest( + 'V6 UserSmartWallet nonce is now set to original + 1', + UserSmartWalletV6, + 'getNonce', + 'call', + [], + true, + value => { + assert.strictEqual(value, (parseInt(originalNonce) + 1).toString()) + } + ) + + await runTest( + 'V6 UserSmartWallet can get next custom action ID to set a user signing key', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 1, // SetUserSigningKey, + constants.FULL_APPROVAL, // This value shouldn't matter + addressTwo, + 0 + ], + true, + value => { + customActionId = value + } + ) + + setUserSigningKeyDharmaSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + await runTest( + 'V6 UserSmartWallet can set a new user signing key with signatures', + UserSmartWalletV6, + 'setUserSigningKey', + 'send', + [ + addressTwo, + 0, + '0x', + setUserSigningKeyDharmaSignature + ], + true, + receipt => {}, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet has the new user signing key set', + UserSmartWalletV6, + 'getUserSigningKey', + 'call', + [], + true, + value => { + assert.strictEqual(value, addressTwo) + } + ) + + await runTest( + 'V6 UserSmartWallet can get next custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 0, // DAIWithdrawal + constants.FULL_APPROVAL, + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + await runTest( + 'V6 UserSmartWallet can get custom action ID and it matches next action ID', + UserSmartWalletV6, + 'getCustomActionID', + 'call', + [ + 0, // DAIWithdrawal + constants.FULL_APPROVAL, + address, + parseInt(originalNonce) + 2, + 0 + ], + true, + value => { + assert.strictEqual(value, customActionId) + } + ) + + await runTest( + 'V6 UserSmartWallet can get next generic action ID', + UserSmartWalletV6, + 'getNextGenericActionID', + 'call', + [ + address, + '0x', + 0 + ], + true, + value => { + genericActionID = value + } + ) + + await runTest( + 'V6 UserSmartWallet can get generic action ID and it matches next action ID', + UserSmartWalletV6, + 'getGenericActionID', + 'call', + [ + address, + '0x', + parseInt(originalNonce) + 2, + 0 + ], + true, + value => { + assert.strictEqual(value, genericActionID) + } + ) + + await runTest( + 'UserSmartWallet calls to atomic methods revert', + UserSmartWalletV6, + '_withdrawDaiAtomic', + 'send', + [ + '1', + address + ], + false + ) + + // Give the Dai Whale some ETH so it can make transactions + await web3.eth.sendTransaction({ + from: address, + to: constants.DAI_WHALE_ADDRESS, + value: web3.utils.toWei('1', 'ether'), + gas: (testingContext !== 'coverage') ? '0xffff' : gasLimit - 1, + gasPrice: 1 + }) + + await runTest( + 'Dai Whale can deposit Dai into the V6 smart wallet', + DAI, + 'transfer', + 'send', + [targetWalletAddress, web3.utils.toWei('100', 'ether')], + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.DAI_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetWalletAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'ether') + ) + } + }, + constants.DAI_WHALE_ADDRESS + ) + + await runTest( + 'USDC Whale can deposit usdc into the V6 smart wallet', + USDC, + 'transfer', + 'send', + [targetWalletAddress, web3.utils.toWei('100', 'lovelace')], // six decimals + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.USDC_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetWalletAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'lovelace') + ) + } + }, + constants.USDC_WHALE_ADDRESS + ) + + await runTest( + 'V6 user smart wallet can trigger repayAndDeposit to deposit all new funds', + UserSmartWalletV6, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + + assert.strictEqual(events[0].address, 'DAI') + assert.strictEqual(events[0].eventName, 'Approval') + + assert.strictEqual(events[1].address, 'CDAI') + assert.strictEqual(events[1].eventName, 'AccrueInterest') + + assert.strictEqual(events[2].address, 'DAI') + assert.strictEqual(events[2].eventName, 'Transfer') + //assert.strictEqual(events[2].returnValues.value, web3.utils.toWei('100', 'ether')) + + assert.strictEqual(events[3].address, 'CDAI') + assert.strictEqual(events[3].eventName, 'Mint') + //assert.strictEqual(events[3].returnValues.mintTokens, web3.utils.toWei('100', 'ether')) + + assert.strictEqual(events[4].address, 'CDAI') + assert.strictEqual(events[4].eventName, 'Transfer') + + assert.strictEqual(events[5].address, 'CUSDC') + assert.strictEqual(events[5].eventName, 'AccrueInterest') + + assert.strictEqual(events[6].address, 'USDC') + assert.strictEqual(events[6].eventName, 'Transfer') + //assert.strictEqual(events[6].returnValues.value, web3.utils.toWei('100', 'lovelace')) + + assert.strictEqual(events[7].address, 'CUSDC') + assert.strictEqual(events[7].eventName, 'Mint') + //assert.strictEqual(events[7].returnValues.mintTokens, web3.utils.toWei('100', 'lovelace')) + + assert.strictEqual(events[8].address, 'CUSDC') + assert.strictEqual(events[8].eventName, 'Transfer') + } + } + ) + + await runTest( + 'Dai Whale can deposit dai into the V6 smart wallet', + DAI, + 'transfer', + 'send', + [targetWalletAddress, web3.utils.toWei('100', 'ether')], + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.DAI_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + targetWalletAddress + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('100', 'ether') + ) + } + }, + constants.DAI_WHALE_ADDRESS + ) + + await runTest( + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, + 'getNextGenericActionID', + 'call', + [ + constants.ESCAPE_HATCH_REGISTRY_ADDRESS, + '0x', + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet cannot call executeAction and target Escape Hatch Registry', + UserSmartWalletV6, + 'executeAction', + 'send', + [ + constants.ESCAPE_HATCH_REGISTRY_ADDRESS, + '0x', + 0, + executeActionUserSignature, + executeActionSignature + ], + false + ) + + await runTest( + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, + 'getNextGenericActionID', + 'call', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet can call executeAction', + UserSmartWalletV6, + 'executeAction', + 'send', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'V6 user smart wallet repayAndDeposit can still deposit without approval', + UserSmartWalletV6, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + + // TODO: verify + } + } + ) + + await runTest( + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, + 'getNextGenericActionID', + 'call', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, constants.FULL_APPROVAL).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet can call executeAction', + UserSmartWalletV6, + 'executeAction', + 'send', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, constants.FULL_APPROVAL).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + + await runTest( + 'V6 user smart wallet repayAndDeposit can deposit with approval added back', + UserSmartWalletV6, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + + // TODO: verify + } + } + ) + + await runTest( + 'V6 user smart wallet can trigger repayAndDeposit even with no funds', + UserSmartWalletV6, + 'repayAndDeposit', + 'send', + [], + true, + receipt => { + //console.log(receipt.status, receipt.gasUsed) + if (testingContext !== 'coverage') { + let events = [] + Object.values(receipt.events).forEach((value) => { + const log = constants.EVENT_DETAILS[value.raw.topics[0]] + const decoded = web3.eth.abi.decodeLog( + log.abi, value.raw.data, value.raw.topics + ) + events.push({ + address: contractNames[value.address], + eventName: log.name, + returnValues: decoded + }) + }) + + assert.strictEqual(events.length, 0) + } + } + ) + + await runTest( + 'V6 UserSmartWallet can get next custom action ID to set a user signing key', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 1, // SetUserSigningKey, + constants.FULL_APPROVAL, // This value shouldn't matter + addressTwo, + 0 + ], + true, + value => { + customActionId = value + } + ) + + await runTest( + 'UserSmartWallet can get the nonce', + UserSmartWalletV6, + 'getNonce', + 'call', + [], + true, + value => { + currentNonce = value + } + ) + + await runTest( + 'V6 UserSmartWallet can get custom action ID and it matches next action ID', + UserSmartWalletV6, + 'getCustomActionID', + 'call', + [ + 1, // SetUserSigningKey, + 0, // Note that this value differs from above + addressTwo, + currentNonce, + 0 + ], + true, + value => { + assert.strictEqual(value, customActionId) + } + ) + + setUserSigningKeyUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + setUserSigningKeyDharmaSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + await runTest( + 'V6 UserSmartWallet can set a new user signing key with signatures', + UserSmartWalletV6, + 'setUserSigningKey', + 'send', + [ + addressTwo, + 0, + setUserSigningKeyUserSignature, + setUserSigningKeyDharmaSignature + ], + true, + receipt => {}, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get next custom action ID to cancel', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 0, // Cancel + constants.FULL_APPROVAL, // This value shouldn't matter + originalAddress, // This value shouldn't matter either + 0 + ], + true, + value => { + customActionId = value + } + ) + + await runTest( + 'UserSmartWallet can get the nonce', + UserSmartWalletV6, + 'getNonce', + 'call', + [], + true, + value => { + currentNonce = value + } + ) + + await runTest( + 'V6 UserSmartWallet can get custom action ID and it matches next action ID', + UserSmartWalletV6, + 'getCustomActionID', + 'call', + [ + 0, // Cancel + 0, // Note that this value differs from above + addressTwo, // This one too + currentNonce, + 0 + ], + true, + value => { + assert.strictEqual(value, customActionId) + } + ) + + cancelUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet secondary can cancel using a signature', + UserSmartWalletV6, + 'cancel', + 'send', + [ + 0, + cancelUserSignature + ], + true, + receipt => {}, + originalAddress + ) + + await runTest( + 'UserSmartWallet nonce is incremented after cancelling', + UserSmartWalletV6, + 'getNonce', + 'call', + [], + true, + value => { + assert.strictEqual(parseInt(value), parseInt(currentNonce) + 1) + } + ) + + await runTest( + 'V6 UserSmartWallet secondary cannot call to withdraw dai without primary', + UserSmartWalletV6, + 'withdrawDai', + 'send', + [ + '1000000000000000000', + address, + 0, + '0x', + '0x' + ], + false + ) + + await runTest( + 'V6 UserSmartWallet secondary cannot call to withdraw usdc without primary', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + 1, + address, + 0, + '0x', + '0x' + ], + false + ) + + await runTest( + 'V6 UserSmartWallet secondary can no longer call to set userSigningKey without primary', + UserSmartWalletV6, + 'setUserSigningKey', + 'send', + [ + address, + 0, + '0x', + '0x' + ], + false + ) + + await runTest( + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + '1', // dust + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot withdraw "dust" USDC', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + '1', + address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + '100000', + constants.NULL_ADDRESS, // bad recipient + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot withdraw USDC to null address', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + '100000', + constants.NULL_ADDRESS, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + '100000', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay can call with two signatures to withdraw USDC', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + '100000', + address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 5, // USDCWithdrawal, + constants.FULL_APPROVAL, + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + usdcWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + usdcUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot call with bad signature to withdraw USDC', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + usdcUserWithdrawalSignature, + '0xffffffff' + usdcWithdrawalSignature.slice(10) + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet cannot call with bad user signature to withdraw USDC', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + '0xffffffff' + usdcUserWithdrawalSignature.slice(10), + usdcWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet relay can call with two signatures to withdraw max USDC', + UserSmartWalletV6, + 'withdrawUSDC', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + usdcUserWithdrawalSignature, + usdcWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + /* TODO: get this working manually + const withdrawalMessage = ( + UserSmartWallet.options.address + // smart wallet address + constants.NULL_BYTES_32.slice(2) + // smart wallet version + address.slice(2) + // user dharma key + address.slice(2) + // dharma key registry key + '5'.padStart(64, '0') + // nonce + constants.NULL_BYTES_32.slice(2) + // minimum gas + '04' + // action type + 'f'.padStart(64, 'f') + // amount + address.slice(2) // recipient + ) + + const saiWithdrawalSignature = signHashedPrefixedHashedHexString( + withdrawalMessage, + address + ) + */ + + await runTest( + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 10, // DaiWithdrawal + '1', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + let daiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + let daiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot withdraw "dust" dai', + UserSmartWalletV6, + 'withdrawDai', + 'send', + [ + '1', + address, + 0, + daiUserWithdrawalSignature, + daiWithdrawalSignature + ], + false, + receipt => {}, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 10, // DaiWithdrawal + '1000000000000000', + constants.NULL_ADDRESS, + 0 + ], + true, + value => { + customActionId = value + } + ) + + daiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + daiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot withdraw dai to null address', + UserSmartWalletV6, + 'withdrawDai', + 'send', + [ + '1000000000000000', + constants.NULL_ADDRESS, + 0, + saiUserWithdrawalSignature, + saiWithdrawalSignature + ], + false, + receipt => {}, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 10, // DaiWithdrawal + '1000000000000000', + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + daiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + daiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay can call with signature to withdraw dai', + UserSmartWalletV6, + 'withdrawDai', + 'send', + [ + '1000000000000000', + address, + 0, + daiUserWithdrawalSignature, + daiWithdrawalSignature + ], + true, + receipt => { + // TODO: verify logs + //console.log(receipt.events) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet cannot get a non-custom "custom" next action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 2, // Generic, + constants.FULL_APPROVAL, + address, + 0 + ], + false + ) + + await runTest( + 'V6 UserSmartWallet cannot get a non-custom "custom" action ID', + UserSmartWalletV6, + 'getCustomActionID', + 'call', + [ + 2, // Generic, + constants.FULL_APPROVAL, + address, + 0, + 0 + ], + false + ) + + await runTest( + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 10, // DaiWithdrawal + constants.FULL_APPROVAL, + address, + 0 + ], + true, + value => { + customActionId = value + } + ) + + daiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + daiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot call with bad signature to withdraw dai', + UserSmartWalletV6, + 'withdrawDai', + 'send', + [ + constants.FULL_APPROVAL, + address, + 0, + daiUserWithdrawalSignature, + '0xffffffff' + daiWithdrawalSignature.slice(10) + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt) + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet relay cannot call with bad user signature to withdraw dai', + UserSmartWalletV6, 'withdrawDai', 'send', [ constants.FULL_APPROVAL, address, 0, - '0xffffffff' + saiUserWithdrawalSignature.slice(10), - saiWithdrawalSignature + '0xffffffff' + daiUserWithdrawalSignature.slice(10), + daiWithdrawalSignature ], false, receipt => { @@ -3711,16 +6548,16 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can call with signature to withdraw sai', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can call with signature to withdraw sai', + UserSmartWalletV6, 'withdrawDai', 'send', [ constants.FULL_APPROVAL, address, 0, - saiUserWithdrawalSignature, - saiWithdrawalSignature + daiUserWithdrawalSignature, + daiWithdrawalSignature ], true, receipt => { @@ -3730,8 +6567,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -3746,19 +6583,19 @@ module.exports = {test: async function (provider, testingContext) { } ) - let ethWithdrawalSignature = signHashedPrefixedHexString( + ethWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - let ethUserWithdrawalSignature = signHashedPrefixedHexString( + ethUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot to withdraw ether with no amount', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot to withdraw ether with no amount', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3776,8 +6613,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -3803,8 +6640,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot to withdraw ether with no recipient', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot to withdraw ether with no recipient', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3822,8 +6659,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -3849,8 +6686,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad signature to withdraw eth', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot call with bad signature to withdraw eth', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3869,8 +6706,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw eth', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3889,8 +6726,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can call with signature to withdraw ether', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can call with signature to withdraw ether', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3908,8 +6745,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -3935,8 +6772,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad signature to withdraw eth', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot call with bad signature to withdraw eth', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3955,8 +6792,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot call with bad user signature to withdraw eth', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3975,8 +6812,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can call with signature to withdraw ether', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can call with signature to withdraw ether', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -3994,8 +6831,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet cancel reverts with bad signature', - UserSmartWalletV5, + 'V6 UserSmartWallet cancel reverts with bad signature', + UserSmartWalletV6, 'cancel', 'send', [ @@ -4008,8 +6845,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet calls revert if insufficient action gas is supplied', - UserSmartWalletV5, + 'V6 UserSmartWallet calls revert if insufficient action gas is supplied', + UserSmartWalletV6, 'cancel', 'send', [ @@ -4020,8 +6857,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet calls succeed if sufficient non-zero action gas supplied', - UserSmartWalletV5, + 'V6 UserSmartWallet calls succeed if sufficient non-zero action gas supplied', + UserSmartWalletV6, 'cancel', 'send', [ @@ -4031,8 +6868,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a cancel custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a cancel custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -4047,11 +6884,11 @@ module.exports = {test: async function (provider, testingContext) { } ) - let cancelSignature = signHashedPrefixedHexString(customActionId, addressTwo) + cancelSignature = signHashedPrefixedHexString(customActionId, addressTwo) await runTest( - 'V5 UserSmartWallet can cancel using a signature', - UserSmartWalletV5, + 'V6 UserSmartWallet can cancel using a signature', + UserSmartWalletV6, 'cancel', 'send', [ @@ -4064,9 +6901,9 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet calls to atomic methods revert', - UserSmartWalletV5, - '_withdrawSaiAtomic', + 'V6 UserSmartWallet calls to atomic methods revert', + UserSmartWalletV6, + '_withdrawDaiAtomic', 'send', [ '1', @@ -4076,8 +6913,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet calls to recover from random address revert', - UserSmartWalletV5, + 'V6 UserSmartWallet calls to recover from random address revert', + UserSmartWalletV6, 'recover', 'send', [ @@ -4087,7 +6924,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'DharmaSmartWalletFactoryV1 can deploy a V5 smart wallet using a Dharma Key', + 'DharmaSmartWalletFactoryV1 can deploy a V6 smart wallet using a Dharma Key', DharmaSmartWalletFactoryV1, 'newSmartWallet', 'send', @@ -4119,8 +6956,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a generic action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, 'getNextGenericActionID', 'call', [ @@ -4145,8 +6982,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet cannot call executeAction and target a non-contract', - UserSmartWalletV5, + 'V6 UserSmartWallet cannot call executeAction and target a non-contract', + UserSmartWalletV6, 'executeAction', 'send', [ @@ -4160,12 +6997,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet cannot call executeAction and target itself', - UserSmartWalletV5, + 'V6 UserSmartWallet cannot call executeAction and target itself', + UserSmartWalletV6, 'executeAction', 'send', [ - UserSmartWalletV5.options.address, + UserSmartWalletV6.options.address, USDC.methods.approve(CUSDC.options.address, 0).encodeABI(), 0, executeActionUserSignature, @@ -4175,8 +7012,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeAction', - UserSmartWalletV5, + 'V6 UserSmartWallet can call executeAction', + UserSmartWalletV6, 'executeAction', 'send', [ @@ -4189,8 +7026,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get the next generic batch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get the next generic batch action ID', + UserSmartWalletV6, 'getNextGenericAtomicBatchActionID', 'call', [ @@ -4205,7 +7042,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'UserSmartWallet can get the nonce', - UserSmartWalletV5, + UserSmartWalletV6, 'getNonce', 'call', [], @@ -4216,8 +7053,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet generic batch action ID with nonce matches next ID', - UserSmartWalletV5, + 'V6 UserSmartWallet generic batch action ID with nonce matches next ID', + UserSmartWalletV6, 'getGenericAtomicBatchActionID', 'call', [ @@ -4242,8 +7079,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeActionWithAtomicBatchCalls', - UserSmartWalletV5, + 'V6 UserSmartWallet can call executeActionWithAtomicBatchCalls', + UserSmartWalletV6, 'executeActionWithAtomicBatchCalls', 'send', [ @@ -4282,7 +7119,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'new user smart wallet can trigger repayAndDeposit to deposit all new funds', - UserSmartWalletV5, + UserSmartWalletV6, 'repayAndDeposit', 'send', [], @@ -4323,42 +7160,6 @@ module.exports = {test: async function (provider, testingContext) { } ) - const FIAT_TOKEN = new web3.eth.Contract( - [ - { - "constant": true, "inputs": [], "name": "blacklister", - "outputs": [{"name": "", "type": "address"}], "payable": false, - "stateMutability": "view", "type": "function" - }, { - "constant": false, "inputs": [{"name": "_account", "type": "address"}], - "name": "unBlacklist", "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" - }, { - "constant": false, "inputs": [{"name": "_account", "type": "address"}], - "name": "blacklist", "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" - }, { - "constant": true, "inputs": [{"name": "_account", "type": "address"}], - "name": "isBlacklisted", "outputs": [{"name": "", "type": "bool"}], - "payable": false, "stateMutability": "view", "type": "function" - }, { - "constant": false, "inputs": [], - "name": "pause", "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" - }, { - "constant": false, "inputs": [], - "name": "unpause", "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" - }, { - "constant": true, "inputs": [], "name": "pauser", - "outputs": [{"name": "", "type": "address"}], "payable": false, - "stateMutability": "view", "type": "function" - } - ], - constants.USDC_MAINNET_ADDRESS - ) - - let blacklister await runTest( 'Check blacklister address', FIAT_TOKEN, @@ -4371,7 +7172,6 @@ module.exports = {test: async function (provider, testingContext) { } ) - let pausear await runTest( 'Check pauser address', FIAT_TOKEN, @@ -4395,7 +7195,6 @@ module.exports = {test: async function (provider, testingContext) { blacklister ) - let targetBlacklistAddress; await runTest( 'DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time', DharmaSmartWalletFactoryV1, @@ -4408,8 +7207,8 @@ module.exports = {test: async function (provider, testingContext) { } ) - const BlacklistedUserSmartWalletV5 = new web3.eth.Contract( - DharmaSmartWalletImplementationV5Artifact.abi, + const BlacklistedUserSmartWalletV6 = new web3.eth.Contract( + DharmaSmartWalletImplementationV6Artifact.abi, targetBlacklistAddress ) @@ -4465,7 +7264,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'blacklisted smart wallet will not approve USDC during repayAndDeposit', - BlacklistedUserSmartWalletV5, + BlacklistedUserSmartWalletV6, 'repayAndDeposit', 'send', [], @@ -4499,8 +7298,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -4526,8 +7325,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet attempt to withdraw max USDC when paused causes ExternalError', - UserSmartWalletV5, + 'V6 UserSmartWallet attempt to withdraw max USDC when paused causes ExternalError', + UserSmartWalletV6, 'withdrawUSDC', 'send', [ @@ -4547,7 +7346,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'smart wallet will not approve USDC when paused during repayAndDeposit', - BlacklistedUserSmartWalletV5, + BlacklistedUserSmartWalletV6, 'repayAndDeposit', 'send', [], @@ -4571,7 +7370,7 @@ module.exports = {test: async function (provider, testingContext) { await runTest( 'unblacklisted, unpaused smart wallet approves USDC during repayAndDeposit', - BlacklistedUserSmartWalletV5, + BlacklistedUserSmartWalletV6, 'repayAndDeposit', 'send', [], @@ -4583,7 +7382,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', + 'V6 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', @@ -4610,7 +7409,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay call to withdraw USDC to blacklisted address', + 'V6 UserSmartWallet relay call to withdraw USDC to blacklisted address', UserSmartWallet, 'withdrawUSDC', 'send', @@ -4631,7 +7430,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', @@ -4658,7 +7457,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay call to withdraw USDC to itself', + 'V6 UserSmartWallet relay call to withdraw USDC to itself', UserSmartWallet, 'withdrawUSDC', 'send', @@ -4677,7 +7476,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', + 'V6 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', @@ -4704,7 +7503,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay call to withdraw USDC to blacklisted address', + 'V6 UserSmartWallet relay call to withdraw USDC to blacklisted address', UserSmartWallet, 'withdrawUSDC', 'send', @@ -4725,8 +7524,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Ether withdrawal custom action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a Ether withdrawal custom action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -4752,8 +7551,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw eth to a non-payable account', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot withdraw eth to a non-payable account', + UserSmartWalletV6, 'withdrawEther', 'send', [ @@ -4771,7 +7570,6 @@ module.exports = {test: async function (provider, testingContext) { originalAddress ) - let targetWalletAddressTwo; await runTest( 'DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time', DharmaSmartWalletFactoryV1, @@ -4786,21 +7584,21 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'DharmaSmartWalletFactoryV1 can deploy a V5 smart wallet using a contract key', + 'DharmaSmartWalletFactoryV1 can deploy a V6 smart wallet using a contract key', DharmaSmartWalletFactoryV1, 'newSmartWallet', 'send', [targetWalletAddress] ) - const UserSmartWalletV5Two = new web3.eth.Contract( - DharmaSmartWalletImplementationV5Artifact.abi, + const UserSmartWalletV6Two = new web3.eth.Contract( + DharmaSmartWalletImplementationV6Artifact.abi, targetWalletAddressTwo ) await runTest( - 'V5 UserSmartWallet cancel reverts with bad contract signature', - UserSmartWalletV5Two, + 'V6 UserSmartWallet cancel reverts with bad contract signature', + UserSmartWalletV6Two, 'cancel', 'send', [ @@ -4813,8 +7611,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a generic action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, 'getNextGenericActionID', 'call', [ @@ -4839,8 +7637,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeAction', - UserSmartWalletV5, + 'V6 UserSmartWallet can call executeAction', + UserSmartWalletV6, 'executeAction', 'send', [ @@ -4853,12 +7651,12 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', [ - 4, // SaiWithdrawal, + 10, // DaiWithdrawal '100000000000000000000000000000000000000', // too much address, 0 @@ -4869,18 +7667,18 @@ module.exports = {test: async function (provider, testingContext) { } ) - saiWithdrawalSignature = signHashedPrefixedHexString( + daiWithdrawalSignature = signHashedPrefixedHexString( customActionId, address ) - saiUserWithdrawalSignature = signHashedPrefixedHexString( + daiUserWithdrawalSignature = signHashedPrefixedHexString( customActionId, addressTwo ) await runTest( - 'V5 UserSmartWallet relay cannot withdraw too much sai', + 'V6 UserSmartWallet relay cannot withdraw too much dai', UserSmartWallet, 'withdrawDai', 'send', @@ -4888,8 +7686,8 @@ module.exports = {test: async function (provider, testingContext) { '100000000000000000000000000000000000000', // too much address, 0, - saiUserWithdrawalSignature, - saiWithdrawalSignature + daiUserWithdrawalSignature, + daiWithdrawalSignature ], true, receipt => { @@ -4900,7 +7698,7 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a USDC withdrawal custom action ID', + 'V6 UserSmartWallet can get a USDC withdrawal custom action ID', UserSmartWallet, 'getNextCustomActionID', 'call', @@ -4926,9 +7724,8 @@ module.exports = {test: async function (provider, testingContext) { addressTwo ) - await runTest( - 'V5 UserSmartWallet relay can call with two signatures to withdraw USDC', + 'V6 UserSmartWallet relay can call with two signatures to withdraw USDC', UserSmartWallet, 'withdrawUSDC', 'send', @@ -4948,14 +7745,14 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get next generic batch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get next generic batch action ID', + UserSmartWalletV6, 'getNextGenericAtomicBatchActionID', 'call', [ [{ - to: SAI.options.address, - data: SAI.methods.transfer( + to: DAI.options.address, + data: DAI.methods.transfer( address, '100000000000000000000000000000' ).encodeABI() }], @@ -4978,14 +7775,14 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure', - UserSmartWalletV5, + 'V6 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure', + UserSmartWalletV6, 'executeActionWithAtomicBatchCalls', 'send', [ [{ - to: SAI.options.address, - data: SAI.methods.transfer( + to: DAI.options.address, + data: DAI.methods.transfer( address, '100000000000000000000000000000' ).encodeABI() }], @@ -5000,14 +7797,14 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get a generic action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, 'getNextGenericActionID', 'call', [ Comptroller.options.address, Comptroller.methods.enterMarkets( - [constants.CSAI_MAINNET_ADDRESS] + [constants.CDAI_MAINNET_ADDRESS] ).encodeABI(), 0 ], @@ -5028,14 +7825,14 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeAction to enter sai market', - UserSmartWalletV5, + 'V6 UserSmartWallet can call executeAction to enter dai market', + UserSmartWalletV6, 'executeAction', 'send', [ Comptroller.options.address, Comptroller.methods.enterMarkets( - [constants.CSAI_MAINNET_ADDRESS] + [constants.CDAI_MAINNET_ADDRESS] ).encodeABI(), 0, executeActionUserSignature, @@ -5044,8 +7841,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'Sai Whale can deposit sai into the smart wallet', - SAI, + 'Dai Whale can deposit dai into the smart wallet', + DAI, 'transfer', 'send', [targetWalletAddress, web3.utils.toWei('100', 'ether')], @@ -5054,7 +7851,7 @@ module.exports = {test: async function (provider, testingContext) { if (testingContext !== 'coverage') { assert.strictEqual( receipt.events.Transfer.returnValues.from, - constants.SAI_WHALE_ADDRESS + constants.DAI_WHALE_ADDRESS ) assert.strictEqual( receipt.events.Transfer.returnValues.to, @@ -5066,18 +7863,18 @@ module.exports = {test: async function (provider, testingContext) { ) } }, - constants.SAI_WHALE_ADDRESS + constants.DAI_WHALE_ADDRESS ) await runTest( - 'V5 UserSmartWallet can trigger repayAndDeposit to deposit all new funds', - UserSmartWalletV5, + 'V6 UserSmartWallet can trigger repayAndDeposit to deposit all new funds', + UserSmartWalletV6, 'repayAndDeposit' ) await runTest( - 'V5 UserSmartWallet can get a generic action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, 'getNextGenericActionID', 'call', [ @@ -5102,8 +7899,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can call executeAction to perform a borrow', - UserSmartWalletV5, + 'V6 UserSmartWallet can call executeAction to perform a borrow', + UserSmartWalletV6, 'executeAction', 'send', [ @@ -5120,56 +7917,12 @@ module.exports = {test: async function (provider, testingContext) { originalAddress ) - await runTest( - 'V5 UserSmartWallet can get a Sai withdrawal custom action ID', - UserSmartWalletV5, - 'getNextCustomActionID', - 'call', - [ - 4, // SaiWithdrawal, - constants.FULL_APPROVAL, - address, - 0 - ], - true, - value => { - customActionId = value - } - ) - - saiWithdrawalSignature = signHashedPrefixedHexString( - customActionId, - address - ) - saiUserWithdrawalSignature = signHashedPrefixedHexString( - customActionId, - addressTwo - ) - await runTest( - 'V5 UserSmartWallet relay cannot withdraw max sai with an outstanding borrow', - UserSmartWalletV5, - 'withdrawDai', - 'send', - [ - constants.FULL_APPROVAL, - address, - 0, - saiUserWithdrawalSignature, - saiWithdrawalSignature - ], - true, - receipt => { - // TODO: verify logs - //console.log(receipt.events) - }, - originalAddress - ) await runTest( - 'V5 UserSmartWallet can get an escape hatch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get an escape hatch action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -5195,8 +7948,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot set an escape hatch with no account', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot set an escape hatch with no account', + UserSmartWalletV6, 'setEscapeHatch', 'send', [ @@ -5213,8 +7966,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get an escape hatch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get an escape hatch action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -5240,8 +7993,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet cannot call escape before escape hatch is set', - UserSmartWalletV5, + 'V6 UserSmartWallet cannot call escape before escape hatch is set', + UserSmartWalletV6, 'escape', 'send', [], @@ -5252,8 +8005,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can set an escape hatch', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can set an escape hatch', + UserSmartWalletV6, 'setEscapeHatch', 'send', [ @@ -5270,8 +8023,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet non-escape hatch account cannot call escape', - UserSmartWalletV5, + 'V6 UserSmartWallet non-escape hatch account cannot call escape', + UserSmartWalletV6, 'escape', 'send', [], @@ -5283,8 +8036,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet escape hatch account can call escape', - UserSmartWalletV5, + 'V6 UserSmartWallet escape hatch account can call escape', + UserSmartWalletV6, 'escape', 'send', [], @@ -5296,8 +8049,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet escape hatch account can call escape again', - UserSmartWalletV5, + 'V6 UserSmartWallet escape hatch account can call escape again', + UserSmartWalletV6, 'escape', 'send', [], @@ -5309,8 +8062,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get an escape hatch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get an escape hatch action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -5336,8 +8089,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can remove an escape hatch', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can remove an escape hatch', + UserSmartWalletV6, 'removeEscapeHatch', 'send', [ @@ -5353,8 +8106,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet cannot call escape once escape hatch is removed', - UserSmartWalletV5, + 'V6 UserSmartWallet cannot call escape once escape hatch is removed', + UserSmartWalletV6, 'escape', 'send', [], @@ -5365,8 +8118,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get an escape hatch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get an escape hatch action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -5392,8 +8145,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay can disable the escape hatch', - UserSmartWalletV5, + 'V6 UserSmartWallet relay can disable the escape hatch', + UserSmartWalletV6, 'permanentlyDisableEscapeHatch', 'send', [ @@ -5409,8 +8162,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet can get an escape hatch action ID', - UserSmartWalletV5, + 'V6 UserSmartWallet can get an escape hatch action ID', + UserSmartWalletV6, 'getNextCustomActionID', 'call', [ @@ -5436,8 +8189,8 @@ module.exports = {test: async function (provider, testingContext) { ) await runTest( - 'V5 UserSmartWallet relay cannot set an escape hatch once disabled', - UserSmartWalletV5, + 'V6 UserSmartWallet relay cannot set an escape hatch once disabled', + UserSmartWalletV6, 'setEscapeHatch', 'send', [ @@ -5453,6 +8206,32 @@ module.exports = {test: async function (provider, testingContext) { originalAddress ) + await runTest( + 'V6 UserSmartWallet relay can trigger sai to dai migration', + UserSmartWalletV6, + 'migrateSaiToDai', + 'send', + [], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet relay can trigger cSai to cDai migration', + UserSmartWalletV6, + 'migrateCSaiToCDai', + 'send', + [], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + // Initiate account recovery await runTest( 'smart wallet account recovery can be initiated', @@ -5460,7 +8239,7 @@ module.exports = {test: async function (provider, testingContext) { 'initiateAccountRecovery', 'send', [ - UserSmartWalletV5.options.address, + UserSmartWalletV6.options.address, originalAddress, 0 // extraTime in seconds ], @@ -5477,7 +8256,7 @@ module.exports = {test: async function (provider, testingContext) { 'recover', 'send', [ - UserSmartWalletV5.options.address, + UserSmartWalletV6.options.address, originalAddress ], false @@ -5493,7 +8272,7 @@ module.exports = {test: async function (provider, testingContext) { 'recover', 'send', [ - UserSmartWalletV5.options.address, + UserSmartWalletV6.options.address, originalAddress ], true, @@ -5618,7 +8397,6 @@ module.exports = {test: async function (provider, testingContext) { false ) - let nextKeyRing; await runTest( `DharmaKeyRingFactoryV1 can get the address of the next key ring`, DharmaKeyRingFactoryV1, @@ -5708,7 +8486,6 @@ module.exports = {test: async function (provider, testingContext) { false ) - let adminActionID await runTest( `KeyRingInstance can get an adminActionID using getNextAdminActionID`, KeyRingInstance, @@ -5966,7 +8743,7 @@ module.exports = {test: async function (provider, testingContext) { ) const UpgradeBeaconProxyV1Implementation = new web3.eth.Contract( - DharmaSmartWalletImplementationV5Artifact.abi, + DharmaSmartWalletImplementationV6Artifact.abi, UpgradeBeaconProxyV1.options.address ) @@ -6584,7 +9361,7 @@ module.exports = {test: async function (provider, testingContext) { DharmaAccountRecoveryManagerV2Coverage, 'initiateAccountRecovery', 'send', - [UserSmartWalletV5.options.address, addressTwo, 0] + [UserSmartWalletV6.options.address, addressTwo, 0] ) await runTest( @@ -6758,7 +9535,7 @@ module.exports = {test: async function (provider, testingContext) { DharmaAccountRecoveryManagerV2Coverage, 'recover', 'send', - [UserSmartWalletV5.options.address, addressTwo], + [UserSmartWalletV6.options.address, addressTwo], false ) @@ -7782,7 +10559,7 @@ module.exports = {test: async function (provider, testingContext) { 'exitAdharmaContingency', 'send', [ - DharmaSmartWalletImplementationV5.options.address, + DharmaSmartWalletImplementationV6.options.address, DharmaKeyRingImplementationV1.options.address ], false @@ -7815,7 +10592,7 @@ module.exports = {test: async function (provider, testingContext) { 'exitAdharmaContingency', 'send', [ - DharmaSmartWalletImplementationV5.options.address, + DharmaSmartWalletImplementationV6.options.address, DharmaKeyRingImplementationV1.options.address ] ) @@ -8232,7 +11009,7 @@ module.exports = {test: async function (provider, testingContext) { const UserSmartWalletAdharma = new web3.eth.Contract( AdharmaSmartWalletImplementationArtifact.abi, - UserSmartWalletV5.options.address + UserSmartWalletV6.options.address ) await runTest( @@ -8409,17 +11186,8 @@ module.exports = {test: async function (provider, testingContext) { [[ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]] ) - let rawData = '0x' - let executorGasLimit = 100000000000 - let hashInputs - let hash - let ownerOneSig - let ownerTwoSig - let ownerThreeSig - let ownerSigs - let ownerSigsOutOfOrder - let unownedSig - let unownedSigs + rawData = '0x' + executorGasLimit = 100000000000 const bizarreSigs = ( '0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0' + @@ -9230,7 +11998,7 @@ module.exports = {test: async function (provider, testingContext) { } ) - let fallbackEscapeHatch = await web3.eth.call({ + fallbackEscapeHatch = await web3.eth.call({ to: DharmaEscapeHatchRegistry.options.address, from: address, data: "0x" @@ -10030,7 +12798,7 @@ module.exports = {test: async function (provider, testingContext) { 'exitAdharmaContingency', 'send', [ - DharmaSmartWalletImplementationV5.options.address, + DharmaSmartWalletImplementationV6.options.address, DharmaKeyRingImplementationV1.options.address ] ) From 5f51c40021618426a4474df5df27813b81fab557 Mon Sep 17 00:00:00 2001 From: 0age <0age@protonmail.com> Date: Wed, 8 Jan 2020 10:26:52 -0500 Subject: [PATCH 4/5] add mock dai migrator and test against DSWv6 --- .solcover.js | 1 + .../DharmaSmartWalletImplementationV6.sol | 4 +- contracts/mock/MockSaiToDaiMigrator.sol | 19 ++++ ...ator.sol => SaiToDaiMigratorInterface.sol} | 2 +- package.json | 12 +- scripts/test/constants.js | 1 + scripts/test/deployMockExternal.js | 91 ++++++++++++--- scripts/test/test.js | 105 ++++++++++++++++++ 8 files changed, 212 insertions(+), 23 deletions(-) create mode 100644 contracts/mock/MockSaiToDaiMigrator.sol rename interfaces/{SaiToDaiMigrator.sol => SaiToDaiMigratorInterface.sol} (67%) diff --git a/.solcover.js b/.solcover.js index 15d2216..5169391 100644 --- a/.solcover.js +++ b/.solcover.js @@ -28,6 +28,7 @@ module.exports = { 'implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol', //'implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol', 'implementations/smart-wallet/DharmaSmartWalletImplementationVX.sol', + 'mock/MockSaiToDaiMigrator.sol', 'mock/MockCodeCheck.sol', 'mock/RelayContract.sol', 'mock/RelayContractV2.sol', diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol index 0692d8b..2ae4dd8 100644 --- a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol +++ b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol @@ -16,7 +16,7 @@ import "../../../interfaces/USDCV1Interface.sol"; import "../../../interfaces/DharmaKeyRegistryInterface.sol"; import "../../../interfaces/DharmaEscapeHatchRegistryInterface.sol"; import "../../../interfaces/ERC1271.sol"; -import "../../../interfaces/SaiToDaiMigrator.sol"; +import "../../../interfaces/SaiToDaiMigratorInterface.sol"; /** @@ -109,7 +109,7 @@ contract DharmaSmartWalletImplementationV6 is 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet ); - SaiToDaiMigrator _MIGRATOR = SaiToDaiMigrator( + SaiToDaiMigratorInterface internal constant _MIGRATOR = SaiToDaiMigratorInterface( 0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849 // mainnet ); diff --git a/contracts/mock/MockSaiToDaiMigrator.sol b/contracts/mock/MockSaiToDaiMigrator.sol new file mode 100644 index 0000000..2846db6 --- /dev/null +++ b/contracts/mock/MockSaiToDaiMigrator.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../../interfaces/SaiToDaiMigratorInterface.sol"; + + +/** + * @title MockSaiToDaiMigrator + * @notice This contract swaps Sai for Dai - be sure to give it the Dai first. + */ +contract MockSaiToDaiMigrator is SaiToDaiMigratorInterface { + IERC20 private constant _SAI = IERC20(0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359); + IERC20 private constant _DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); + + function swapSaiToDai(uint256 balance) external { + _SAI.transferFrom(msg.sender, address(this), balance); + _DAI.transfer(msg.sender, balance); + } +} \ No newline at end of file diff --git a/interfaces/SaiToDaiMigrator.sol b/interfaces/SaiToDaiMigratorInterface.sol similarity index 67% rename from interfaces/SaiToDaiMigrator.sol rename to interfaces/SaiToDaiMigratorInterface.sol index a04a423..4990a7f 100644 --- a/interfaces/SaiToDaiMigrator.sol +++ b/interfaces/SaiToDaiMigratorInterface.sol @@ -1,6 +1,6 @@ pragma solidity 0.5.11; -interface SaiToDaiMigrator { +interface SaiToDaiMigratorInterface { function swapSaiToDai(uint256 balance) external; } \ No newline at end of file diff --git a/package.json b/package.json index 0518b5b..d624dcf 100644 --- a/package.json +++ b/package.json @@ -17,15 +17,15 @@ "web3": "1.2.1" }, "scripts": { - "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", + "all": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xddb108893104de4e1c6d0e47c42237db4e617acc -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "build": "./node_modules/.bin/truffle compile", "ci": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -q & echo 'local chain started.' && ./node_modules/.bin/truffle compile && node scripts/test/ci.js && ./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", - "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "coverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xddb108893104de4e1c6d0e47c42237db4e617acc -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-coverage-output.log & echo 'coverage chain started.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", + "forkCoverage": "./node_modules/.bin/ganache-cli-coverage --emitFreeLogs true --allowUnlimitedContractSize true --gasLimit 0xfffffffffff --port 8555 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xddb108893104de4e1c6d0e47c42237db4e617acc -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-coverage-output.log & echo 'fork coverage chain started on port 8555.' && node --max-old-space-size=8192 ./node_modules/.bin/solidity-coverage; kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'coverage chain stopped.'", "lint": "./node_modules/.bin/solhint 'contracts/**/*.sol' && ./node_modules/.bin/solium -d .", - "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", - "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", + "start": "./node_modules/.bin/ganache-cli --gasLimit 8000000 -i 1234 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0xddb108893104de4e1c6d0e47c42237db4e617acc -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' 2>&1 > ganache-output.log & echo 'local chain started.'", + "forkStart": "./node_modules/.bin/ganache-cli --port 8545 --gasLimit 8000000 --fork https://mainnet.infura.io/v3/e7faf3dd07254d76859ec8c7c3259d9d@8396520 -e 10000 -u 0xb5b06a16621616875A6C2637948bF98eA57c58fa -u 0x8134d518e0CeF5388136c0De43d7E12278701Ac5 -u 0xddb108893104de4e1c6d0e47c42237db4e617acc -u 0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9 -u 0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911 -u 0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6 -u '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' -u '0x76B03EB651153a81fA1f212f2f59329B4180A46F' -u '0x035e742A7E62253C606b9028eeB65178B44F1e7E' -u '0x5dB0115f3B72d19cEa34dD697cf412Ff86dc7E1b' -u '0xf0d160DEC1749aFaF5A831668093B1431f7C8527' 2>&1 > ganache-output.log & echo 'fork chain started on port 8545.'", "stop": "kill -9 \"$(ps -ax | grep -m1 '[n]ode ./node_modules/.bin/ganache-cli' | awk '{print $1;}')\" && echo 'local chain stopped.'", "test": "./node_modules/.bin/truffle compile && node scripts/test/ci.js" } -} +} \ No newline at end of file diff --git a/scripts/test/constants.js b/scripts/test/constants.js index 318ffa7..03d8364 100644 --- a/scripts/test/constants.js +++ b/scripts/test/constants.js @@ -107,6 +107,7 @@ module.exports = Object.freeze({ CDAI_MAINNET_ADDRESS: '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', CUSDC_MAINNET_ADDRESS: '0x39AA39c021dfbaE8faC545936693aC917d5E7563', CETH_MAINNET_ADDRESS: '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5', + DAI_MIGRATOR_MAINNET_ADDRESS: '0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849', MOCK_USDC_BLACKLISTED_ADDRESS: '0x6000000000000000000000000000000000000006', COMPTROLLER_MAINNET_ADDRESS: ( '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B' diff --git a/scripts/test/deployMockExternal.js b/scripts/test/deployMockExternal.js index 8d7ab64..ed02cba 100644 --- a/scripts/test/deployMockExternal.js +++ b/scripts/test/deployMockExternal.js @@ -4,6 +4,7 @@ var util = require('ethereumjs-util') const constants = require('./constants.js') const IERC20Artifact = require('../../build/contracts/IERC20.json') +const MockSaiToDaiMigratorArtifact = require('../../build/contracts/MockSaiToDaiMigrator.json') module.exports = {test: async function (provider, testingContext) { var web3 = provider @@ -36,6 +37,10 @@ module.exports = {test: async function (provider, testingContext) { IERC20Artifact.abi, constants.CUSDC_MAINNET_ADDRESS ) + const MockSaiToDaiMigrator = new web3.eth.Contract( + MockSaiToDaiMigratorArtifact.abi, constants.DAI_MIGRATOR_MAINNET_ADDRESS + ) + const UNITROLLER = new web3.eth.Contract( [ { @@ -4630,24 +4635,20 @@ module.exports = {test: async function (provider, testingContext) { await web3.eth.sendTransaction({ from: originalAddress, to: '0xb5b06a16621616875A6C2637948bF98eA57c58fa', - value: web3.utils.toWei('1', 'ether'), + value: web3.utils.toWei('0.1', 'ether'), gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1, gasPrice: 1 }) - console.log('deploying mock price oracle contract...') - const priceOracleDeployReceipt = await web3.eth.sendTransaction({ - from: address, - gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, - gasPrice: 1, - data: mockPriceOracleDeploymentData + console.log('funding Dai migrator deployer address...') + await web3.eth.sendTransaction({ + from: originalAddress, + to: '0xddb108893104de4e1c6d0e47c42237db4e617acc', + value: web3.utils.toWei('0.8', 'ether'), + gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1, + gasPrice: 1 }) - assert.strictEqual( - priceOracleDeployReceipt.contractAddress, - '0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14' - ) - console.log('funding dai deployer address...') await web3.eth.sendTransaction({ from: originalAddress, @@ -4675,6 +4676,19 @@ module.exports = {test: async function (provider, testingContext) { gasPrice: 1 }) + console.log('deploying mock price oracle contract...') + const priceOracleDeployReceipt = await web3.eth.sendTransaction({ + from: address, + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: mockPriceOracleDeploymentData + }) + + assert.strictEqual( + priceOracleDeployReceipt.contractAddress, + '0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14' + ) + console.log('incrementing dai deployment nonce...') let daiDeployReceipt for (i = 0; i < 1; i++) { @@ -4698,7 +4712,7 @@ module.exports = {test: async function (provider, testingContext) { daiDeployReceipt.contractAddress, constants.DAI_MAINNET_ADDRESS ) - console.log('incrementing sai deployment nonce...') + console.log('incrementing Sai deployment nonce...') let saiDeployReceipt for (i = 0; i < 4; i++) { saiDeployReceipt = await web3.eth.sendTransaction({ @@ -4721,6 +4735,33 @@ module.exports = {test: async function (provider, testingContext) { saiDeployReceipt.contractAddress, constants.SAI_MAINNET_ADDRESS ) + console.log( + 'incrementing Dai migrator deployment nonce (this takes ~30 seconds)...' + ) + let daiMigratorDeployReceipt + for (i = 0; i < 1250; i++) { + daiMigratorDeployReceipt = await web3.eth.sendTransaction({ + from: '0xddb108893104de4e1c6d0e47c42237db4e617acc', + to: '0xddb108893104de4e1c6d0e47c42237db4e617acc', + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: '0x' + }).catch(console.error) + } + + console.log('deploying mock Dai migrator...') + daiMigratorDeployReceipt = await web3.eth.sendTransaction({ + from: '0xddb108893104de4e1c6d0e47c42237db4e617acc', + gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1, + gasPrice: 1, + data: MockSaiToDaiMigratorArtifact.bytecode + }) + + assert.strictEqual( + daiMigratorDeployReceipt.contractAddress, + constants.DAI_MIGRATOR_MAINNET_ADDRESS + ) + await runTest( 'Transfer Dai to whale address', DAI, @@ -4735,6 +4776,20 @@ module.exports = {test: async function (provider, testingContext) { '0xb5b06a16621616875A6C2637948bF98eA57c58fa' ) + await runTest( + 'Transfer Dai to migrator address', + DAI, + 'transfer', + 'send', + [ + constants.DAI_MIGRATOR_MAINNET_ADDRESS, + '1000000000000000000000000000000000000000000000000000000000000000000000000000' + ], + true, + receipt => {}, + '0xb5b06a16621616875A6C2637948bF98eA57c58fa' + ) + await runTest( 'Transfer Sai to whale address', SAI, @@ -4756,7 +4811,7 @@ module.exports = {test: async function (provider, testingContext) { 'send', [ address, - '100000000000000000000000000000000000000000000000000000000000000000000000000000' + '1000000000000000000000000000000000000000000000000000000000000000000000000000' ], true, receipt => {}, @@ -5182,6 +5237,14 @@ module.exports = {test: async function (provider, testingContext) { ] ) + await runTest( + 'Call MockSaiToDaiMigrator', + MockSaiToDaiMigrator, + 'swapSaiToDai', + 'send', + [0] + ) + // TODO: list increase cDAI and cUSDC collateral factor on comptroller // TODO: set prices using price oracle diff --git a/scripts/test/test.js b/scripts/test/test.js index 8401bf3..262f4e5 100644 --- a/scripts/test/test.js +++ b/scripts/test/test.js @@ -5103,6 +5103,51 @@ module.exports = {test: async function (provider, testingContext) { 'repayAndDeposit' ) + await runTest( + 'V5 UserSmartWallet can get a generic action ID', + UserSmartWalletV5, + 'getNextGenericActionID', + 'call', + [ + CSAI.options.address, + CSAI.methods.transfer(address, web3.utils.toWei('1', 'mwei')).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V5 UserSmartWallet can call executeAction to transfer cSai', + UserSmartWalletV5, + 'executeAction', + 'send', + [ + CSAI.options.address, + CSAI.methods.transfer(address, web3.utils.toWei('1', 'mwei')).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ], + true, + receipt => { + //console.log(receipt.events) + }, + originalAddress + ) + await runTest( 'V5 UserSmartWallet can get a generic action ID', UserSmartWalletV5, @@ -8206,6 +8251,66 @@ module.exports = {test: async function (provider, testingContext) { originalAddress ) + await runTest( + 'V6 UserSmartWallet relay can trigger sai to dai migration as a no-op', + UserSmartWalletV6, + 'migrateSaiToDai', + 'send', + [], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'V6 UserSmartWallet relay can trigger cSai to cDai migration as a no-op', + UserSmartWalletV6, + 'migrateCSaiToCDai', + 'send', + [], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + + await runTest( + 'cSai can be sent to V6 UserSmartWallet', + CSAI, + 'transfer', + 'send', + [UserSmartWalletV6.options.address, web3.utils.toWei('1', 'mwei')] + ) + + await runTest( + 'Sai Whale can deposit sai into the V6 user smart wallet', + SAI, + 'transfer', + 'send', + [UserSmartWalletV6.options.address, web3.utils.toWei('1', 'ether')], + true, + receipt => { + if (testingContext !== 'coverage') { + assert.strictEqual( + receipt.events.Transfer.returnValues.from, + constants.SAI_WHALE_ADDRESS + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.to, + UserSmartWalletV6.options.address + ) + assert.strictEqual( + receipt.events.Transfer.returnValues.value, + web3.utils.toWei('1', 'ether') + ) + } + }, + constants.SAI_WHALE_ADDRESS + ) + await runTest( 'V6 UserSmartWallet relay can trigger sai to dai migration', UserSmartWalletV6, From 36d88337b00f8b153536550ecb41af2a9dbc3231 Mon Sep 17 00:00:00 2001 From: 0age <0age@protonmail.com> Date: Wed, 8 Jan 2020 13:32:36 -0500 Subject: [PATCH 5/5] improve DSWv6 test coverage --- scripts/test/test.js | 153 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/scripts/test/test.js b/scripts/test/test.js index 262f4e5..c4ea878 100644 --- a/scripts/test/test.js +++ b/scripts/test/test.js @@ -5490,6 +5490,27 @@ module.exports = {test: async function (provider, testingContext) { } ) + await runTest( + 'cSai can be sent to V6 UserSmartWallet', + CSAI, + 'transfer', + 'send', + [UserSmartWalletV6.options.address, web3.utils.toWei('0.5', 'mwei')] + ) + + await runTest( + 'V6 UserSmartWallet relay can trigger cSai to cDai migration before cDai approval', + UserSmartWalletV6, + 'migrateCSaiToCDai', + 'send', + [], + true, + receipt => { + // TODO: verify logs + }, + originalAddress + ) + await runTest( 'V6 UserSmartWallet can get next custom action ID', UserSmartWalletV6, @@ -5631,6 +5652,46 @@ module.exports = {test: async function (provider, testingContext) { constants.USDC_WHALE_ADDRESS ) + await runTest( + 'V6 UserSmartWallet can get a generic action ID', + UserSmartWalletV6, + 'getNextGenericActionID', + 'call', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + 0 + ], + true, + value => { + customActionId = value + } + ) + + executeActionSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + executeActionUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet can call executeAction', + UserSmartWalletV6, + 'executeAction', + 'send', + [ + DAI.options.address, + DAI.methods.approve(CDAI.options.address, 0).encodeABI(), + 0, + executeActionUserSignature, + executeActionSignature + ] + ) + await runTest( 'V6 user smart wallet can trigger repayAndDeposit to deposit all new funds', UserSmartWalletV6, @@ -5919,6 +5980,49 @@ module.exports = {test: async function (provider, testingContext) { } ) + await runTest( + 'V6 UserSmartWallet can get custom action ID and it matches next action ID', + UserSmartWalletV6, + 'getNextCustomActionID', + 'call', + [ + 1, // SetUserSigningKey, + 0, + constants.NULL_ADDRESS, + 0 + ], + true, + value => { + customActionId = value + } + ) + + setUserSigningKeyUserSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + setUserSigningKeyDharmaSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + await runTest( + 'V6 UserSmartWallet cannot set the null address as a new user signing key', + UserSmartWalletV6, + 'setUserSigningKey', + 'send', + [ + constants.NULL_ADDRESS, + 0, + setUserSigningKeyUserSignature, + setUserSigningKeyDharmaSignature + ], + false, + receipt => {}, + originalAddress + ) + await runTest( 'V6 UserSmartWallet can get next custom action ID to set a user signing key', UserSmartWalletV6, @@ -7695,6 +7799,53 @@ module.exports = {test: async function (provider, testingContext) { ] ) + await runTest( + 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', + UserSmartWallet, + 'getNextCustomActionID', + 'call', + [ + 10, // DaiWithdrawal + '1000000000000000000', + constants.NULL_ADDRESS, + 0 + ], + true, + value => { + customActionId = value + } + ) + + daiWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + address + ) + + daiUserWithdrawalSignature = signHashedPrefixedHexString( + customActionId, + addressTwo + ) + + await runTest( + 'V6 UserSmartWallet relay cannot withdraw to the null address', + UserSmartWallet, + 'withdrawDai', + 'send', + [ + '1000000000000000000', + constants.NULL_ADDRESS, + 0, + daiUserWithdrawalSignature, + daiWithdrawalSignature + ], + false, + receipt => { + // TODO: verify logs + //console.log(receipt.events) + }, + originalAddress + ) + await runTest( 'V6 UserSmartWallet can get a Dai withdrawal custom action ID', UserSmartWallet, @@ -8282,7 +8433,7 @@ module.exports = {test: async function (provider, testingContext) { CSAI, 'transfer', 'send', - [UserSmartWalletV6.options.address, web3.utils.toWei('1', 'mwei')] + [UserSmartWalletV6.options.address, web3.utils.toWei('0.5', 'mwei')] ) await runTest(