diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..7007c8a
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "tabWidth": 4,
+ "semi": true,
+ "singleQuote": false
+}
diff --git a/.solcover.js b/.solcover.js
index 5169391..dbe79aa 100644
--- a/.solcover.js
+++ b/.solcover.js
@@ -1,11 +1,10 @@
module.exports = {
norpc: true,
testCommand: 'node --max-old-space-size=4096 ./scripts/test/testCoverage.js',
- compileCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle compile',
+ compileCommand: 'node --max-old-space-size=8192 ../node_modules/.bin/truffle compile',
copyPackages: ['web3'],
skipFiles: [
'account-recovery/DharmaAccountRecoveryManager.sol',
- //'account-recovery/DharmaAccountRecoveryManagerV2.sol',
'factories/key-ring/DharmaKeyRingFactoryV3.sol',
'factories/smart-wallet/DharmaSmartWalletFactoryV2.sol',
'helpers/CodeHashCache.sol',
@@ -13,28 +12,30 @@ module.exports = {
'helpers/FactoryFactFinder.sol',
'helpers/ImmutableCreate2Factory.sol',
'helpers/IndestructibleRegistry.sol',
+ 'helpers/SmartWalletRevertReasonHelperV1.sol',
'helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol',
- //'helpers/Timelocker.sol',
- //'helpers/TimelockerV2.sol',
- //'implementations/key-ring/AdharmaKeyRingImplementation.sol',
'implementations/key-ring/DharmaKeyRingImplementationV0.sol',
'implementations/key-ring/DharmaKeyRingImplementationV2.sol',
- //'implementations/smart-wallet/AdharmaSmartWalletImplementation.sol',
'implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol',
'implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol',
'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/DharmaSmartWalletImplementationV6.sol',
+ //'implementations/smart-wallet/DharmaSmartWalletImplementationV7.sol'
'implementations/smart-wallet/DharmaSmartWalletImplementationVX.sol',
+ 'implementations/token/MockDharmaDaiImplementationV1.sol',
+ 'implementations/token/DharmaDaiInitializer.sol',
+ 'implementations/token/DharmaTokenHelpers.sol',
+ 'implementations/token/DharmaTokenOverrides.sol',
+ 'implementations/token/DharmaTokenV1.sol',
+ 'implementations/token/DharmaUSDCImplementationV1.sol',
+ 'implementations/token/DharmaUSDCInitializer.sol',
'mock/MockSaiToDaiMigrator.sol',
'mock/MockCodeCheck.sol',
'mock/RelayContract.sol',
'mock/RelayContractV2.sol',
- //'multisigs/DharmaUpgradeMultisig.sol',
- //'multisigs/DharmaKeyRegistryMultisig.sol',
- //'multisigs/DharmaAccountRecoveryOperatorMultisig.sol',
'openzeppelin-upgradeability/cryptography/ECDSA.sol',
'openzeppelin-upgradeability/ownership/Ownable.sol',
'openzeppelin-upgradeability/upgradeability/AdminUpgradeabilityProxy.sol',
@@ -44,14 +45,19 @@ module.exports = {
'openzeppelin-upgradeability/upgradeability/ProxyAdmin.sol',
'openzeppelin-upgradeability/upgradeability/UpgradeabilityProxy.sol',
'openzeppelin-upgradeability/utils/Address.sol',
+ 'proxies/token/DharmaDai.sol',
+ 'proxies/token/DharmaUSDC.sol',
'registries/DharmaKeyRegistryV1.sol',
'test/BadBeacon.sol',
'test/BadBeaconTwo.sol',
+ 'test/BalanceChecker.sol',
'test/MockDharmaKeyRingFactory.sol',
'test/DharmaTestingMultisig.sol',
'test/MockAdharmaKeyRingFactory.sol',
'test/TimelockEdgecaseTester.sol',
'test/TimelockTwoStepOwnableTestContract.sol',
- 'test/UpgradeBeaconImplementationCheck.sol'
+ 'test/UpgradeBeaconImplementationCheck.sol',
+ 'upgradeability/token/DharmaDaiUpgradeBeacon.sol',
+ 'upgradeability/token/DharmaUSDCUpgradeBeacon.sol'
]
}
\ No newline at end of file
diff --git a/.soliumignore b/.soliumignore
index 7c2eeab..6ff98f4 100644
--- a/.soliumignore
+++ b/.soliumignore
@@ -5,10 +5,10 @@ contracts/mock/RelayContractV2.sol
interfaces/RelayContractInterface.sol
# disagree with indentation error
-contracts/helpers/FactoryFactFinder.sol
-contracts/helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol
+extra-contracts/helpers/FactoryFactFinder.sol
contracts/upgradeability/DharmaUpgradeBeaconController.sol
contracts/implementations/smart-wallet/AdharmaSmartWalletImplementation.sol
+contracts/implementations/token/DharmaTokenOverrides.sol
# parsing error due to dynamic abi.decode - try again in later version
contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol
@@ -18,8 +18,11 @@ contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV3.sol
contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV4.sol
contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol
contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol
+contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV7.sol
contracts/implementations/smart-wallet/DharmaSmartWalletImplementationVX.sol
+contracts/implementations/token/MockDharmaDaiImplementationV1.sol
+
extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol
extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol
extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol
diff --git a/README.md b/README.md
index 10f50a7..6860331 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
> 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.
-[![Smart Wallet Version](https://img.shields.io/endpoint?url=https%3A%2F%2Fdharma-version-api.netlify.com%2F.netlify%2Ffunctions%2Fserver%3Ftarget%3Dsmartwallet)](https://etherscan.io/address/0x00000000001f2bec34d4a98c839cf711afc842c6#code)
+[![Smart Wallet Version](https://img.shields.io/endpoint?url=https%3A%2F%2Fdharma-version-api.netlify.com%2F.netlify%2Ffunctions%2Fserver%3Ftarget%3Dsmartwallet)](https://etherscan.io/address/0x0000000000ab32e9e7bd6bd3c37a7e99fb8c2d43#code)
[![Key Ring Version](https://img.shields.io/endpoint?url=https%3A%2F%2Fdharma-version-api.netlify.com%2F.netlify%2Ffunctions%2Fserver%3Ftarget%3Dkeyring)](https://etherscan.io/address/0x00000000ea0007cdab60e07437e59e9cc41c2e49#code)
[![License](https://img.shields.io/github/license/dharma-eng/dharma-smart-wallet.svg)](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/LICENSE.md)
[![Build Status](https://img.shields.io/travis/dharma-eng/dharma-smart-wallet)](https://travis-ci.org/dharma-eng/dharma-smart-wallet)
@@ -15,7 +15,7 @@
## Summary
The **Dharma Smart Wallet** is a 2/2 "multisig" smart contract, controlled by the user's Dharma Key Ring and by Dharma Labs, that:
-- allows users to **make deposits and mint cDai or cUSDC from Compound** by simply sending Dai or USDC to their smart wallet address, even **before a contract has been deployed** to that address
+- allows users to **make deposits and mint [Dharma Dai or Dharma USD Coin](https://github.com/dharma-eng/dharma-token)** by simply sending Dai or USDC to their smart wallet address, even **before a contract has been deployed** to that address
- allows users to **make Dai or USDC withdrawals without paying for gas**, by providing signed messages that are validated against both the user's **Dharma Key Ring contract** and against the **Dharma Key Registry** and relayed by Dharma
- allows users to **recover their account if access is lost or compromised** after a three-day timelock, or to opt out of account recovery entirely, via the **Account Recovery Manager**
- allows for **upgrades to all user smart wallets at once**, without requiring any action on behalf of the user, and with a seven-day timelock prior to each upgrade, using the **Upgrade Beacon Controller Manager**
@@ -28,6 +28,7 @@ The **Dharma Key Ring** is an N/M "multisig" smart contract, controlled and conf
These contracts have been audited by Trail of Bits - see their security assessment for more information.
+
## Table of Contents
- [Contract Deployment Addresses and Verified Source Code](#contract-deployment-addresses-and-verified-source-code)
- [Overview](#overview)
@@ -36,34 +37,35 @@ These contracts have been audited by Trail of Bits - DharmaUpgradeBeaconControllerManager | Dharma Smart Wallet | Dharma Smart Wallet |
-| DharmaUpgradeBeaconController | AdharmaSmartWalletImplementation | DharmaSmartWalletFactoryV1 |
-| DharmaUpgradeBeacon | DharmaSmartWalletImplementationV1 | [DharmaSmartWalletFactoryV2](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/smart-wallet/DharmaSmartWalletFactoryV2.sol) |
-| DharmaKeyRingUpgradeBeaconController | DharmaSmartWalletImplementationV2 | |
-| DharmaKeyRingUpgradeBeacon | DharmaSmartWalletImplementationV3 | Dharma Key Ring |
-| DharmaUpgradeBeaconEnvoy | DharmaSmartWalletImplementationV4 | DharmaKeyRingFactoryV1 |
-| DharmaKeyRegistryV1 | DharmaSmartWalletImplementationV5 | DharmaKeyRingFactoryV2 |
-| DharmaKeyRegistryV2 | Dharma Key Ring | [DharmaKeyRingFactoryV3](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/key-ring/DharmaKeyRingFactoryV3.sol) |
+| DharmaUpgradeBeaconControllerManager | AdharmaSmartWalletImplementation | DharmaSmartWalletFactoryV1 |
+| DharmaUpgradeBeaconController |DharmaSmartWalletImplementationV1 | [DharmaSmartWalletFactoryV2](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/smart-wallet/DharmaSmartWalletFactoryV2.sol) |
+| DharmaUpgradeBeacon | DharmaSmartWalletImplementationV2 | |
+| DharmaKeyRingUpgradeBeaconController | DharmaSmartWalletImplementationV3 | |
+| DharmaKeyRingUpgradeBeacon | DharmaSmartWalletImplementationV4 | |
+| DharmaUpgradeBeaconEnvoy | DharmaSmartWalletImplementationV5 | DharmaKeyRingFactoryV1 |
+| DharmaKeyRegistryV1 | DharmaSmartWalletImplementationV6 | DharmaKeyRingFactoryV2 |
+| DharmaKeyRegistryV2 | DharmaSmartWalletImplementationV7 | [DharmaKeyRingFactoryV3](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/key-ring/DharmaKeyRingFactoryV3.sol) |
| DharmaAccountRecoveryManagerV2 | AdharmaKeyRingImplementation | |
| DharmaEscapeHatchRegistry | DharmaKeyRingImplementationV1 | |
+
## Overview
The Dharma Smart Wallet and Dharma Key Ring are designed with the following assumptions in mind:
- Dharma users will **share custody** of their smart wallet, with Dharma Labs serving as a **security backstop**, in order to better protect their funds from loss and from external adversaries and to simplify the process of earning interest on their stablecoins. The security backstop gives users the liberty to store keys in contexts that would be insufficient taken in isolation, such as in their web browser, while still maintaining non-custodial assurances that, were Dharma's key to ever become compromised, their funds would stay securely in their possession. If users decide they would rather use a fully self-custodial wallet and handle the details themselves, they will migrate away from the smart wallet by transferring their funds to a new address, or wait for upgrades to the smart wallet that unlock options for greater degrees of self-custody.
- Users are content to **let Dharma make upgrades to their smart wallets**, and do not require opt-in upgrades. However, a seven-day timelock on upgrades will let users "opt-out" of unwanted upgrades by giving them a window of time to withdraw their funds from the smart wallet.
- The initial wallet implementation uses a **subsidized meta-transaction mechanism**, where Dharma pays for the gas - in other words, there is no need to implement strict gas metering or extra fees in order to pay the transaction relayer back (as a matter of fact, **the user won't have to deal with gas or transaction submissions at all**).
- The wallet validates protected actions using **standard ethereum message signatures** (ECDSA + ecrecover + EIP-191) with **replay protection** baked in. Additionally, the Dharma Smart Wallet supports EIP-1271, which allows for the Dharma Key Ring to hold multiple signing keys and to eventually support per-key and per-action-type permissions and thresholds.
-- The smart wallet is **not set up to do anything too fancy**, like deploy contracts or run arbitrary code - it only needs to be able to make transfers and calls into other contract accounts. In particular, interactions with Compound V2 are mediated via custom, streamlined functions.
+- The smart wallet is **not set up to do anything too fancy**, like deploy contracts or run arbitrary code - it only needs to be able to make transfers and calls into other contract accounts. In particular, interactions with Dharma Tokens and Compound V2 contracts are mediated via custom, streamlined functions.
### Dharma Smart Wallet
-The current implementation of the [Dharma Smart Wallet](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV3.sol) works as follows:
-- Smart wallet deployments and stablecoin deposits can be initiated by anyone who is willing to pay the gas. Smart wallet addresses are counterfactual based on the initial user signing key, and can be safely deployed by anyone using a [Dharma Smart Wallet Factory](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/smart-wallet/DharmaSmartWalletFactoryV2.sol), as withdrawals will atomically redeem and transfer the relevant stablecoin. Therefore, expect any Dai or USDC sent to the smart wallet address to quickly be converted to cDAI or cUSDC.
+The current implementation of the [Dharma Smart Wallet](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV6.sol) works as follows:
+- Smart wallet deployments and stablecoin deposits can be initiated by anyone who is willing to pay the gas. Smart wallet addresses are counterfactual based on the initial user signing key, and can be safely deployed by anyone using a [Dharma Smart Wallet Factory](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/smart-wallet/DharmaSmartWalletFactoryV1.sol), as withdrawals will atomically redeem and transfer the relevant stablecoin. Therefore, expect any Dai or USDC sent to the smart wallet address to quickly be converted to dDAI or dUSDC.
- Every withdrawal requires signatures from both the user **and** from Dharma Labs in order to be accepted. The signature component from the user is validated against their Dharma Key Ring, and the signature component from Dharma Labs is validated against the [Dharma Key Registry](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/registries/DharmaKeyRegistryV2.sol). Either party may cancel a given signature at any time prior to execution.
-- The [Dharma Account Recovery Manager](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/account-recovery/DharmaAccountRecoveryManager.sol) will only be used in the event that a user has lost access to their Dharma Key Ring or it has been compromised - it will not have any other control over the user's smart wallet. Furthermore, the Account Recovery Manager enforces a three-day timelock before any account can be recovered. A user can also permanently opt out of account recovery through the Account Recovery Manager, though this is not recommended unless the user is highly confident in their own key management.
+- The [Dharma Account Recovery Manager](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/account-recovery/DharmaAccountRecoveryManagerV2.sol) will only be used in the event that a user has lost access to their Dharma Key Ring or it has been compromised - it will not have any other control over the user's smart wallet. Furthermore, the Account Recovery Manager enforces a three-day timelock before any account can be recovered. A user can also permanently opt out of account recovery through the Account Recovery Manager, though this is not recommended unless the user is highly confident in their own key management.
- Both required signatures must be provided at the same time - this enables actions to be taken in a single transaction, and also lets an account that is not a signatory on the wallet submit the transaction and pay for the gas. One of the signatures can be omitted if the submitting account _is_ a valid signatory.
- To protect against replay attacks, every call to the smart wallet will include a nonce that must match the current nonce on the smart wallet, as well as an optional minimum gas amount, and each time the smart wallet is called with enough gas and valid signatures that nonce will be incremented. This applies even when the action being taken by the smart wallet reverts, in which case an event will be emitted.
- Additional features will be rolled out incrementally, like the ability to assume greater degrees of self-custody over the smart wallet or to designate alternate recovery mechanisms for the smart wallet.
@@ -74,7 +76,7 @@ The Dharma Smart Wallet is controlled by the [Dharma Key Ring](https://github.co
- It differentiates between two primary key types (note that "dual" keys can be both types at once):
- Admin keys, which are used to add or remove other keys and to change thresholds or other properties of the key ring
- Standard keys, which are used to verify most external signatures that it receives based on the data provided (notably, attempts to set a new user signing key for the smart wallet must provide signatures from Admin keys)
-- Key Ring addresses are _also_ counterfactual, based on their initial signing key, and are only deployed once they are needed to make a withdrawal or to add an additional key. They can be deployed by anyone, using a [Dharma Key Ring Factory](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/key-ring/DharmaKeyRingFactoryV3.sol) - furthermore, anyone can deploy their own Dharma Key Ring for use in other applications.
+- Key Ring addresses are _also_ counterfactual, based on their initial signing key, and are only deployed once they are needed to make a withdrawal or to add an additional key. They can be deployed by anyone, using a [Dharma Key Ring Factory](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/factories/key-ring/DharmaKeyRingFactoryV2.sol) - furthermore, anyone can deploy their own Dharma Key Ring for use in other applications.
- All required signatures must be provided at the same time - this enables actions to be taken in a single transaction. Provided signatures must be ordered based on the signing address, from lowest to highest, in order to be considered valid.
- To protect against replay attacks, every call to the key ring to execute an Admin action will include a nonce that must match the current nonce on the key ring, and each time the smart wallet is called with enough gas and valid signatures that nonce will be incremented. Note that gas is not an input to signatures on the key ring, since there are no external calls made by the key ring during execution, so calls with insufficient gas can be replayed until they succeed or until another admin action is taken that increments the nonce.
@@ -90,6 +92,7 @@ Both the Dharma Smart Wallet and the Dharma Key Ring are upgradeable:
- Prior to each upgrade, a prospective implementation needs to first be deployed and registered as a potential upgrade candidate. This gives the community a chance to review the implementation, and to raise any potential concerns or opt-out of the upgrade by withdrawing their funds.
- The Dharma Escape Hatch is an opt-in feature that enables a smart wallet to call into the [Dharma Escape Hatch Registry](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/registries/DharmaEscapeHatchRegistry.sol) and designate an "escape hatch" account that can sweep the entire balance from the wallet by [calling into the `escape()` function](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV4.sol#L728) directly. This gives users with an existing, secure key the option to exit the system at any point without needing to first secure Dharma's approval.
+
## Install
To install locally, you'll need Node.js 10 through 12 and Yarn *(or npm)*. To get everything set up:
```sh
@@ -99,6 +102,7 @@ $ yarn install
$ yarn build
```
+
## Usage
To run tests locally, start the testRPC, trigger the tests, run the linter, and tear down the testRPC *(you can do all of this at once via* `yarn all` *if you prefer)*:
```sh
@@ -127,6 +131,7 @@ $ yarn build
$ yarn forkCoverage
```
+
## Example Contracts and Notable Transactions
Example Contracts:
- Example UpgradeBeaconProxyV1 smart wallet instance
@@ -148,6 +153,8 @@ Notable Transactions:
- Upgrade Beacon Controller Manager ownership transferred to multisig
- Dharma Account Recovery Manager V2 ownership transferred to multisig
- V5 implementation set on Smart Wallet Upgrade Beacon
+- V6 implementation set on Smart Wallet Upgrade Beacon
+
## Additional Information
Have any questions or feedback? Join the conversation in the Dharma_HQ Discord server. Also, see the "Why Smart Wallets Should Catch Your Interest" article for a more informal discussion around some of the motivations, features, and design decisions of the Dharma Smart Wallet.
diff --git a/contracts/helpers/SmartWalletRevertReasonHelperV1.sol b/contracts/helpers/SmartWalletRevertReasonHelperV1.sol
new file mode 100644
index 0000000..0006707
--- /dev/null
+++ b/contracts/helpers/SmartWalletRevertReasonHelperV1.sol
@@ -0,0 +1,50 @@
+pragma solidity 0.5.11;
+
+
+/**
+ * @title SmartWalletRevertReasonHelperV1
+ * @author 0age
+ * @notice This contract takes revert reason "codes" and returns revert reason
+ * strings for use in handling failures on the Dharma Smart Wallet.
+ */
+contract SmartWalletRevertReasonHelperV1 {
+ /**
+ * @notice Pure function to retrieve a revert reason string for a given code.
+ * @param code uint256 The code for the revert reason.
+ * @return A string with the revert reason.
+ */
+ function reason(uint256 code) external pure returns (string memory) {
+ if (code == 0) return "Insufficient Dai supplied.";
+ if (code == 1) return "No recipient supplied.";
+ if (code == 2) return "Could not transfer Dai.";
+ if (code == 3) return "Insufficient USDC supplied.";
+ if (code == 4) return "Must supply a non-zero amount of Ether.";
+ if (code == 5) return "Must supply an escape hatch account.";
+ if (code == 6) return "No escape hatch is currently set for this smart wallet.";
+ if (code == 7) return "Only the escape hatch account may call this function.";
+ if (code == 8) return "Only the account recovery manager may call this function.";
+ if (code == 9) return "cSai redeem failed.";
+ if (code == 10) return "Dai approval failed.";
+ if (code == 11) return "Must supply two 65-byte signatures.";
+ if (code == 12) return "Verification failed - invalid user signature.";
+ if (code == 13) return "Verification failed - invalid Dharma signature.";
+ if (code == 14) return "No user signing key provided.";
+ if (code == 15) return "Sai approval failed.";
+ if (code == 16) return "Exchange rate cannot be below 1:1.";
+ if (code == 17) return "DAI contract reverted on approval.";
+ if (code == 18) return "Recipient rejected ether transfer.";
+ if (code == 19) return "Invalid action - insufficient gas supplied by transaction submitter.";
+ if (code == 20) return "Invalid action - invalid user signature.";
+ if (code == 21) return "Invalid action - invalid Dharma signature.";
+ if (code == 22) return "Invalid action - invalid signature.";
+ if (code == 23) return "CToken approval failed.";
+ if (code == 24) return "Failed to mint any dTokens using the cToken balance on this contract.";
+ if (code == 25) return "External accounts or unapproved internal functions cannot call this.";
+ if (code == 26) return "Invalid `to` parameter - must supply a contract address containing code.";
+ if (code == 27) return "Invalid `to` parameter - cannot supply the address of this contract.";
+ if (code == 28) return "Invalid `to` parameter - cannot supply the Dharma Escape Hatch Registry.";
+ if (code == 29) return "Invalid custom action type.";
+ if (code == 30) return "Insufficient data supplied.";
+ return "(no revert reason)";
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV7.sol b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV7.sol
new file mode 100644
index 0000000..7f752cc
--- /dev/null
+++ b/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV7.sol
@@ -0,0 +1,2225 @@
+pragma solidity 0.5.11; // optimization runs: 200, evm version: petersburg
+// WARNING - `executeActionWithAtomicBatchCalls` has a `bytes[]` argument that
+// requires ABIEncoderV2. Exercise caution when calling that specific function.
+pragma experimental ABIEncoderV2;
+
+import "@openzeppelin/contracts/utils/Address.sol";
+import "@openzeppelin/contracts/cryptography/ECDSA.sol";
+import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import "../../../interfaces/DharmaSmartWalletImplementationV1Interface.sol";
+import "../../../interfaces/DharmaSmartWalletImplementationV3Interface.sol";
+import "../../../interfaces/DharmaSmartWalletImplementationV4Interface.sol";
+import "../../../interfaces/DharmaSmartWalletImplementationV7Interface.sol";
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/DTokenInterface.sol";
+import "../../../interfaces/USDCV1Interface.sol";
+import "../../../interfaces/DharmaKeyRegistryInterface.sol";
+import "../../../interfaces/DharmaEscapeHatchRegistryInterface.sol";
+import "../../../interfaces/ERC1271.sol";
+import "../../../interfaces/SaiToDaiMigratorInterface.sol";
+import "../../helpers/SmartWalletRevertReasonHelperV1.sol";
+
+
+/**
+ * @title DharmaSmartWalletImplementationV7
+ * @author 0age
+ * @notice The V7 implementation for the Dharma smart wallet is a non-custodial,
+ * meta-transaction-enabled wallet with helper functions to facilitate lending
+ * funds through Dharma Dai and Dharma USD Coin (which in turn use CompoundV2),
+ * and with an added security backstop provided by Dharma Labs prior to making
+ * withdrawals. It adds support for Dharma Dai and Dharma USD Coin - they employ
+ * the respective cTokens as backing tokens and mint and redeem them internally
+ * as interest-bearing collateral. This implementation also 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 automatically
+ * be deposited into the respective Dharma Token upon deployment of the new
+ * smart wallet instance.
+ */
+contract DharmaSmartWalletImplementationV7 is
+ DharmaSmartWalletImplementationV1Interface,
+ DharmaSmartWalletImplementationV3Interface,
+ DharmaSmartWalletImplementationV4Interface,
+ DharmaSmartWalletImplementationV7Interface,
+ ERC1271 {
+ using Address for address;
+ using ECDSA for bytes32;
+ // WARNING: DO NOT REMOVE OR REORDER STORAGE WHEN WRITING NEW IMPLEMENTATIONS!
+
+ // The user signing key associated with this account is in storage slot 0.
+ // It is the core differentiator when it comes to the account in question.
+ address private _userSigningKey;
+
+ // The nonce associated with this account is in storage slot 1. Every time a
+ // signature is submitted, it must have the appropriate nonce, and once it has
+ // been accepted the nonce will be incremented.
+ uint256 private _nonce;
+
+ // The self-call context flag is in storage slot 2. Some protected functions
+ // may only be called externally from calls originating from other methods on
+ // this contract, which enables appropriate exception handling on reverts.
+ // Any storage should only be set immediately preceding a self-call and should
+ // be cleared upon entering the protected function being called.
+ bytes4 internal _selfCallContext;
+
+ // END STORAGE DECLARATIONS - DO NOT REMOVE OR REORDER STORAGE ABOVE HERE!
+
+ // The smart wallet version will be used when constructing valid signatures.
+ uint256 internal constant _DHARMA_SMART_WALLET_VERSION = 7;
+
+ // DharmaKeyRegistryV2 holds a public key for verifying meta-transactions.
+ DharmaKeyRegistryInterface internal constant _DHARMA_KEY_REGISTRY = (
+ DharmaKeyRegistryInterface(0x000000000D38df53b45C5733c7b34000dE0BDF52)
+ );
+
+ // Account recovery is facilitated using a hard-coded recovery manager,
+ // controlled by Dharma and implementing appropriate timelocks.
+ address internal constant _ACCOUNT_RECOVERY_MANAGER = address(
+ 0x0000000000DfEd903aD76996FC07BF89C0127B1E
+ );
+
+ // Users can designate an "escape hatch" account with the ability to sweep all
+ // funds from their smart wallet by using the Dharma Escape Hatch Registry.
+ DharmaEscapeHatchRegistryInterface internal constant _ESCAPE_HATCH_REGISTRY = (
+ DharmaEscapeHatchRegistryInterface(0x00000000005280B515004B998a944630B6C663f8)
+ );
+
+ // Interface with dDai, dUSDC, Dai, USDC, Sai, cSai, cDai, cUSDC, & migrator.
+ DTokenInterface internal constant _DDAI = DTokenInterface(
+ 0x00000000001876eB1444c986fD502e618c587430 // mainnet
+ );
+
+ DTokenInterface internal constant _DUSDC = DTokenInterface(
+ 0x00000000008943c65cAf789FFFCF953bE156f6f8 // mainnet
+ );
+
+ IERC20 internal constant _DAI = IERC20(
+ 0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
+ );
+
+ IERC20 internal constant _USDC = IERC20(
+ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
+ );
+
+ IERC20 internal constant _SAI = IERC20(
+ 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359 // mainnet
+ );
+
+ CTokenInterface internal constant _CSAI = CTokenInterface(
+ 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC // mainnet
+ );
+
+ CTokenInterface internal constant _CDAI = CTokenInterface(
+ 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 // mainnet
+ );
+
+ CTokenInterface internal constant _CUSDC = CTokenInterface(
+ 0x39AA39c021dfbaE8faC545936693aC917d5E7563 // mainnet
+ );
+
+ SaiToDaiMigratorInterface internal constant _MIGRATOR = SaiToDaiMigratorInterface(
+ 0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849 // mainnet
+ );
+
+ USDCV1Interface internal constant _USDC_NAUGHTY = USDCV1Interface(
+ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
+ );
+
+ // The "revert reason helper" contains a collection of revert reason strings.
+ SmartWalletRevertReasonHelperV1 internal constant _REVERT_REASON_HELPER = (
+ SmartWalletRevertReasonHelperV1(0xE24257338d0c15f3Dd00Ed59fcA9e50CfB167bA8)
+ );
+
+ // Compound returns a value of 0 to indicate success, or lack of an error.
+ uint256 internal constant _COMPOUND_SUCCESS = 0;
+
+ // ERC-1271 must return this magic value when `isValidSignature` is called.
+ bytes4 internal constant _ERC_1271_MAGIC_VALUE = bytes4(0x20c13b0b);
+
+ // Minimum supported deposit & non-maximum withdrawal size is .001 underlying.
+ uint256 private constant _JUST_UNDER_ONE_1000th_DAI = 999999999999999;
+ uint256 private constant _JUST_UNDER_ONE_1000th_USDC = 999;
+
+ // Specify the amount of gas to supply when making Ether transfers.
+ uint256 private constant _ETH_TRANSFER_GAS = 4999;
+
+ /**
+ * @notice In the initializer, set up the initial user signing key, set
+ * approval on the Dharma Dai and Dharma USD Coin contracts, and deposit any
+ * Dai or USDC already at this address to receive dDai or dUSDC. 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.
+ */
+ function initialize(address userSigningKey) external {
+ // Ensure that this function is only callable during contract construction.
+ assembly { if extcodesize(address) { revert(0, 0) } }
+
+ // Set up the user's signing key and emit a corresponding event.
+ _setUserSigningKey(userSigningKey);
+
+ // Approve the dDai contract to transfer Dai on behalf of this contract.
+ if (_setFullApproval(AssetType.DAI)) {
+ // Get the current Dai balance on this contract.
+ uint256 daiBalance = _DAI.balanceOf(address(this));
+
+ // Try to deposit the full Dai balance to Dharma Dai.
+ _depositDharmaToken(AssetType.DAI, daiBalance);
+ }
+
+ // Approve the dUSDC contract to transfer USDC on behalf of this contract.
+ if (_setFullApproval(AssetType.USDC)) {
+ // Get the current USDC balance on this contract.
+ uint256 usdcBalance = _USDC.balanceOf(address(this));
+
+ // Try to deposit the full Dai balance to Dharma USDC.
+ _depositDharmaToken(AssetType.USDC, usdcBalance);
+ }
+ }
+
+ /**
+ * @notice Deposit all Dai and USDC currently residing at this address and
+ * receive Dharma Dai or Dharma USD Coin in return. Note that "repay" is not
+ * currently implemented, though it may be in a future implementation. 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 {
+ // Get the current Dai balance on this contract.
+ uint256 daiBalance = _DAI.balanceOf(address(this));
+
+ // If there is any Dai balance, check for adequate approval for dDai.
+ if (daiBalance > 0) {
+ uint256 daiAllowance = _DAI.allowance(address(this), address(_DDAI));
+ // If allowance is insufficient, try to set it before depositing.
+ if (daiAllowance < daiBalance) {
+ if (_setFullApproval(AssetType.DAI)) {
+ // Deposit the full available Dai balance to Dharma Dai.
+ _depositDharmaToken(AssetType.DAI, daiBalance);
+ }
+ // Otherwise, just go ahead and try the Dai deposit.
+ } else {
+ // Deposit the full available Dai balance to Dharma Dai.
+ _depositDharmaToken(AssetType.DAI, daiBalance);
+ }
+ }
+
+ // Get the current USDC balance on this contract.
+ uint256 usdcBalance = _USDC.balanceOf(address(this));
+
+ // If there is any USDC balance, check for adequate approval for dUSDC.
+ if (usdcBalance > 0) {
+ uint256 usdcAllowance = _USDC.allowance(address(this), address(_DUSDC));
+ // If allowance is insufficient, try to set it before depositing.
+ if (usdcAllowance < usdcBalance) {
+ if (_setFullApproval(AssetType.USDC)) {
+ // Deposit the full available USDC balance to Dharma USDC.
+ _depositDharmaToken(AssetType.USDC, usdcBalance);
+ }
+ // Otherwise, just go ahead and try the USDC deposit.
+ } else {
+ // Deposit the full available USDC balance to Dharma USDC.
+ _depositDharmaToken(AssetType.USDC, usdcBalance);
+ }
+ }
+ }
+
+ /**
+ * @notice Withdraw Dai to a provided recipient address by redeeming the
+ * underlying Dai from the dDai contract and transferring it to the recipient.
+ * All Dai in Dharma Dai and in the smart wallet itself can be withdrawn by
+ * providing an amount of uint256(-1) or 0xfff...fff. This function can be
+ * called directly by the account set as the global key on the Dharma Key
+ * Registry, or by any relayer that provides a signed message from the same
+ * keyholder. The nonce used for the signature must match the current nonce on
+ * the smart wallet, and gas supplied to the call must exceed the specified
+ * minimum action gas, plus the gas that will be spent before the gas check is
+ * reached - usually somewhere around 25,000 gas. If the withdrawal fails, an
+ * `ExternalError` with additional details on what went wrong will be emitted.
+ * Note that some dust may still be left over, even in the event of a max
+ * withdrawal, due to the fact that Dai has a higher precision than dDai. Also
+ * note that the withdrawal will fail in the event that Compound does not have
+ * sufficient Dai available to withdraw.
+ * @param amount uint256 The amount of Dai to withdraw.
+ * @param recipient address The account to transfer the withdrawn Dai to.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return True if the withdrawal succeeded, otherwise false.
+ */
+ function withdrawDai(
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok) {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.DAIWithdrawal,
+ abi.encode(amount, recipient),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Ensure that an amount of at least 0.001 Dai has been supplied.
+ require(amount > _JUST_UNDER_ONE_1000th_DAI, _revertReason(0));
+
+ // Ensure that a non-zero recipient has been supplied.
+ require(recipient != address(0), _revertReason(1));
+
+ // Set the self-call context in order to call _withdrawDaiAtomic.
+ _selfCallContext = this.withdrawDai.selector;
+
+ // Make the atomic self-call - if redeemUnderlying fails on dDai, it will
+ // succeed but nothing will happen except firing an ExternalError event. If
+ // the second part of the self-call (the Dai transfer) fails, it will revert
+ // and roll back the first part of the call as well as fire an ExternalError
+ // event after returning from the failed call.
+ bytes memory returnData;
+ (ok, returnData) = address(this).call(abi.encodeWithSelector(
+ this._withdrawDaiAtomic.selector, amount, recipient
+ ));
+
+ // If the atomic call failed, emit an event signifying a transfer failure.
+ if (!ok) {
+ emit ExternalError(address(_DAI), _revertReason(2));
+ } else {
+ // Set ok to false if the call succeeded but the withdrawal failed.
+ ok = abi.decode(returnData, (bool));
+ }
+ }
+
+ /**
+ * @notice Protected function that can only be called from `withdrawDai` on
+ * this contract. It will attempt to withdraw the supplied amount of Dai, or
+ * the maximum amount if specified using `uint256(-1)`, to the supplied
+ * recipient address by redeeming the underlying Dai from the dDai contract
+ * and transferring it to the recipient. An ExternalError will be emitted and
+ * the transfer will be skipped if the call to `redeem` or `redeemUnderlying`
+ * fails, and any revert will be caught by `withdrawDai` and diagnosed in
+ * order to emit an appropriate `ExternalError` as well.
+ * @param amount uint256 The amount of Dai to withdraw.
+ * @param recipient address The account to transfer the withdrawn Dai to.
+ * @return True if the withdrawal succeeded, otherwise false.
+ */
+ function _withdrawDaiAtomic(
+ uint256 amount,
+ address recipient
+ ) external returns (bool success) {
+ // Ensure caller is this contract and self-call context is correctly set.
+ _enforceSelfCallFrom(this.withdrawDai.selector);
+
+ // If amount = 0xfff...fff, withdraw the maximum amount possible.
+ bool maxWithdraw = (amount == uint256(-1));
+ if (maxWithdraw) {
+ // First attempt to redeem all dDai if there is a balance.
+ _withdrawMaxFromDharmaToken(AssetType.DAI);
+
+ // Then transfer all Dai to recipient if there is a balance.
+ require(_transferMax(_DAI, recipient, false));
+ success = true;
+ } else {
+ // Attempt to withdraw specified Dai from Dharma Dai before proceeding.
+ if (_withdrawFromDharmaToken(AssetType.DAI, amount)) {
+ // At this point Dai transfer should never fail - wrap it just in case.
+ require(_DAI.transfer(recipient, amount));
+ success = true;
+ }
+ }
+ }
+
+ /**
+ * @notice Withdraw USDC to a provided recipient address by redeeming the
+ * underlying USDC from the dUSDC contract and transferring it to recipient.
+ * All USDC in Dharma USD Coin and in the smart wallet itself can be withdrawn
+ * by providing an amount of uint256(-1) or 0xfff...fff. This function can be
+ * called directly by the account set as the global key on the Dharma Key
+ * Registry, or by any relayer that provides a signed message from the same
+ * keyholder. The nonce used for the signature must match the current nonce on
+ * the smart wallet, and gas supplied to the call must exceed the specified
+ * minimum action gas, plus the gas that will be spent before the gas check is
+ * reached - usually somewhere around 25,000 gas. If the withdrawal fails, an
+ * `ExternalError` with additional details on what went wrong will be emitted.
+ * Note that the USDC contract can be paused and also allows for blacklisting
+ * accounts - either of these possibilities may cause a withdrawal to fail. In
+ * addition, Compound may not have sufficient USDC available at the time to
+ * withdraw.
+ * @param amount uint256 The amount of USDC to withdraw.
+ * @param recipient address The account to transfer the withdrawn USDC to.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return True if the withdrawal succeeded, otherwise false.
+ */
+ function withdrawUSDC(
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok) {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.USDCWithdrawal,
+ abi.encode(amount, recipient),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Ensure that an amount of at least 0.001 USDC has been supplied.
+ require(amount > _JUST_UNDER_ONE_1000th_USDC, _revertReason(3));
+
+ // Ensure that a non-zero recipient has been supplied.
+ require(recipient != address(0), _revertReason(1));
+
+ // Set the self-call context in order to call _withdrawUSDCAtomic.
+ _selfCallContext = this.withdrawUSDC.selector;
+
+ // Make the atomic self-call - if redeemUnderlying fails on dUSDC, it will
+ // succeed but nothing will happen except firing an ExternalError event. If
+ // the second part of the self-call (USDC transfer) fails, it will revert
+ // and roll back the first part of the call as well as fire an ExternalError
+ // event after returning from the failed call.
+ bytes memory returnData;
+ (ok, returnData) = address(this).call(abi.encodeWithSelector(
+ this._withdrawUSDCAtomic.selector, amount, recipient
+ ));
+ if (!ok) {
+ // Find out why USDC transfer reverted (doesn't give revert reasons).
+ _diagnoseAndEmitUSDCSpecificError(_USDC.transfer.selector);
+ } else {
+ // Set ok to false if the call succeeded but the withdrawal failed.
+ ok = abi.decode(returnData, (bool));
+ }
+ }
+
+ /**
+ * @notice Protected function that can only be called from `withdrawUSDC` on
+ * this contract. It will attempt to withdraw the supplied amount of USDC, or
+ * the maximum amount if specified using `uint256(-1)`, to the supplied
+ * recipient address by redeeming the underlying USDC from the dUSDC contract
+ * and transferring it to the recipient. An ExternalError will be emitted and
+ * the transfer will be skipped if the call to `redeemUnderlying` fails, and
+ * any revert will be caught by `withdrawUSDC` and diagnosed in order to emit
+ * an appropriate ExternalError as well.
+ * @param amount uint256 The amount of USDC to withdraw.
+ * @param recipient address The account to transfer the withdrawn USDC to.
+ * @return True if the withdrawal succeeded, otherwise false.
+ */
+ function _withdrawUSDCAtomic(
+ uint256 amount,
+ address recipient
+ ) external returns (bool success) {
+ // Ensure caller is this contract and self-call context is correctly set.
+ _enforceSelfCallFrom(this.withdrawUSDC.selector);
+
+ // If amount = 0xfff...fff, withdraw the maximum amount possible.
+ bool maxWithdraw = (amount == uint256(-1));
+ if (maxWithdraw) {
+ // Attempt to redeem all dUSDC from Dharma USDC if there is a balance.
+ _withdrawMaxFromDharmaToken(AssetType.USDC);
+
+ // Then transfer all USDC to recipient if there is a balance.
+ require(_transferMax(_USDC, recipient, false));
+ success = true;
+ } else {
+ // Attempt to withdraw specified USDC from Dharma USDC before proceeding.
+ if (_withdrawFromDharmaToken(AssetType.USDC, amount)) {
+ // Ensure that the USDC transfer does not fail.
+ require(_USDC.transfer(recipient, amount));
+ success = true;
+ }
+ }
+ }
+
+ /**
+ * @notice Withdraw Ether to a provided recipient address by transferring it
+ * to a recipient. This is only intended to be utilized on V7 as a mechanism
+ * for recovering Ether from this contract.
+ * @param amount uint256 The amount of Ether to withdraw.
+ * @param recipient address The account to transfer the Ether to.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return True if the transfer succeeded, otherwise false.
+ */
+ function withdrawEther(
+ uint256 amount,
+ address payable recipient,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok) {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.ETHWithdrawal,
+ abi.encode(amount, recipient),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Ensure that a non-zero amount of Ether has been supplied.
+ require(amount > 0, _revertReason(4));
+
+ // Ensure that a non-zero recipient has been supplied.
+ require(recipient != address(0), _revertReason(1));
+
+ // Attempt to transfer Ether to the recipient and emit an appropriate event.
+ ok = _transferETH(recipient, amount);
+ }
+
+ /**
+ * @notice Allow a signatory to increment the nonce at any point. The current
+ * nonce needs to be provided as an argument to the signature so as not to
+ * enable griefing attacks. All arguments can be omitted if called directly.
+ * No value is returned from this function - it will either succeed or revert.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param signature bytes A signature that resolves to either the public key
+ * set for this account in storage slot zero, `_userSigningKey`, or the public
+ * key returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ */
+ function cancel(
+ uint256 minimumActionGas,
+ bytes calldata signature
+ ) external {
+ // Get the current nonce.
+ uint256 nonceToCancel = _nonce;
+
+ // Ensure the caller or the supplied signature is valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.Cancel,
+ abi.encode(),
+ minimumActionGas,
+ signature,
+ signature
+ );
+
+ // Emit an event to validate that the nonce is no longer valid.
+ emit Cancel(nonceToCancel);
+ }
+
+ /**
+ * @notice Perform a generic call to another contract. Note that accounts with
+ * no code may not be specified, nor may the smart wallet itself or the escape
+ * hatch registry. In order to increment the nonce and invalidate the
+ * signatures, a call to this function with a valid target, signatutes, and
+ * gas will always succeed. To determine whether the call made as part of the
+ * action was successful or not, either the return values or the `CallSuccess`
+ * or `CallFailure` event can be used.
+ * @param to address The contract to call.
+ * @param data bytes The calldata to provide when making the call.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return A boolean signifying the status of the call, as well as any data
+ * returned from the call.
+ */
+ function executeAction(
+ address to,
+ bytes calldata data,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok, bytes memory returnData) {
+ // Ensure that the `to` address is a contract and is not this contract.
+ _ensureValidGenericCallTarget(to);
+
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ (bytes32 actionID, uint256 nonce) = _validateActionAndIncrementNonce(
+ ActionType.Generic,
+ abi.encode(to, data),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Note: from this point on, there are no reverts (apart from out-of-gas or
+ // call-depth-exceeded) originating from this action. However, the call
+ // itself may revert, in which case the function will return `false`, along
+ // with the revert reason encoded as bytes, and fire an CallFailure event.
+
+ // Perform the action via low-level call and set return values using result.
+ (ok, returnData) = to.call(data);
+
+ // Emit a CallSuccess or CallFailure event based on the outcome of the call.
+ if (ok) {
+ // Note: while the call succeeded, the action may still have "failed"
+ // (for example, successful calls to Compound can still return an error).
+ emit CallSuccess(actionID, false, nonce, to, data, returnData);
+ } else {
+ // Note: while the call failed, the nonce will still be incremented, which
+ // will invalidate all supplied signatures.
+ emit CallFailure(actionID, nonce, to, data, string(returnData));
+ }
+ }
+
+ /**
+ * @notice Allow signatory to set a new user signing key. The current nonce
+ * needs to be provided as an argument to the signature so as not to enable
+ * griefing attacks. No value is returned from this function - it will either
+ * succeed or revert.
+ * @param userSigningKey address The new user signing key to set on this smart
+ * wallet.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ */
+ function setUserSigningKey(
+ address userSigningKey,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.SetUserSigningKey,
+ abi.encode(userSigningKey),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Set new user signing key on smart wallet and emit a corresponding event.
+ _setUserSigningKey(userSigningKey);
+ }
+
+ /**
+ * @notice Set a dedicated address as the "escape hatch" account. This account
+ * can then call `escape()` at any point to "sweep" the entire Dai, USDC,
+ * residual cDai, cUSDC, dDai, dUSDC, and Ether balance from the smart wallet.
+ * This function call will revert if the smart wallet has previously called
+ * `permanentlyDisableEscapeHatch` at any point and disabled the escape hatch.
+ * No value is returned from this function - it will either succeed or revert.
+ * @param account address The account to set as the escape hatch account.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ */
+ function setEscapeHatch(
+ address account,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.SetEscapeHatch,
+ abi.encode(account),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Ensure that an escape hatch account has been provided.
+ require(account != address(0), _revertReason(5));
+
+ // Set a new escape hatch for the smart wallet unless it has been disabled.
+ _ESCAPE_HATCH_REGISTRY.setEscapeHatch(account);
+ }
+
+ /**
+ * @notice Remove the "escape hatch" account if one is currently set. This
+ * function call will revert if the smart wallet has previously called
+ * `permanentlyDisableEscapeHatch` at any point and disabled the escape hatch.
+ * No value is returned from this function - it will either succeed or revert.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ */
+ function removeEscapeHatch(
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.RemoveEscapeHatch,
+ abi.encode(),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Remove the escape hatch for the smart wallet if one is currently set.
+ _ESCAPE_HATCH_REGISTRY.removeEscapeHatch();
+ }
+
+ /**
+ * @notice Permanently disable the "escape hatch" mechanism for this smart
+ * wallet. This function call will revert if the smart wallet has already
+ * called `permanentlyDisableEscapeHatch` at any point in the past. No value
+ * is returned from this function - it will either succeed or revert.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ */
+ function permanentlyDisableEscapeHatch(
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external {
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ _validateActionAndIncrementNonce(
+ ActionType.DisableEscapeHatch,
+ abi.encode(),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Permanently disable the escape hatch mechanism for this smart wallet.
+ _ESCAPE_HATCH_REGISTRY.permanentlyDisableEscapeHatch();
+ }
+
+ /**
+ * @notice Allow the designated escape hatch account to "sweep" the entire
+ * Sai, Dai, USDC, residual dDai, dUSDC, cSai, cDai & cUSDC, and Ether balance
+ * from the smart wallet. The call will revert for any other caller, or if
+ * there is no escape hatch account on this smart wallet. First, an attempt
+ * will be made to redeem any dDai or dUSDC that is currently deposited in a
+ * dToken. Then, attempts will be made to transfer all Sai, Dai, USDC,
+ * residual cSai, cDai & cUSDC, and Ether to the escape hatch account. If any
+ * portion of this operation does not succeed, it will simply be skipped,
+ * allowing the rest of the operation to proceed. Finally, an `Escaped` event
+ * will be emitted. No value is returned from this function - it will either
+ * succeed or revert.
+ */
+ function escape() external {
+ // Get the escape hatch account, if one exists, for this account.
+ (bool exists, address escapeHatch) = _ESCAPE_HATCH_REGISTRY.getEscapeHatch();
+
+ // Ensure that an escape hatch is currently set for this smart wallet.
+ require(exists, _revertReason(6));
+
+ // Ensure that the escape hatch account is the caller.
+ require(msg.sender == escapeHatch, _revertReason(7));
+
+ // Attempt to redeem all dDai for Dai on Dharma Dai.
+ _withdrawMaxFromDharmaToken(AssetType.DAI);
+
+ // Attempt to redeem all dUSDC for USDC on Dharma USDC.
+ _withdrawMaxFromDharmaToken(AssetType.USDC);
+
+ // Attempt to transfer the total Dai balance to the caller.
+ _transferMax(_DAI, msg.sender, true);
+
+ // Attempt to transfer the total USDC balance to the caller.
+ _transferMax(_USDC, msg.sender, true);
+
+ // Attempt to transfer any residual cSai to the caller.
+ _transferMax(IERC20(address(_CSAI)), msg.sender, true);
+
+ // Attempt to transfer any residual cDai to the caller.
+ _transferMax(IERC20(address(_CDAI)), msg.sender, true);
+
+ // Attempt to transfer any residual cUSDC to the caller.
+ _transferMax(IERC20(address(_CUSDC)), msg.sender, true);
+
+ // Attempt to transfer any residual dDai to the caller.
+ _transferMax(IERC20(address(_DDAI)), msg.sender, true);
+
+ // Attempt to transfer any residual dUSDC to the caller.
+ _transferMax(IERC20(address(_DUSDC)), msg.sender, true);
+
+ // Determine if there is Ether at this address that should be transferred.
+ uint256 balance = address(this).balance;
+ if (balance > 0) {
+ // Attempt to transfer any Ether to caller and emit an appropriate event.
+ _transferETH(msg.sender, balance);
+ }
+
+ // Emit an `Escaped` event.
+ emit Escaped();
+ }
+
+ /**
+ * @notice Allow the account recovery manager to set a new user signing key on
+ * the smart wallet. The call will revert for any other caller. The account
+ * recovery manager implements a set of controls around the process, including
+ * a timelock and an option to permanently opt out of account recover. No
+ * value is returned from this function - it will either succeed or revert.
+ * @param newUserSigningKey address The new user signing key to set on this
+ * smart wallet.
+ */
+ function recover(address newUserSigningKey) external {
+ require(msg.sender == _ACCOUNT_RECOVERY_MANAGER, _revertReason(8));
+
+ // Increment nonce to prevent signature reuse should original key be reset.
+ _nonce++;
+
+ // Set up the user's new dharma key and emit a corresponding event.
+ _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 dDai. 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 migrateCSaiToDDai() 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, _revertReason(9));
+
+ // 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 dDai allowance is insufficient, set it before depositing.
+ if (_DAI.allowance(address(this), address(_DDAI)) < daiBalance) {
+ require(_DAI.approve(address(_DDAI), uint256(-1)), _revertReason(10));
+ }
+
+ // Deposit the new Dai balance on Dharma Dai.
+ _DDAI.mint(daiBalance);
+ }
+ }
+
+ /**
+ * @notice Redeem all available cDAI for Dai and use that Dai to mint dDai. 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 migrateCDaiToDDai() external {
+ _migrateCTokenToDToken(AssetType.DAI);
+ }
+
+ /**
+ * @notice Redeem all available cUSDC for USDC and use that USDC to mint
+ * dUSDC. If any step in the process fails, the call will revert and prior
+ * steps will be rolled back. Also note that existing USDC is not included as
+ * part of this operation.
+ */
+ function migrateCUSDCToDUSDC() external {
+ _migrateCTokenToDToken(AssetType.USDC);
+ }
+
+ /**
+ * @notice View function to retrieve the Dai and USDC balances held by the
+ * smart wallet, both directly and held in Dharma Dai and Dharma USD Coin, as
+ * well as the Ether balance (the underlying dEther balance will always return
+ * zero in this implementation, as there is no dEther yet).
+ * @return The Dai balance, the USDC balance, the Ether balance, the
+ * underlying Dai balance of the dDai balance, and the underlying USDC balance
+ * of the dUSDC balance (zero will always be returned as the underlying Ether
+ * balance of the dEther balance in this implementation).
+ */
+ function getBalances() external view returns (
+ uint256 daiBalance,
+ uint256 usdcBalance,
+ uint256 etherBalance,
+ uint256 dDaiUnderlyingDaiBalance,
+ uint256 dUsdcUnderlyingUsdcBalance,
+ uint256 dEtherUnderlyingEtherBalance // always returns 0
+ ) {
+ daiBalance = _DAI.balanceOf(address(this));
+ usdcBalance = _USDC.balanceOf(address(this));
+ etherBalance = address(this).balance;
+ dDaiUnderlyingDaiBalance = _DDAI.balanceOfUnderlying(address(this));
+ dUsdcUnderlyingUsdcBalance = _DUSDC.balanceOfUnderlying(address(this));
+ }
+
+ /**
+ * @notice View function for getting the current user signing key for the
+ * smart wallet.
+ * @return The current user signing key.
+ */
+ function getUserSigningKey() external view returns (address userSigningKey) {
+ userSigningKey = _userSigningKey;
+ }
+
+ /**
+ * @notice View function for getting the current nonce of the smart wallet.
+ * This nonce is incremented whenever an action is taken that requires a
+ * signature and/or a specific caller.
+ * @return The current nonce.
+ */
+ function getNonce() external view returns (uint256 nonce) {
+ nonce = _nonce;
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for the corresponding action. Any nonce value
+ * may be supplied, which enables constructing valid message hashes for
+ * multiple future actions ahead of time.
+ * @param action uint8 The type of action, designated by it's index. Valid
+ * custom actions in V7 include Cancel (0), SetUserSigningKey (1),
+ * 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.
+ * @param recipient address The account to transfer withdrawn funds to or the
+ * new user signing key. This value is ignored for Cancel, RemoveEscapeHatch,
+ * and DisableEscapeHatch action types.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getNextCustomActionID(
+ ActionType action,
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ action,
+ _validateCustomActionTypeAndGetArguments(action, amount, recipient),
+ _nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for the corresponding action. The current nonce
+ * will be used, which means that it will only be valid for the next action
+ * taken.
+ * @param action uint8 The type of action, designated by it's index. Valid
+ * custom actions in V7 include Cancel (0), SetUserSigningKey (1),
+ * 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.
+ * @param recipient address The account to transfer withdrawn funds to or the
+ * new user signing key. This value is ignored for Cancel, RemoveEscapeHatch,
+ * and DisableEscapeHatch action types.
+ * @param nonce uint256 The nonce to use.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getCustomActionID(
+ ActionType action,
+ uint256 amount,
+ address recipient,
+ uint256 nonce,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ action,
+ _validateCustomActionTypeAndGetArguments(action, amount, recipient),
+ nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for a given generic action. The current nonce
+ * will be used, which means that it will only be valid for the next action
+ * taken.
+ * @param to address The target to call into as part of the generic action.
+ * @param data bytes The data to supply when calling into the target.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getNextGenericActionID(
+ address to,
+ bytes calldata data,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ ActionType.Generic,
+ abi.encode(to, data),
+ _nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for a given generic action. Any nonce value may
+ * be supplied, which enables constructing valid message hashes for multiple
+ * future actions ahead of time.
+ * @param to address The target to call into as part of the generic action.
+ * @param data bytes The data to supply when calling into the target.
+ * @param nonce uint256 The nonce to use.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getGenericActionID(
+ address to,
+ bytes calldata data,
+ uint256 nonce,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ ActionType.Generic,
+ abi.encode(to, data),
+ nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice View function that implements ERC-1271 and validates a set of
+ * signatures, one from the owner (using ERC-1271 as well if the user signing
+ * key is a contract) and one from the Dharma Key Registry against the
+ * supplied data. The data must be ABI encoded as (bytes32, bytes), where the
+ * first bytes32 parameter represents the hash digest for validating the
+ * supplied signatures and the second bytes parameter contains context for the
+ * requested validation. The two signatures are packed together, with the one
+ * from Dharma coming first and that from the user coming second - this is so
+ * that, in future versions, multiple user signatures may be supplied if the
+ * associated key ring requires them.
+ * @param data bytes The data used to validate the signature.
+ * @param signatures bytes The two signatures, each 65 bytes - one from the
+ * owner (using ERC-1271 as well if the user signing key is a contract) and
+ * one from the Dharma Key Registry.
+ * @return The 4-byte magic value to signify a valid signature in ERC-1271, if
+ * the signatures are both valid.
+ */
+ function isValidSignature(
+ bytes calldata data, bytes calldata signatures
+ ) external view returns (bytes4 magicValue) {
+ // Get message hash digest and any additional context from data argument.
+ bytes32 digest;
+ bytes memory context;
+
+ if (data.length == 32) {
+ digest = abi.decode(data, (bytes32));
+ } else {
+ require(data.length >= 64, _revertReason(30));
+ (digest, context) = abi.decode(data, (bytes32, bytes));
+ }
+
+ // Get Dharma signature & user signature from combined signatures argument.
+ require(signatures.length == 130, _revertReason(11));
+ bytes memory signaturesInMemory = signatures;
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ assembly {
+ r := mload(add(signaturesInMemory, 0x20))
+ s := mload(add(signaturesInMemory, 0x40))
+ v := byte(0, mload(add(signaturesInMemory, 0x60)))
+ }
+ bytes memory dharmaSignature = abi.encodePacked(r, s, v);
+
+ assembly {
+ r := mload(add(signaturesInMemory, 0x61))
+ s := mload(add(signaturesInMemory, 0x81))
+ v := byte(0, mload(add(signaturesInMemory, 0xa1)))
+ }
+ bytes memory userSignature = abi.encodePacked(r, s, v);
+
+ // Validate user signature with `SignatureVerification` as the action type.
+ require(
+ _validateUserSignature(
+ digest,
+ ActionType.SignatureVerification,
+ context,
+ _userSigningKey,
+ userSignature
+ ),
+ _revertReason(12)
+ );
+
+ // Recover Dharma signature against key returned from Dharma Key Registry.
+ require(
+ _getDharmaSigningKey() == digest.recover(dharmaSignature),
+ _revertReason(13)
+ );
+
+ // Return the ERC-1271 magic value to indicate success.
+ magicValue = _ERC_1271_MAGIC_VALUE;
+ }
+
+ /**
+ * @notice Pure function for getting the current Dharma Smart Wallet version.
+ * @return The current Dharma Smart Wallet version.
+ */
+ function getVersion() external pure returns (uint256 version) {
+ version = _DHARMA_SMART_WALLET_VERSION;
+ }
+
+ /**
+ * @notice Perform a series of generic calls to other contracts. If any call
+ * fails during execution, the preceding calls will be rolled back, but their
+ * original return data will still be accessible. Calls that would otherwise
+ * occur after the failed call will not be executed. Note that accounts with
+ * no code may not be specified, nor may the smart wallet itself or the escape
+ * hatch registry. In order to increment the nonce and invalidate the
+ * signatures, a call to this function with valid targets, signatutes, and gas
+ * will always succeed. To determine whether each call made as part of the
+ * action was successful or not, either the corresponding return value or the
+ * corresponding `CallSuccess` or `CallFailure` event can be used - note that
+ * even calls that return a success status will have been rolled back unless
+ * all of the calls returned a success status. Finally, note that this
+ * function must currently be implemented as a public function (instead of as
+ * an external one) due to an ABIEncoderV2 `UnimplementedFeatureError`.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return An array of structs signifying the status of each call, as well as
+ * any data returned from that call. Calls that are not executed will return
+ * empty data.
+ */
+ function executeActionWithAtomicBatchCalls(
+ Call[] memory calls,
+ uint256 minimumActionGas,
+ bytes memory userSignature,
+ bytes memory dharmaSignature
+ ) public returns (bool[] memory ok, bytes[] memory returnData) {
+ // Ensure that each `to` address is a contract and is not this contract.
+ for (uint256 i = 0; i < calls.length; i++) {
+ _ensureValidGenericCallTarget(calls[i].to);
+ }
+
+ // Ensure caller and/or supplied signatures are valid and increment nonce.
+ (bytes32 actionID, uint256 nonce) = _validateActionAndIncrementNonce(
+ ActionType.GenericAtomicBatch,
+ abi.encode(calls),
+ minimumActionGas,
+ userSignature,
+ dharmaSignature
+ );
+
+ // Note: from this point on, there are no reverts (apart from out-of-gas or
+ // call-depth-exceeded) originating from this contract. However, one of the
+ // calls may revert, in which case the function will return `false`, along
+ // with the revert reason encoded as bytes, and fire an CallFailure event.
+
+ // Specify length of returned values in order to work with them in memory.
+ ok = new bool[](calls.length);
+ returnData = new bytes[](calls.length);
+
+ // Set self-call context to call _executeActionWithAtomicBatchCallsAtomic.
+ _selfCallContext = this.executeActionWithAtomicBatchCalls.selector;
+
+ // Make the atomic self-call - if any call fails, calls that preceded it
+ // will be rolled back and calls that follow it will not be made.
+ (bool externalOk, bytes memory rawCallResults) = address(this).call(
+ abi.encodeWithSelector(
+ this._executeActionWithAtomicBatchCallsAtomic.selector, calls
+ )
+ );
+
+ // Parse data returned from self-call into each call result and store / log.
+ CallReturn[] memory callResults = abi.decode(rawCallResults, (CallReturn[]));
+ for (uint256 i = 0; i < callResults.length; i++) {
+ Call memory currentCall = calls[i];
+
+ // Set the status and the return data / revert reason from the call.
+ ok[i] = callResults[i].ok;
+ returnData[i] = callResults[i].returnData;
+
+ // Emit CallSuccess or CallFailure event based on the outcome of the call.
+ if (callResults[i].ok) {
+ // Note: while the call succeeded, the action may still have "failed".
+ emit CallSuccess(
+ actionID,
+ !externalOk, // If another call failed this will have been rolled back
+ nonce,
+ currentCall.to,
+ currentCall.data,
+ callResults[i].returnData
+ );
+ } else {
+ // Note: while the call failed, the nonce will still be incremented,
+ // which will invalidate all supplied signatures.
+ emit CallFailure(
+ actionID,
+ nonce,
+ currentCall.to,
+ currentCall.data,
+ string(callResults[i].returnData)
+ );
+
+ // exit early - any calls after the first failed call will not execute.
+ break;
+ }
+ }
+ }
+
+ /**
+ * @notice Protected function that can only be called from
+ * `executeActionWithAtomicBatchCalls` on this contract. It will attempt to
+ * perform each specified call, populating the array of results as it goes,
+ * unless a failure occurs, at which point it will revert and "return" the
+ * array of results as revert data. Otherwise, it will simply return the array
+ * upon successful completion of each call. Finally, note that this function
+ * must currently be implemented as a public function (instead of as an
+ * external one) due to an ABIEncoderV2 `UnimplementedFeatureError`.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @return An array of structs signifying the status of each call, as well as
+ * any data returned from that call. Calls that are not executed will return
+ * empty data. If any of the calls fail, the array will be returned as revert
+ * data.
+ */
+ function _executeActionWithAtomicBatchCallsAtomic(
+ Call[] memory calls
+ ) public returns (CallReturn[] memory callResults) {
+ // Ensure caller is this contract and self-call context is correctly set.
+ _enforceSelfCallFrom(this.executeActionWithAtomicBatchCalls.selector);
+
+ bool rollBack = false;
+ callResults = new CallReturn[](calls.length);
+
+ for (uint256 i = 0; i < calls.length; i++) {
+ // Perform low-level call and set return values using result.
+ (bool ok, bytes memory returnData) = calls[i].to.call(calls[i].data);
+ callResults[i] = CallReturn({ok: ok, returnData: returnData});
+ if (!ok) {
+ // Exit early - any calls after the first failed call will not execute.
+ rollBack = true;
+ break;
+ }
+ }
+
+ if (rollBack) {
+ // Wrap in length encoding and revert (provide data instead of a string).
+ bytes memory callResultsBytes = abi.encode(callResults);
+ assembly { revert(add(32, callResultsBytes), mload(callResultsBytes)) }
+ }
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for a given generic atomic batch action. The
+ * current nonce will be used, which means that it will only be valid for the
+ * next action taken. Finally, note that this function must currently be
+ * implemented as a public function (instead of as an external one) due to an
+ * ABIEncoderV2 `UnimplementedFeatureError`.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getNextGenericAtomicBatchActionID(
+ Call[] memory calls,
+ uint256 minimumActionGas
+ ) public view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ ActionType.GenericAtomicBatch,
+ abi.encode(calls),
+ _nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice View function that, given an action type and arguments, will return
+ * the action ID or message hash that will need to be prefixed (according to
+ * EIP-191 0x45), hashed, and signed by both the user signing key and by the
+ * key returned for this smart wallet by the Dharma Key Registry in order to
+ * construct a valid signature for a given generic atomic batch action. Any
+ * nonce value may be supplied, which enables constructing valid message
+ * hashes for multiple future actions ahead of time. Finally, note that this
+ * function must currently be implemented as a public function (instead of as
+ * an external one) due to an ABIEncoderV2 `UnimplementedFeatureError`.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @param calls Call[] A struct containing the target and calldata to provide
+ * when making each call.
+ * @param nonce uint256 The nonce to use.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function getGenericAtomicBatchActionID(
+ Call[] memory calls,
+ uint256 nonce,
+ uint256 minimumActionGas
+ ) public view returns (bytes32 actionID) {
+ // Determine the actionID - this serves as a signature hash for an action.
+ actionID = _getActionID(
+ ActionType.GenericAtomicBatch,
+ abi.encode(calls),
+ nonce,
+ minimumActionGas,
+ _userSigningKey,
+ _getDharmaSigningKey()
+ );
+ }
+
+ /**
+ * @notice Internal function for setting a new user signing key. Called by the
+ * initializer, by the `setUserSigningKey` function, and by the `recover`
+ * function. A `NewUserSigningKey` event will also be emitted.
+ * @param userSigningKey address The new user signing key to set on this smart
+ * wallet.
+ */
+ function _setUserSigningKey(address userSigningKey) internal {
+ // Ensure that a user signing key is set on this smart wallet.
+ require(userSigningKey != address(0), _revertReason(14));
+
+ _userSigningKey = userSigningKey;
+ emit NewUserSigningKey(userSigningKey);
+ }
+
+ /**
+ * @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 _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.
+ if (saiToSwap > allowance) {
+ // Approve migrator contract to transfer Sai on behalf of this wallet.
+ require(
+ _SAI.approve(address(_MIGRATOR), uint256(-1)), _revertReason(15)
+ );
+ }
+
+ // Get the current Dai balance on this contract.
+ uint256 currentDaiBalance = _DAI.balanceOf(address(this));
+
+ // 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, _revertReason(16));
+ } else {
+ // Explicitly specify a change in balance of zero if no swap occurred.
+ dai = 0;
+ }
+ }
+
+ /**
+ * @notice Internal function for setting the allowance of a given ERC20 asset
+ * to the maximum value. This enables the corresponding dToken for the asset
+ * to pull in tokens in order to make deposits.
+ * @param asset uint256 The ID of the asset, either Dai (0) or USDC (1).
+ * @return True if the approval succeeded, otherwise false.
+ */
+ function _setFullApproval(AssetType asset) internal returns (bool ok) {
+ // Get asset's underlying token address and corresponding dToken address.
+ address token;
+ address dToken;
+ if (asset == AssetType.DAI) {
+ token = address(_DAI);
+ dToken = address(_DDAI);
+ } else {
+ token = address(_USDC);
+ dToken = address(_DUSDC);
+ }
+
+ // Approve dToken contract to transfer underlying on behalf of this wallet.
+ (ok, ) = address(token).call(abi.encodeWithSelector(
+ // Note: since both Tokens have the same interface, just use DAI's.
+ _DAI.approve.selector, dToken, uint256(-1)
+ ));
+
+ // Emit a corresponding event if the approval failed.
+ if (!ok) {
+ if (asset == AssetType.DAI) {
+ emit ExternalError(address(_DAI), _revertReason(17));
+ } else {
+ // Find out why USDC transfer reverted (it doesn't give revert reasons).
+ _diagnoseAndEmitUSDCSpecificError(_USDC.approve.selector);
+ }
+ }
+ }
+
+ /**
+ * @notice Internal function for depositing a given ERC20 asset and balance on
+ * the corresponding dToken. No value is returned, as no additional steps need
+ * to be conditionally performed after the deposit.
+ * @param asset uint256 The ID of the asset, either Dai (0) or USDC (1).
+ * @param balance uint256 The amount of the asset to deposit. Note that an
+ * attempt to deposit "dust" (i.e. very small amounts) may result in fewer
+ * dTokens being minted than is implied by the current exchange rate due to a
+ * lack of sufficient precision on the tokens in question.
+ */
+ function _depositDharmaToken(AssetType asset, uint256 balance) internal {
+ // Only perform a deposit if the balance is at least .001 Dai or USDC.
+ if (
+ asset == AssetType.DAI && balance > _JUST_UNDER_ONE_1000th_DAI ||
+ asset == AssetType.USDC && balance > _JUST_UNDER_ONE_1000th_USDC
+ ) {
+ // Get dToken address for the asset type.
+ address dToken = asset == AssetType.DAI ? address(_DDAI) : address(_DUSDC);
+
+ // Attempt to mint the balance on the dToken contract.
+ (bool ok, bytes memory data) = dToken.call(abi.encodeWithSelector(
+ // Note: since both dTokens have the same interface, just use dDai's.
+ _DDAI.mint.selector, balance
+ ));
+
+ // Log an external error if something went wrong with the attempt.
+ _checkDharmaTokenInteractionAndLogAnyErrors(
+ asset, _DDAI.mint.selector, ok, data
+ );
+ }
+ }
+
+ /**
+ * @notice Internal function for withdrawing a given underlying asset balance
+ * from the corresponding dToken. Note that the requested balance may not be
+ * currently available on Compound, which will cause the withdrawal to fail.
+ * @param asset uint256 The asset's ID, either Dai (0) or USDC (1).
+ * @param balance uint256 The amount of the asset to withdraw, denominated in
+ * the underlying token. Note that an attempt to withdraw "dust" (i.e. very
+ * small amounts) may result in 0 underlying tokens being redeemed, or in
+ * fewer tokens being redeemed than is implied by the current exchange rate
+ * (due to lack of sufficient precision on the tokens).
+ * @return True if the withdrawal succeeded, otherwise false.
+ */
+ function _withdrawFromDharmaToken(
+ AssetType asset, uint256 balance
+ ) internal returns (bool success) {
+ // Get dToken address for the asset type. (No custom ETH withdrawal action.)
+ address dToken = asset == AssetType.DAI ? address(_DDAI) : address(_DUSDC);
+
+ // Attempt to redeem the underlying balance from the dToken contract.
+ (bool ok, bytes memory data) = dToken.call(abi.encodeWithSelector(
+ // Note: function selector is the same for each dToken so just use dDai's.
+ _DDAI.redeemUnderlying.selector, balance
+ ));
+
+ // Log an external error if something went wrong with the attempt.
+ success = _checkDharmaTokenInteractionAndLogAnyErrors(
+ asset, _DDAI.redeemUnderlying.selector, ok, data
+ );
+ }
+
+ /**
+ * @notice Internal function for withdrawing the total underlying asset
+ * balance from the corresponding dToken. Note that the requested balance may
+ * not be currently available on Compound, which will cause the withdrawal to
+ * fail.
+ * @param asset uint256 The asset's ID, either Dai (0) or USDC (1).
+ */
+ function _withdrawMaxFromDharmaToken(AssetType asset) internal {
+ // Get dToken address for the asset type. (No custom ETH withdrawal action.)
+ address dToken = asset == AssetType.DAI ? address(_DDAI) : address(_DUSDC);
+
+ // Try to retrieve the current dToken balance for this account.
+ IERC20 dTokenBalance;
+ (bool ok, bytes memory data) = dToken.call(abi.encodeWithSelector(
+ dTokenBalance.balanceOf.selector, address(this)
+ ));
+
+ uint256 redeemAmount = 0;
+ if (ok && data.length == 32) {
+ redeemAmount = abi.decode(data, (uint256));
+ } else {
+ // Something went wrong with the balance check - log an ExternalError.
+ _checkDharmaTokenInteractionAndLogAnyErrors(
+ asset, dTokenBalance.balanceOf.selector, ok, data
+ );
+ }
+
+ // Only perform the call to redeem if there is a non-zero balance.
+ if (redeemAmount > 0) {
+ // Attempt to redeem the underlying balance from the dToken contract.
+ (ok, data) = dToken.call(abi.encodeWithSelector(
+ // Function selector is the same for all dTokens, so just use dDai's.
+ _DDAI.redeem.selector, redeemAmount
+ ));
+
+ // Log an external error if something went wrong with the attempt.
+ _checkDharmaTokenInteractionAndLogAnyErrors(
+ asset, _DDAI.redeem.selector, ok, data
+ );
+ }
+ }
+
+ /**
+ * @notice Internal function for transferring the total underlying balance of
+ * the corresponding token to a designated recipient. It will return true if
+ * tokens were successfully transferred (or there is no balance), signified by
+ * the boolean returned by the transfer function, or the call status if the
+ * `suppressRevert` boolean is set to true.
+ * @param token IERC20 The interface of the token in question.
+ * @param recipient address The account that will receive the tokens.
+ * @param suppressRevert bool A boolean indicating whether reverts should be
+ * suppressed or not. Used by the escape hatch so that a problematic transfer
+ * will not block the rest of the call from executing.
+ * @return True if tokens were successfully transferred or if there is no
+ * balance, else false.
+ */
+ function _transferMax(
+ IERC20 token, address recipient, bool suppressRevert
+ ) internal returns (bool success) {
+ // Get the current balance on the smart wallet for the supplied ERC20 token.
+ uint256 balance = 0;
+ bool balanceCheckWorked = true;
+ if (!suppressRevert) {
+ balance = token.balanceOf(address(this));
+ } else {
+ // Try to retrieve current token balance for this account with 1/2 gas.
+ (bool ok, bytes memory data) = address(token).call.gas(gasleft() / 2)(
+ abi.encodeWithSelector(token.balanceOf.selector, address(this))
+ );
+
+ if (ok && data.length == 32) {
+ balance = abi.decode(data, (uint256));
+ } else {
+ // Something went wrong with the balance check.
+ balanceCheckWorked = false;
+ }
+ }
+
+ // Only perform the call to transfer if there is a non-zero balance.
+ if (balance > 0) {
+ if (!suppressRevert) {
+ // Perform the transfer and pass along the returned boolean (or revert).
+ success = token.transfer(recipient, balance);
+ } else {
+ // Attempt transfer with 1/2 gas, allow reverts, and return call status.
+ (success, ) = address(token).call.gas(gasleft() / 2)(
+ abi.encodeWithSelector(token.transfer.selector, recipient, balance)
+ );
+ }
+ } else {
+ // Skip the transfer and return true as long as the balance check worked.
+ success = balanceCheckWorked;
+ }
+ }
+
+ /**
+ * @notice Internal function for transferring Ether to a designated recipient.
+ * It will return true and emit an `EthWithdrawal` event if Ether was
+ * successfully transferred - otherwise, it will return false and emit an
+ * `ExternalError` event.
+ * @param recipient address payable The account that will receive the Ether.
+ * @param amount uint256 The amount of Ether to transfer.
+ * @return True if Ether was successfully transferred, else false.
+ */
+ function _transferETH(
+ address payable recipient, uint256 amount
+ ) internal returns (bool success) {
+ // Attempt to transfer any Ether to caller and emit an event if it fails.
+ (success, ) = recipient.call.gas(_ETH_TRANSFER_GAS).value(amount)("");
+ if (!success) {
+ emit ExternalError(recipient, _revertReason(18));
+ } else {
+ emit EthWithdrawal(amount, recipient);
+ }
+ }
+
+ /**
+ * @notice Internal function for validating supplied gas (if specified),
+ * retrieving the signer's public key from the Dharma Key Registry, deriving
+ * the action ID, validating the provided caller and/or signatures using that
+ * action ID, and incrementing the nonce. This function serves as the
+ * entrypoint for all protected "actions" on the smart wallet, and is the only
+ * area where these functions should revert (other than due to out-of-gas
+ * errors, which can be guarded against by supplying a minimum action gas
+ * requirement).
+ * @param action uint8 The type of action, designated by it's index. Valid
+ * actions in V7 include Cancel (0), SetUserSigningKey (1), Generic (2),
+ * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5),
+ * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and
+ * DisableEscapeHatch (9).
+ * @param arguments bytes ABI-encoded arguments for the action.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used. A unique hash returned from `getCustomActionID` is prefixed
+ * and hashed to create the message hash for the signature.
+ * @param dharmaSignature bytes A signature that resolves to the public key
+ * returned for this account from the Dharma Key Registry. A unique hash
+ * returned from `getCustomActionID` is prefixed and hashed to create the
+ * signed message.
+ * @return The nonce of the current action (prior to incrementing it).
+ */
+ function _validateActionAndIncrementNonce(
+ ActionType action,
+ bytes memory arguments,
+ uint256 minimumActionGas,
+ bytes memory userSignature,
+ bytes memory dharmaSignature
+ ) internal returns (bytes32 actionID, uint256 actionNonce) {
+ // Ensure that the current gas exceeds the minimum required action gas.
+ // This prevents griefing attacks where an attacker can invalidate a
+ // signature without providing enough gas for the action to succeed. Also
+ // note that some gas will be spent before this check is reached - supplying
+ // ~30,000 additional gas should suffice when submitting transactions. To
+ // skip this requirement, supply zero for the minimumActionGas argument.
+ if (minimumActionGas != 0) {
+ require(gasleft() >= minimumActionGas, _revertReason(19));
+ }
+
+ // Get the current nonce for the action to be performed.
+ actionNonce = _nonce;
+
+ // Get the user signing key that will be used to verify their signature.
+ address userSigningKey = _userSigningKey;
+
+ // Get the Dharma signing key that will be used to verify their signature.
+ address dharmaSigningKey = _getDharmaSigningKey();
+
+ // Determine the actionID - this serves as the signature hash.
+ actionID = _getActionID(
+ action,
+ arguments,
+ actionNonce,
+ minimumActionGas,
+ userSigningKey,
+ dharmaSigningKey
+ );
+
+ // Compute the message hash - the hashed, EIP-191-0x45-prefixed action ID.
+ bytes32 messageHash = actionID.toEthSignedMessageHash();
+
+ // Actions other than Cancel require both signatures; Cancel only needs one.
+ if (action != ActionType.Cancel) {
+ // Validate user signing key signature unless it is `msg.sender`.
+ if (msg.sender != userSigningKey) {
+ require(
+ _validateUserSignature(
+ messageHash, action, arguments, userSigningKey, userSignature
+ ),
+ _revertReason(20)
+ );
+ }
+
+ // Validate Dharma signing key signature unless it is `msg.sender`.
+ if (msg.sender != dharmaSigningKey) {
+ require(
+ dharmaSigningKey == messageHash.recover(dharmaSignature),
+ _revertReason(21)
+ );
+ }
+ } else {
+ // Validate signing key signature unless user or Dharma is `msg.sender`.
+ if (msg.sender != userSigningKey && msg.sender != dharmaSigningKey) {
+ require(
+ dharmaSigningKey == messageHash.recover(dharmaSignature) ||
+ _validateUserSignature(
+ messageHash, action, arguments, userSigningKey, userSignature
+ ),
+ _revertReason(22)
+ );
+ }
+ }
+
+ // Increment nonce in order to prevent reuse of signatures after the call.
+ _nonce++;
+ }
+
+ /**
+ * @notice Use all available cTokens to mint the respective dTokens. If any
+ * step in the process fails, the call will revert and prior steps will be
+ * rolled back. Also note that existing underlying tokens are not included as
+ * part of this operation.
+ */
+ function _migrateCTokenToDToken(AssetType token) internal {
+ CTokenInterface cToken;
+ DTokenInterface dToken;
+
+ if (token == AssetType.DAI) {
+ cToken = _CDAI;
+ dToken = _DDAI;
+ } else {
+ cToken = _CUSDC;
+ dToken = _DUSDC;
+ }
+
+ // Get the current cToken balance for this account.
+ uint256 balance = cToken.balanceOf(address(this));
+
+ // Only perform the conversion if there is a non-zero balance.
+ if (balance > 0) {
+ // If the allowance is insufficient, set it before depositing.
+ if (cToken.allowance(address(this), address(dToken)) < balance) {
+ require(cToken.approve(address(dToken), uint256(-1)), _revertReason(23));
+ }
+
+ // Deposit the new balance on the Dharma Token.
+ require(dToken.mintViaCToken(balance) > 0, _revertReason(24));
+ }
+ }
+
+ /**
+ * @notice Internal function to determine whether a call to a given dToken
+ * succeeded, and to emit a relevant ExternalError event if it failed.
+ * @param asset uint256 The ID of the asset, either Dai (0) or USDC (1).
+ * @param functionSelector bytes4 The function selector that was called on the
+ * corresponding dToken of the asset type.
+ * @param ok bool A boolean representing whether the call returned or
+ * reverted.
+ * @param data bytes The data provided by the returned or reverted call.
+ * @return True if the interaction was successful, otherwise false. This will
+ * be used to determine if subsequent steps in the action should be attempted
+ * or not, specifically a transfer following a withdrawal.
+ */
+ function _checkDharmaTokenInteractionAndLogAnyErrors(
+ AssetType asset,
+ bytes4 functionSelector,
+ bool ok,
+ bytes memory data
+ ) internal returns (bool success) {
+ // Log an external error if something went wrong with the attempt.
+ if (ok) {
+ if (data.length == 32) {
+ uint256 amount = abi.decode(data, (uint256));
+ if (amount > 0) {
+ success = true;
+ } else {
+ // Get called contract address, name of contract, and function name.
+ (address account, string memory name, string memory functionName) = (
+ _getDharmaTokenDetails(asset, functionSelector)
+ );
+
+ emit ExternalError(
+ account,
+ string(
+ abi.encodePacked(
+ name,
+ " contract did not provide any tokens when calling ",
+ functionName,
+ "."
+ )
+ )
+ );
+ }
+ } else {
+ // Get called contract address, name of contract, and function name.
+ (address account, string memory name, string memory functionName) = (
+ _getDharmaTokenDetails(asset, functionSelector)
+ );
+
+ emit ExternalError(
+ account,
+ string(
+ abi.encodePacked(
+ name,
+ " contract returned malformed data while attempting to call ",
+ functionName,
+ "."
+ )
+ )
+ );
+ }
+
+ } else {
+ // Get called contract address, name of contract, and function name.
+ (address account, string memory name, string memory functionName) = (
+ _getDharmaTokenDetails(asset, functionSelector)
+ );
+
+ // Decode the revert reason in the event one was returned.
+ string memory revertReason = _decodeRevertReason(data);
+
+ emit ExternalError(
+ account,
+ string(
+ abi.encodePacked(
+ name,
+ " contract reverted while attempting to call ",
+ functionName,
+ ": ",
+ revertReason
+ )
+ )
+ );
+ }
+ }
+
+ /**
+ * @notice Internal function to diagnose the reason that a call to the USDC
+ * contract failed and to emit a corresponding ExternalError event. USDC can
+ * blacklist accounts and pause the contract, which can both cause a transfer
+ * or approval to fail.
+ * @param functionSelector bytes4 The function selector that was called on the
+ * USDC contract.
+ */
+ function _diagnoseAndEmitUSDCSpecificError(bytes4 functionSelector) internal {
+ // Determine the name of the function that was called on USDC.
+ string memory functionName;
+ if (functionSelector == _USDC.transfer.selector) {
+ functionName = "transfer";
+ } else {
+ functionName = "approve";
+ }
+
+ // Find out why USDC transfer reverted (it doesn't give revert reasons).
+ if (_USDC_NAUGHTY.isBlacklisted(address(this))) {
+ emit ExternalError(
+ address(_USDC),
+ string(
+ abi.encodePacked(
+ functionName, " failed - USDC has blacklisted this user."
+ )
+ )
+ );
+ } else { // Note: `else if` breaks coverage.
+ if (_USDC_NAUGHTY.paused()) {
+ emit ExternalError(
+ address(_USDC),
+ string(
+ abi.encodePacked(
+ functionName, " failed - USDC contract is currently paused."
+ )
+ )
+ );
+ } else {
+ emit ExternalError(
+ address(_USDC),
+ string(
+ abi.encodePacked(
+ "USDC contract reverted on ", functionName, "."
+ )
+ )
+ );
+ }
+ }
+ }
+
+ /**
+ * @notice Internal function to ensure that protected functions can only be
+ * called from this contract and that they have the appropriate context set.
+ * The self-call context is then cleared. It is used as an additional guard
+ * against reentrancy, especially once generic actions are supported by the
+ * smart wallet in future versions.
+ * @param selfCallContext bytes4 The expected self-call context, equal to the
+ * function selector of the approved calling function.
+ */
+ function _enforceSelfCallFrom(bytes4 selfCallContext) internal {
+ // Ensure caller is this contract and self-call context is correctly set.
+ require(
+ msg.sender == address(this) && _selfCallContext == selfCallContext,
+ _revertReason(25)
+ );
+
+ // Clear the self-call context.
+ delete _selfCallContext;
+ }
+
+ /**
+ * @notice Internal view function for validating a user's signature. If the
+ * user's signing key does not have contract code, it will be validated via
+ * ecrecover; otherwise, it will be validated using ERC-1271, passing the
+ * message hash that was signed, the action type, and the arguments as data.
+ * @param messageHash bytes32 The message hash that is signed by the user. It
+ * is derived by prefixing (according to EIP-191 0x45) and hashing an actionID
+ * returned from `getCustomActionID`.
+ * @param action uint8 The type of action, designated by it's index. Valid
+ * actions in V7 include Cancel (0), SetUserSigningKey (1), Generic (2),
+ * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5),
+ * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and
+ * DisableEscapeHatch (9).
+ * @param arguments bytes ABI-encoded arguments for the action.
+ * @param userSignature bytes A signature that resolves to the public key
+ * set for this account in storage slot zero, `_userSigningKey`. If the user
+ * signing key is not a contract, ecrecover will be used; otherwise, ERC1271
+ * will be used.
+ * @return A boolean representing the validity of the supplied user signature.
+ */
+ function _validateUserSignature(
+ bytes32 messageHash,
+ ActionType action,
+ bytes memory arguments,
+ address userSigningKey,
+ bytes memory userSignature
+ ) internal view returns (bool valid) {
+ if (!userSigningKey.isContract()) {
+ valid = userSigningKey == messageHash.recover(userSignature);
+ } else {
+ bytes memory data = abi.encode(messageHash, action, arguments);
+ valid = (
+ ERC1271(userSigningKey).isValidSignature(
+ data, userSignature
+ ) == _ERC_1271_MAGIC_VALUE
+ );
+ }
+ }
+
+ /**
+ * @notice Internal view function to get the Dharma signing key for the smart
+ * wallet from the Dharma Key Registry. This key can be set for each specific
+ * smart wallet - if none has been set, a global fallback key will be used.
+ * @return The address of the Dharma signing key, or public key corresponding
+ * to the secondary signer.
+ */
+ function _getDharmaSigningKey() internal view returns (
+ address dharmaSigningKey
+ ) {
+ dharmaSigningKey = _DHARMA_KEY_REGISTRY.getKey();
+ }
+
+ /**
+ * @notice Internal view function that, given an action type and arguments,
+ * will return the action ID or message hash that will need to be prefixed
+ * (according to EIP-191 0x45), hashed, and signed by the key designated by
+ * the Dharma Key Registry in order to construct a valid signature for the
+ * corresponding action. The current nonce will be supplied to this function
+ * when reconstructing an action ID during protected function execution based
+ * on the supplied parameters.
+ * @param action uint8 The type of action, designated by it's index. Valid
+ * actions in V7 include Cancel (0), SetUserSigningKey (1), Generic (2),
+ * GenericAtomicBatch (3), DAIWithdrawal (10), USDCWithdrawal (5),
+ * ETHWithdrawal (6), SetEscapeHatch (7), RemoveEscapeHatch (8), and
+ * DisableEscapeHatch (9).
+ * @param arguments bytes ABI-encoded arguments for the action.
+ * @param nonce uint256 The nonce to use.
+ * @param minimumActionGas uint256 The minimum amount of gas that must be
+ * provided to this call - be aware that additional gas must still be included
+ * to account for the cost of overhead incurred up until the start of this
+ * function call.
+ * @param dharmaSigningKey address The address of the secondary key, or public
+ * key corresponding to the secondary signer.
+ * @return The action ID, which will need to be prefixed, hashed and signed in
+ * order to construct a valid signature.
+ */
+ function _getActionID(
+ ActionType action,
+ bytes memory arguments,
+ uint256 nonce,
+ uint256 minimumActionGas,
+ address userSigningKey,
+ address dharmaSigningKey
+ ) internal view returns (bytes32 actionID) {
+ // actionID is constructed according to EIP-191-0x45 to prevent replays.
+ actionID = keccak256(
+ abi.encodePacked(
+ address(this),
+ _DHARMA_SMART_WALLET_VERSION,
+ userSigningKey,
+ dharmaSigningKey,
+ nonce,
+ minimumActionGas,
+ action,
+ arguments
+ )
+ );
+ }
+
+ /**
+ * @notice Internal pure function to get the dToken address, it's name, and
+ * the name of the called function, based on a supplied asset type and
+ * function selector. It is used to help construct ExternalError events.
+ * @param asset uint256 The ID of the asset, either Dai (0) or USDC (1).
+ * @param functionSelector bytes4 The function selector that was called on the
+ * corresponding dToken of the asset type.
+ * @return The dToken address, it's name, and the name of the called function.
+ */
+ function _getDharmaTokenDetails(
+ AssetType asset,
+ bytes4 functionSelector
+ ) internal pure returns (
+ address account,
+ string memory name,
+ string memory functionName
+ ) {
+ if (asset == AssetType.DAI) {
+ account = address(_DDAI);
+ name = "Dharma Dai";
+ } else {
+ account = address(_DUSDC);
+ name = "Dharma USD Coin";
+ }
+
+ // Note: since both dTokens have the same interface, just use dDai's.
+ if (functionSelector == _DDAI.mint.selector) {
+ functionName = "mint";
+ } else {
+ if (functionSelector == IERC20(account).balanceOf.selector) {
+ functionName = "balanceOf";
+ } else {
+ functionName = string(abi.encodePacked(
+ "redeem",
+ functionSelector == _DDAI.redeem.selector ? "" : "Underlying"
+ ));
+ }
+ }
+ }
+
+ /**
+ * @notice Internal view function to ensure that a given `to` address provided
+ * as part of a generic action is valid. Calls cannot be performed to accounts
+ * without code or back into the smart wallet itself. Additionally, generic
+ * calls cannot supply the address of the Dharma Escape Hatch registry - the
+ * specific, designated functions must be used in order to make calls into it.
+ * @param to address The address that will be targeted by the generic call.
+ */
+ function _ensureValidGenericCallTarget(address to) internal view {
+ require(to.isContract(), _revertReason(26));
+
+ require(to != address(this), _revertReason(27));
+
+ require(to != address(_ESCAPE_HATCH_REGISTRY), _revertReason(28));
+ }
+
+ /**
+ * @notice Internal pure function to ensure that a given action type is a
+ * "custom" action type (i.e. is not a generic action type) and to construct
+ * 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 V7 include Cancel (0), SetUserSigningKey (1),
+ * 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.
+ * @param recipient address The account to transfer withdrawn funds to or the
+ * new user signing key. This value is ignored for Cancel, RemoveEscapeHatch,
+ * and DisableEscapeHatch action types.
+ * @return A bytes array containing the arguments that will be provided as
+ * a component of the inputs when constructing a custom action ID.
+ */
+ function _validateCustomActionTypeAndGetArguments(
+ ActionType action, uint256 amount, address recipient
+ ) internal pure returns (bytes memory arguments) {
+ // Ensure that the action type is a valid custom action type.
+ require(
+ action == ActionType.Cancel ||
+ action == ActionType.SetUserSigningKey ||
+ action == ActionType.DAIWithdrawal ||
+ action == ActionType.USDCWithdrawal ||
+ action == ActionType.ETHWithdrawal ||
+ action == ActionType.SetEscapeHatch ||
+ action == ActionType.RemoveEscapeHatch ||
+ action == ActionType.DisableEscapeHatch,
+ _revertReason(29)
+ );
+
+ // Use action type to determine parameters to include in returned arguments.
+ if (
+ action == ActionType.Cancel ||
+ action == ActionType.RemoveEscapeHatch ||
+ action == ActionType.DisableEscapeHatch
+ ) {
+ // Ignore parameters for Cancel, RemoveEscapeHatch, or DisableEscapeHatch.
+ arguments = abi.encode();
+ } else if (
+ action == ActionType.SetUserSigningKey ||
+ action == ActionType.SetEscapeHatch
+ ) {
+ // Ignore `amount` parameter for other, non-withdrawal actions.
+ arguments = abi.encode(recipient);
+ } else {
+ // Use both `amount` and `recipient` parameters for withdrawals.
+ arguments = abi.encode(amount, recipient);
+ }
+ }
+
+ /**
+ * @notice Internal pure function to decode revert reasons. The revert reason
+ * prefix is removed and the remaining string argument is decoded.
+ * @param revertData bytes The raw data supplied alongside the revert.
+ * @return The decoded revert reason string.
+ */
+ function _decodeRevertReason(
+ bytes memory revertData
+ ) internal pure returns (string memory revertReason) {
+ // Solidity prefixes revert reason with 0x08c379a0 -> Error(string) selector
+ if (
+ revertData.length > 68 && // prefix (4) + position (32) + length (32)
+ revertData[0] == byte(0x08) &&
+ revertData[1] == byte(0xc3) &&
+ revertData[2] == byte(0x79) &&
+ revertData[3] == byte(0xa0)
+ ) {
+ // Get the revert reason without the prefix from the revert data.
+ bytes memory revertReasonBytes = new bytes(revertData.length - 4);
+ for (uint256 i = 4; i < revertData.length; i++) {
+ revertReasonBytes[i - 4] = revertData[i];
+ }
+
+ // Decode the resultant revert reason as a string.
+ revertReason = abi.decode(revertReasonBytes, (string));
+ } else {
+ // Simply return the default, with no revert reason.
+ revertReason = _revertReason(uint256(-1));
+ }
+ }
+
+ /**
+ * @notice Internal pure function call the revert reason helper contract,
+ * supplying a revert "code" and receiving back a revert reason string.
+ * @param code uint256 The code for the revert reason.
+ * @return The revert reason string.
+ */
+ function _revertReason(
+ uint256 code
+ ) internal pure returns (string memory reason) {
+ reason = _REVERT_REASON_HELPER.reason(code);
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaDaiInitializer.sol b/contracts/implementations/token/DharmaDaiInitializer.sol
new file mode 100644
index 0000000..d723c1f
--- /dev/null
+++ b/contracts/implementations/token/DharmaDaiInitializer.sol
@@ -0,0 +1,70 @@
+pragma solidity 0.5.11;
+
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/ERC20Interface.sol";
+
+
+/**
+ * @title DharmaDaiInitializer
+ * @author 0age
+ * @notice Initializer implementation for the Dharma Dai token.
+ */
+contract DharmaDaiInitializer {
+ event Accrue(uint256 dTokenExchangeRate, uint256 cTokenExchangeRate);
+
+ // The block number and cToken + dToken exchange rates are updated on accrual.
+ struct AccrualIndex {
+ uint112 dTokenExchangeRate;
+ uint112 cTokenExchangeRate;
+ uint32 block;
+ }
+
+ CTokenInterface internal constant _CDAI = CTokenInterface(
+ 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 // mainnet
+ );
+
+ ERC20Interface internal constant _DAI = ERC20Interface(
+ 0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
+ );
+
+ uint256 internal constant _MAX_UINT_112 = 5192296858534827628530496329220095;
+
+ // Set block number and dToken + cToken exchange rate in slot zero on accrual.
+ AccrualIndex private _accrualIndex;
+
+ /**
+ * @notice Initialize Dharma Dai by approving cDai to transfer Dai on behalf
+ * of this contract and setting the initial dDai and cDai exchange rates in
+ * storage.
+ */
+ function initialize() external {
+ // Approve cToken to transfer underlying for this contract in order to mint.
+ require(
+ _DAI.approve(address(_CDAI), uint256(-1)), "Initial cDai approval failed."
+ );
+
+ // Initial dToken exchange rate is 1-to-1 (dTokens have 8 decimals).
+ uint256 dTokenExchangeRate = 1e28;
+
+ // Accrue cToken interest and retrieve the current cToken exchange rate.
+ uint256 cTokenExchangeRate = _CDAI.exchangeRateCurrent();
+
+ // Initialize accrual index with current block number and exchange rates.
+ AccrualIndex storage accrualIndex = _accrualIndex;
+ accrualIndex.dTokenExchangeRate = uint112(dTokenExchangeRate);
+ accrualIndex.cTokenExchangeRate = _safeUint112(cTokenExchangeRate);
+ accrualIndex.block = uint32(block.number);
+ emit Accrue(dTokenExchangeRate, cTokenExchangeRate);
+ }
+
+ /**
+ * @notice Internal pure function to convert a uint256 to a uint112, reverting
+ * if the conversion would cause an overflow.
+ * @param input uint256 The unsigned integer to convert.
+ * @return The converted unsigned integer.
+ */
+ function _safeUint112(uint256 input) internal pure returns (uint112 output) {
+ require(input <= _MAX_UINT_112, "Overflow on conversion to uint112.");
+ output = uint112(input);
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaTokenHelpers.sol b/contracts/implementations/token/DharmaTokenHelpers.sol
new file mode 100644
index 0000000..e812c8a
--- /dev/null
+++ b/contracts/implementations/token/DharmaTokenHelpers.sol
@@ -0,0 +1,237 @@
+pragma solidity 0.5.11;
+
+import "@openzeppelin/contracts/math/SafeMath.sol";
+import "../../../interfaces/CTokenInterface.sol";
+import "./DharmaTokenOverrides.sol";
+
+
+/**
+ * @title DharmaTokenHelpers
+ * @author 0age
+ * @notice A collection of constants and internal pure functions used by Dharma
+ * Tokens.
+ */
+contract DharmaTokenHelpers is DharmaTokenOverrides {
+ using SafeMath for uint256;
+
+ uint8 internal constant _DECIMALS = 8; // matches cToken decimals
+ uint256 internal constant _SCALING_FACTOR = 1e18;
+ uint256 internal constant _SCALING_FACTOR_MINUS_ONE = 999999999999999999;
+ uint256 internal constant _HALF_OF_SCALING_FACTOR = 5e17;
+ uint256 internal constant _COMPOUND_SUCCESS = 0;
+ uint256 internal constant _MAX_UINT_112 = 5192296858534827628530496329220095;
+ uint256 internal constant _MAX_UNMALLEABLE_S = (
+ 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
+ );
+
+ /**
+ * @notice Internal pure function to determine if a call to Compound succeeded
+ * and to revert, supplying the reason, if it failed. Failure can be caused by
+ * a call that reverts, or by a call that does not revert but returns a
+ * non-zero error code.
+ * @param functionSelector bytes4 The function selector that was called.
+ * @param ok bool A boolean representing whether the call returned or
+ * reverted.
+ * @param data bytes The data provided by the returned or reverted call.
+ */
+ function _checkCompoundInteraction(
+ bytes4 functionSelector, bool ok, bytes memory data
+ ) internal pure {
+ CTokenInterface cToken;
+ if (ok) {
+ if (
+ functionSelector == cToken.transfer.selector ||
+ functionSelector == cToken.transferFrom.selector
+ ) {
+ require(
+ abi.decode(data, (bool)), string(
+ abi.encodePacked(
+ "Compound ",
+ _getCTokenSymbol(),
+ " contract returned false on calling ",
+ _getFunctionName(functionSelector),
+ "."
+ )
+ )
+ );
+ } else {
+ uint256 compoundError = abi.decode(data, (uint256)); // throw on no data
+ if (compoundError != _COMPOUND_SUCCESS) {
+ revert(
+ string(
+ abi.encodePacked(
+ "Compound ",
+ _getCTokenSymbol(),
+ " contract returned error code ",
+ uint8((compoundError / 10) + 48),
+ uint8((compoundError % 10) + 48),
+ " on calling ",
+ _getFunctionName(functionSelector),
+ "."
+ )
+ )
+ );
+ }
+ }
+ } else {
+ revert(
+ string(
+ abi.encodePacked(
+ "Compound ",
+ _getCTokenSymbol(),
+ " contract reverted while attempting to call ",
+ _getFunctionName(functionSelector),
+ ": ",
+ _decodeRevertReason(data)
+ )
+ )
+ );
+ }
+ }
+
+ /**
+ * @notice Internal pure function to get a Compound function name based on the
+ * selector.
+ * @param functionSelector bytes4 The function selector.
+ * @return The name of the function as a string.
+ */
+ function _getFunctionName(
+ bytes4 functionSelector
+ ) internal pure returns (string memory functionName) {
+ CTokenInterface cToken;
+ if (functionSelector == cToken.mint.selector) {
+ functionName = "mint";
+ } else if (functionSelector == cToken.redeem.selector) {
+ functionName = "redeem";
+ } else if (functionSelector == cToken.redeemUnderlying.selector) {
+ functionName = "redeemUnderlying";
+ } else if (functionSelector == cToken.transferFrom.selector) {
+ functionName = "transferFrom";
+ } else if (functionSelector == cToken.transfer.selector) {
+ functionName = "transfer";
+ } else if (functionSelector == cToken.accrueInterest.selector) {
+ functionName = "accrueInterest";
+ } else {
+ functionName = "an unknown function";
+ }
+ }
+
+ /**
+ * @notice Internal pure function to decode revert reasons. The revert reason
+ * prefix is removed and the remaining string argument is decoded.
+ * @param revertData bytes The raw data supplied alongside the revert.
+ * @return The decoded revert reason string.
+ */
+ function _decodeRevertReason(
+ bytes memory revertData
+ ) internal pure returns (string memory revertReason) {
+ // Solidity prefixes revert reason with 0x08c379a0 -> Error(string) selector
+ if (
+ revertData.length > 68 && // prefix (4) + position (32) + length (32)
+ revertData[0] == byte(0x08) &&
+ revertData[1] == byte(0xc3) &&
+ revertData[2] == byte(0x79) &&
+ revertData[3] == byte(0xa0)
+ ) {
+ // Get the revert reason without the prefix from the revert data.
+ bytes memory revertReasonBytes = new bytes(revertData.length - 4);
+ for (uint256 i = 4; i < revertData.length; i++) {
+ revertReasonBytes[i - 4] = revertData[i];
+ }
+
+ // Decode the resultant revert reason as a string.
+ revertReason = abi.decode(revertReasonBytes, (string));
+ } else {
+ // Simply return the default, with no revert reason.
+ revertReason = "(no revert reason)";
+ }
+ }
+
+ /**
+ * @notice Internal pure function to construct a failure message string for
+ * the revert reason on transfers of underlying tokens that do not succeed.
+ * @return The failure message.
+ */
+ function _getTransferFailureMessage() internal pure returns (
+ string memory message
+ ) {
+ message = string(
+ abi.encodePacked(_getUnderlyingName(), " transfer failed.")
+ );
+ }
+
+ /**
+ * @notice Internal pure function to convert a uint256 to a uint112, reverting
+ * if the conversion would cause an overflow.
+ * @param input uint256 The unsigned integer to convert.
+ * @return The converted unsigned integer.
+ */
+ function _safeUint112(uint256 input) internal pure returns (uint112 output) {
+ require(input <= _MAX_UINT_112, "Overflow on conversion to uint112.");
+ output = uint112(input);
+ }
+
+ /**
+ * @notice Internal pure function to convert an underlying amount to a dToken
+ * or cToken amount using an exchange rate and fixed-point arithmetic.
+ * @param underlying uint256 The underlying amount to convert.
+ * @param exchangeRate uint256 The exchange rate (multiplied by 10^18).
+ * @param roundUp bool Whether the final amount should be rounded up - it will
+ * instead be truncated (rounded down) if this value is false.
+ * @return The cToken or dToken amount.
+ */
+ function _fromUnderlying(
+ uint256 underlying, uint256 exchangeRate, bool roundUp
+ ) internal pure returns (uint256 amount) {
+ if (roundUp) {
+ amount = (
+ (underlying.mul(_SCALING_FACTOR)).add(exchangeRate.sub(1))
+ ).div(exchangeRate);
+ } else {
+ amount = (underlying.mul(_SCALING_FACTOR)).div(exchangeRate);
+ }
+ }
+
+ /**
+ * @notice Internal pure function to convert a dToken or cToken amount to the
+ * underlying amount using an exchange rate and fixed-point arithmetic.
+ * @param amount uint256 The cToken or dToken amount to convert.
+ * @param exchangeRate uint256 The exchange rate (multiplied by 10^18).
+ * @param roundUp bool Whether the final amount should be rounded up - it will
+ * instead be truncated (rounded down) if this value is false.
+ * @return The underlying amount.
+ */
+ function _toUnderlying(
+ uint256 amount, uint256 exchangeRate, bool roundUp
+ ) internal pure returns (uint256 underlying) {
+ if (roundUp) {
+ underlying = (
+ (amount.mul(exchangeRate).add(_SCALING_FACTOR_MINUS_ONE)
+ ) / _SCALING_FACTOR);
+ } else {
+ underlying = amount.mul(exchangeRate) / _SCALING_FACTOR;
+ }
+ }
+
+ /**
+ * @notice Internal pure function to convert an underlying amount to a dToken
+ * or cToken amount and back to the underlying, so as to properly capture
+ * rounding errors, by using an exchange rate and fixed-point arithmetic.
+ * @param underlying uint256 The underlying amount to convert.
+ * @param exchangeRate uint256 The exchange rate (multiplied by 10^18).
+ * @param roundUpOne bool Whether the intermediate dToken or cToken amount
+ * should be rounded up - it will instead be truncated (rounded down) if this
+ * value is false.
+ * @param roundUpTwo bool Whether the final underlying amount should be
+ * rounded up - it will instead be truncated (rounded down) if this value is
+ * false.
+ * @return The intermediate cToken or dToken amount and the final underlying
+ * amount.
+ */
+ function _fromUnderlyingAndBack(
+ uint256 underlying, uint256 exchangeRate, bool roundUpOne, bool roundUpTwo
+ ) internal pure returns (uint256 amount, uint256 adjustedUnderlying) {
+ amount = _fromUnderlying(underlying, exchangeRate, roundUpOne);
+ adjustedUnderlying = _toUnderlying(amount, exchangeRate, roundUpTwo);
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaTokenOverrides.sol b/contracts/implementations/token/DharmaTokenOverrides.sol
new file mode 100644
index 0000000..649f172
--- /dev/null
+++ b/contracts/implementations/token/DharmaTokenOverrides.sol
@@ -0,0 +1,36 @@
+pragma solidity 0.5.11;
+
+
+/**
+ * @title DharmaTokenOverrides
+ * @author 0age
+ * @notice A collection of internal view and pure functions that should be
+ * overridden by the ultimate Dharma Token implementation.
+ */
+contract DharmaTokenOverrides {
+ /**
+ * @notice Internal view function to get the current cToken exchange rate and
+ * supply rate per block. This function is meant to be overridden by the
+ * dToken that inherits this contract.
+ * @return The current cToken exchange rate, or amount of underlying tokens
+ * that are redeemable for each cToken, and the cToken supply rate per block
+ * (with 18 decimal places added to each returned rate).
+ */
+ function _getCurrentCTokenRates() internal view returns (
+ uint256 exchangeRate, uint256 supplyRate
+ );
+
+ function _getUnderlyingName() internal pure returns (string memory underlyingName);
+
+ function _getUnderlying() internal pure returns (address underlying);
+
+ function _getCTokenSymbol() internal pure returns (string memory cTokenSymbol);
+
+ function _getCToken() internal pure returns (address cToken);
+
+ function _getDTokenName() internal pure returns (string memory dTokenName);
+
+ function _getDTokenSymbol() internal pure returns (string memory dTokenSymbol);
+
+ function _getVault() internal pure returns (address vault);
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaTokenV1.sol b/contracts/implementations/token/DharmaTokenV1.sol
new file mode 100644
index 0000000..08617bf
--- /dev/null
+++ b/contracts/implementations/token/DharmaTokenV1.sol
@@ -0,0 +1,1022 @@
+pragma solidity 0.5.11;
+
+import "./DharmaTokenHelpers.sol";
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/DTokenInterface.sol";
+import "../../../interfaces/ERC20Interface.sol";
+import "../../../interfaces/ERC1271Interface.sol";
+
+
+/**
+ * @title DharmaTokenV1
+ * @author 0age (dToken mechanics derived from Compound cTokens, ERC20 mechanics
+ * derived from Open Zeppelin's ERC20 contract)
+ * @notice A Dharma Token (or dToken) is an upgradeable ERC20 token with support
+ * for meta-transactions that earns interest with respect to a given stablecoin,
+ * and is backed by that stablecoin's respective Compound cToken. The V1 dToken
+ * exchange rate will grow at 90% the rate of the backing cToken exchange rate.
+ * This abstract contract contains functionality shared by each dToken - those
+ * implementations will then inherit this contract and override any relevant,
+ * unimplemented internal functions with implementation-specific ones.
+ */
+contract DharmaTokenV1 is ERC20Interface, DTokenInterface, DharmaTokenHelpers {
+ // Set the version of the Dharma Token as a constant.
+ uint256 private constant _DTOKEN_VERSION = 1;
+
+ // Set block number and dToken + cToken exchange rate in slot zero on accrual.
+ AccrualIndex private _accrualIndex;
+
+ // Slot one tracks the total issued dTokens.
+ uint256 private _totalSupply;
+
+ // Slots two and three are entrypoints into balance and allowance mappings.
+ mapping (address => uint256) private _balances;
+ mapping (address => mapping (address => uint256)) private _allowances;
+
+ // Slot four is an entrypoint into a mapping for used meta-transaction hashes.
+ mapping (bytes32 => bool) private _executedMetaTxs;
+
+ /**
+ * @notice Transfer `underlyingToSupply` underlying tokens from `msg.sender`
+ * to this contract, use them to mint cTokens as backing, and mint dTokens to
+ * `msg.sender`. Ensure that this contract has been approved to transfer the
+ * underlying on behalf of the caller before calling this function.
+ * @param underlyingToSupply uint256 The amount of underlying to provide as
+ * part of minting.
+ * @return The amount of dTokens received in return for the supplied
+ * underlying tokens.
+ */
+ function mint(
+ uint256 underlyingToSupply
+ ) external returns (uint256 dTokensMinted) {
+ // Instantiate interfaces for the underlying token and the backing cToken.
+ ERC20Interface underlying = ERC20Interface(_getUnderlying());
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Pull in underlying - ensure that this contract has sufficient allowance.
+ require(
+ underlying.transferFrom(msg.sender, address(this), underlyingToSupply),
+ _getTransferFailureMessage()
+ );
+
+ // Use underlying to mint cTokens and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.mint.selector, underlyingToSupply
+ ));
+ _checkCompoundInteraction(cToken.mint.selector, ok, data);
+
+ // Accrue after the Compound mint to avoid duplicating accrual calculations.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(false);
+
+ // Get underlying equivalent of minted cTokens to prevent "dust" griefing.
+ (, uint256 underlyingEquivalent) = _fromUnderlyingAndBack(
+ underlyingToSupply, cTokenExchangeRate, false, false
+ );
+
+ // Determine dTokens to mint using underlying equivalent and exchange rate.
+ dTokensMinted = _fromUnderlying(
+ underlyingEquivalent, dTokenExchangeRate, false
+ );
+
+ // Mint dTokens to the caller.
+ _mint(msg.sender, underlyingToSupply, dTokensMinted);
+ }
+
+ /**
+ * @notice Transfer `cTokensToSupply` cTokens from `msg.sender` to this
+ * contract and mint dTokens to `msg.sender`. Ensure that this contract has
+ * been approved to transfer the cTokens on behalf of the caller before
+ * calling this function.
+ * @param cTokensToSupply uint256 The amount of cTokens to provide as part of
+ * minting.
+ * @return The amount of dTokens received in return for the supplied cTokens.
+ */
+ function mintViaCToken(
+ uint256 cTokensToSupply
+ ) external returns (uint256 dTokensMinted) {
+ // Instantiate the interface for the backing cToken.
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Pull in cTokens - ensure that this contract has sufficient allowance.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.transferFrom.selector, msg.sender, address(this), cTokensToSupply
+ ));
+ _checkCompoundInteraction(cToken.transferFrom.selector, ok, data);
+
+ // Accrue interest and retrieve current cToken and dToken exchange rates.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(true);
+
+ // Determine the underlying equivalent of the supplied cToken amount.
+ uint256 underlyingEquivalent = _toUnderlying(
+ cTokensToSupply, cTokenExchangeRate, false
+ );
+
+ // Determine dTokens to mint using underlying equivalent and exchange rate.
+ dTokensMinted = _fromUnderlying(
+ underlyingEquivalent, dTokenExchangeRate, false
+ );
+
+ // Mint dTokens to the caller.
+ _mint(msg.sender, underlyingEquivalent, dTokensMinted);
+ }
+
+ /**
+ * @notice Redeem `dTokensToBurn` dTokens from `msg.sender`, use the
+ * corresponding cTokens to redeem the required underlying, and transfer the
+ * redeemed underlying tokens to `msg.sender`.
+ * @param dTokensToBurn uint256 The amount of dTokens to provide in exchange
+ * for underlying tokens.
+ * @return The amount of underlying received in return for the provided
+ * dTokens.
+ */
+ function redeem(
+ uint256 dTokensToBurn
+ ) external returns (uint256 underlyingReceived) {
+ // Instantiate interfaces for the underlying token and the backing cToken.
+ ERC20Interface underlying = ERC20Interface(_getUnderlying());
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Accrue interest and retrieve current dToken and cToken exchange rates.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(true);
+
+ // Determine the equivalent underlying value of the dTokens to be burned.
+ uint256 underlyingEquivalent = _toUnderlying(
+ dTokensToBurn, dTokenExchangeRate, false
+ );
+
+ // Get minted cTokens and underlying equivalent to prevent "dust" griefing.
+ uint256 cTokenEquivalent;
+ (cTokenEquivalent, underlyingReceived) = _fromUnderlyingAndBack(
+ underlyingEquivalent, cTokenExchangeRate, false, false
+ );
+
+ // Burn the dTokens.
+ _burn(msg.sender, underlyingReceived, dTokensToBurn);
+
+ // Use cTokens to redeem underlying and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.redeem.selector, cTokenEquivalent
+ ));
+ _checkCompoundInteraction(cToken.redeem.selector, ok, data);
+
+ // Send the redeemed underlying tokens to the caller.
+ require(
+ underlying.transfer(msg.sender, underlyingReceived),
+ _getTransferFailureMessage()
+ );
+ }
+
+ /**
+ * @notice Redeem `dTokensToBurn` dTokens from `msg.sender` and transfer the
+ * corresponding amount of cTokens to `msg.sender`.
+ * @param dTokensToBurn uint256 The amount of dTokens to provide in exchange
+ * for the cTokens.
+ * @return The amount of cTokens received in return for the provided dTokens.
+ */
+ function redeemToCToken(
+ uint256 dTokensToBurn
+ ) external returns (uint256 cTokensReceived) {
+ // Instantiate the interface for the backing cToken.
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Accrue interest and retrieve current cToken and dToken exchange rates.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(true);
+
+ // Determine the underlying token value of the dTokens to be burned.
+ uint256 underlyingEquivalent = _toUnderlying(
+ dTokensToBurn, dTokenExchangeRate, false
+ );
+
+ // Determine amount of cTokens corresponding to underlying equivalent value.
+ cTokensReceived = _fromUnderlying(
+ underlyingEquivalent, cTokenExchangeRate, false
+ );
+
+ // Burn the dTokens.
+ _burn(msg.sender, underlyingEquivalent, dTokensToBurn);
+
+ // Transfer cTokens to the caller and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.transfer.selector, msg.sender, cTokensReceived
+ ));
+ _checkCompoundInteraction(cToken.transfer.selector, ok, data);
+ }
+
+ /**
+ * @notice Redeem the dToken equivalent value of the underlying token amount
+ * `underlyingToReceive` from `msg.sender`, use the corresponding cTokens to
+ * redeem the underlying, and transfer the underlying to `msg.sender`.
+ * @param underlyingToReceive uint256 The amount, denominated in the
+ * underlying token, of the cToken to redeem in exchange for the received
+ * underlying token.
+ * @return The amount of dTokens burned in exchange for the returned
+ * underlying tokens.
+ */
+ function redeemUnderlying(
+ uint256 underlyingToReceive
+ ) external returns (uint256 dTokensBurned) {
+ // Instantiate interfaces for the underlying token and the backing cToken.
+ ERC20Interface underlying = ERC20Interface(_getUnderlying());
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Use cTokens to redeem underlying and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.redeemUnderlying.selector, underlyingToReceive
+ ));
+ _checkCompoundInteraction(cToken.redeemUnderlying.selector, ok, data);
+
+ // Accrue after the Compound redeem to avoid duplicating calculations.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(false);
+
+ // Get underlying equivalent of redeemed cTokens to prevent "dust" griefing.
+ (, uint256 underlyingEquivalent) = _fromUnderlyingAndBack(
+ underlyingToReceive, cTokenExchangeRate, true, true // rounding up both
+ );
+
+ // Determine the dTokens to redeem using the exchange rate, rounding up.
+ dTokensBurned = _fromUnderlying(
+ underlyingEquivalent, dTokenExchangeRate, true
+ );
+
+ // Burn the dTokens.
+ _burn(msg.sender, underlyingToReceive, dTokensBurned);
+
+ // Send the redeemed underlying tokens to the caller.
+ require(
+ underlying.transfer(msg.sender, underlyingToReceive),
+ _getTransferFailureMessage()
+ );
+ }
+
+ /**
+ * @notice Redeem the dToken equivalent value of the underlying tokens of
+ * amount `underlyingToReceive` from `msg.sender` and transfer the
+ * corresponding amount of cTokens to `msg.sender`.
+ * @param underlyingToReceive uint256 The amount, denominated in the
+ * underlying token, of cTokens to receive.
+ * @return The amount of dTokens burned in exchange for the returned cTokens.
+ */
+ function redeemUnderlyingToCToken(
+ uint256 underlyingToReceive
+ ) external returns (uint256 dTokensBurned) {
+ // Instantiate the interface for the backing cToken.
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Accrue interest and retrieve current cToken and dToken exchange rates.
+ (uint256 dTokenExchangeRate, uint256 cTokenExchangeRate) = _accrue(true);
+
+ // Get received cTokens and underlying equivalent (prevent "dust" griefing).
+ (
+ uint256 cTokensToReceive, uint256 underlyingEquivalent
+ ) = _fromUnderlyingAndBack(
+ underlyingToReceive, cTokenExchangeRate, false, true // round down cTokens
+ );
+
+ // Determine redeemed dTokens using equivalent underlying value, rounded up.
+ dTokensBurned = _fromUnderlying(
+ underlyingEquivalent, dTokenExchangeRate, true
+ );
+
+ // Burn the dTokens.
+ _burn(msg.sender, underlyingToReceive, dTokensBurned);
+
+ // Transfer cTokens to the caller and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.transfer.selector, msg.sender, cTokensToReceive
+ ));
+ _checkCompoundInteraction(cToken.transfer.selector, ok, data);
+ }
+
+ /**
+ * @notice Transfer cTokens with underlying value in excess of the total
+ * underlying dToken value to a dedicated "vault" account. A "hard" accrual
+ * will first be performed, triggering an accrual on both the cToken and the
+ * dToken.
+ * @return The amount of cTokens transferred to the vault account.
+ */
+ function pullSurplus() external returns (uint256 cTokenSurplus) {
+ // Instantiate the interface for the backing cToken.
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ // Accrue interest on the cToken and ensure that the operation succeeds.
+ (bool ok, bytes memory data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.accrueInterest.selector
+ ));
+ _checkCompoundInteraction(cToken.accrueInterest.selector, ok, data);
+
+ // Accrue interest on the dToken, reusing the stored cToken exchange rate.
+ _accrue(false);
+
+ // Determine cToken surplus in underlying (cToken value - dToken value).
+ uint256 underlyingSurplus;
+ (underlyingSurplus, cTokenSurplus) = _getSurplus();
+
+ // Transfer cToken surplus to vault and ensure that the operation succeeds.
+ (ok, data) = address(cToken).call(abi.encodeWithSelector(
+ cToken.transfer.selector, _getVault(), cTokenSurplus
+ ));
+ _checkCompoundInteraction(cToken.transfer.selector, ok, data);
+
+ emit CollectSurplus(underlyingSurplus, cTokenSurplus);
+ }
+
+ /**
+ * @notice Manually advance the dToken exchange rate and cToken exchange rate
+ * to that of the current block. Note that dToken accrual does not trigger
+ * cToken accrual - instead, the updated exchange rate will be calculated
+ * internally.
+ */
+ function accrueInterest() external {
+ // Accrue interest on the dToken.
+ _accrue(true);
+ }
+
+ /**
+ * @notice Transfer `amount` dTokens from `msg.sender` to `recipient`.
+ * @param recipient address The account to transfer the dTokens to.
+ * @param amount uint256 The amount of dTokens to transfer.
+ * @return A boolean indicating whether the transfer was successful.
+ */
+ function transfer(
+ address recipient, uint256 amount
+ ) external returns (bool success) {
+ _transfer(msg.sender, recipient, amount);
+ success = true;
+ }
+
+ /**
+ * @notice Transfer dTokens equivalent to `underlyingEquivalentAmount`
+ * underlying from `msg.sender` to `recipient`.
+ * @param recipient address The account to transfer the dTokens to.
+ * @param underlyingEquivalentAmount uint256 The underlying equivalent amount
+ * of dTokens to transfer.
+ * @return A boolean indicating whether the transfer was successful.
+ */
+ function transferUnderlying(
+ address recipient, uint256 underlyingEquivalentAmount
+ ) external returns (bool success) {
+ // Accrue interest and retrieve the current dToken exchange rate.
+ (uint256 dTokenExchangeRate, ) = _accrue(true);
+
+ // Determine dToken amount to transfer using the exchange rate, rounded up.
+ uint256 dTokenAmount = _fromUnderlying(
+ underlyingEquivalentAmount, dTokenExchangeRate, true
+ );
+
+ // Transfer the dTokens.
+ _transfer(msg.sender, recipient, dTokenAmount);
+ success = true;
+ }
+
+ /**
+ * @notice Approve `spender` to transfer up to `value` dTokens on behalf of
+ * `msg.sender`.
+ * @param spender address The account to grant the allowance.
+ * @param value uint256 The size of the allowance to grant.
+ * @return A boolean indicating whether the approval was successful.
+ */
+ function approve(
+ address spender, uint256 value
+ ) external returns (bool success) {
+ _approve(msg.sender, spender, value);
+ success = true;
+ }
+
+ /**
+ * @notice Transfer `amount` dTokens from `sender` to `recipient` as long as
+ * `msg.sender` has sufficient allowance.
+ * @param sender address The account to transfer the dTokens from.
+ * @param recipient address The account to transfer the dTokens to.
+ * @param amount uint256 The amount of dTokens to transfer.
+ * @return A boolean indicating whether the transfer was successful.
+ */
+ function transferFrom(
+ address sender, address recipient, uint256 amount
+ ) external returns (bool success) {
+ _transferFrom(sender, recipient, amount);
+ success = true;
+ }
+
+ /**
+ * @notice Transfer dTokens eqivalent to `underlyingEquivalentAmount`
+ * underlying from `sender` to `recipient` as long as `msg.sender` has
+ * sufficient allowance.
+ * @param sender address The account to transfer the dTokens from.
+ * @param recipient address The account to transfer the dTokens to.
+ * @param underlyingEquivalentAmount uint256 The underlying equivalent amount
+ * of dTokens to transfer.
+ * @return A boolean indicating whether the transfer was successful.
+ */
+ function transferUnderlyingFrom(
+ address sender, address recipient, uint256 underlyingEquivalentAmount
+ ) external returns (bool success) {
+ // Accrue interest and retrieve the current dToken exchange rate.
+ (uint256 dTokenExchangeRate, ) = _accrue(true);
+
+ // Determine dToken amount to transfer using the exchange rate, rounded up.
+ uint256 dTokenAmount = _fromUnderlying(
+ underlyingEquivalentAmount, dTokenExchangeRate, true
+ );
+
+ // Transfer the dTokens and adjust allowance accordingly.
+ _transferFrom(sender, recipient, dTokenAmount);
+ success = true;
+ }
+
+ /**
+ * @notice Increase the current allowance of `spender` by `value` dTokens.
+ * @param spender address The account to grant the additional allowance.
+ * @param addedValue uint256 The amount to increase the allowance by.
+ * @return A boolean indicating whether the modification was successful.
+ */
+ function increaseAllowance(
+ address spender, uint256 addedValue
+ ) external returns (bool success) {
+ _approve(
+ msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)
+ );
+ success = true;
+ }
+
+ /**
+ * @notice Decrease the current allowance of `spender` by `value` dTokens.
+ * @param spender address The account to decrease the allowance for.
+ * @param subtractedValue uint256 The amount to subtract from the allowance.
+ * @return A boolean indicating whether the modification was successful.
+ */
+ function decreaseAllowance(
+ address spender, uint256 subtractedValue
+ ) external returns (bool success) {
+ _approve(
+ msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)
+ );
+ success = true;
+ }
+
+ /**
+ * @notice Modify the current allowance of `spender` for `owner` by `value`
+ * dTokens, increasing it if `increase` is true otherwise decreasing it, via a
+ * meta-transaction that expires at `expiration` (or does not expire if the
+ * value is zero) and uses `salt` as an additional input, validated using
+ * `signatures`.
+ * @param owner address The account granting the modified allowance.
+ * @param spender address The account to modify the allowance for.
+ * @param value uint256 The amount to modify the allowance by.
+ * @param increase bool A flag that indicates whether the allowance will be
+ * increased by the specified value (if true) or decreased by it (if false).
+ * @param expiration uint256 A timestamp indicating how long the modification
+ * meta-transaction is valid for - a value of zero will signify no expiration.
+ * @param salt bytes32 An arbitrary salt to be provided as an additional input
+ * to the hash digest used to validate the signatures.
+ * @param signatures bytes A signature, or collection of signatures, that the
+ * owner must provide in order to authorize the meta-transaction. If the
+ * account of the owner does not have any runtime code deployed to it, the
+ * signature will be verified using ecrecover; otherwise, it will be supplied
+ * to the owner along with the message digest and context via ERC-1271 for
+ * validation.
+ * @return A boolean indicating whether the modification was successful.
+ */
+ function modifyAllowanceViaMetaTransaction(
+ address owner,
+ address spender,
+ uint256 value,
+ bool increase,
+ uint256 expiration,
+ bytes32 salt,
+ bytes calldata signatures
+ ) external returns (bool success) {
+ require(expiration == 0 || now <= expiration, "Meta-transaction expired.");
+
+ // Construct the meta-transaction's message hash based on relevant context.
+ bytes memory context = abi.encodePacked(
+ address(this),
+ // _DTOKEN_VERSION,
+ this.modifyAllowanceViaMetaTransaction.selector,
+ expiration,
+ salt,
+ abi.encode(owner, spender, value, increase)
+ );
+ bytes32 messageHash = keccak256(context);
+
+ // Ensure message hash has never been used before and register it as used.
+ require(!_executedMetaTxs[messageHash], "Meta-transaction already used.");
+ _executedMetaTxs[messageHash] = true;
+
+ // Construct the digest to compare signatures against using EIP-191 0x45.
+ bytes32 digest = keccak256(
+ abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)
+ );
+
+ // Calculate new allowance by applying modification to current allowance.
+ uint256 currentAllowance = _allowances[owner][spender];
+ uint256 newAllowance = (
+ increase ? currentAllowance.add(value) : currentAllowance.sub(value)
+ );
+
+ // Use EIP-1271 if owner is a contract - otherwise, use ecrecover.
+ if (_isContract(owner)) {
+ // Validate via ERC-1271 against the owner account.
+ bytes memory data = abi.encode(digest, context);
+ bytes4 magic = ERC1271Interface(owner).isValidSignature(data, signatures);
+ require(magic == bytes4(0x20c13b0b), "Invalid signatures.");
+ } else {
+ // Validate via ecrecover against the owner account.
+ _verifyRecover(owner, digest, signatures);
+ }
+
+ // Modify the allowance.
+ _approve(owner, spender, newAllowance);
+ success = true;
+ }
+
+ /**
+ * @notice View function to determine a meta-transaction message hash, and to
+ * determine if it is still valid (i.e. it has not yet been used and is not
+ * expired). The returned message hash will need to be prefixed using EIP-191
+ * 0x45 and hashed again in order to generate a final digest for the required
+ * signature - in other words, the same procedure utilized by `eth_Sign`.
+ * @param functionSelector bytes4 The function selector for the given
+ * meta-transaction. There is only one function selector available for V1:
+ * `0x2d657fa5` (the selector for `modifyAllowanceViaMetaTransaction`).
+ * @param arguments bytes The abi-encoded function arguments (aside from the
+ * `expiration`, `salt`, and `signatures` arguments) that should be supplied
+ * to the given function.
+ * @param expiration uint256 A timestamp indicating how long the given
+ * meta-transaction is valid for - a value of zero will signify no expiration.
+ * @param salt bytes32 An arbitrary salt to be provided as an additional input
+ * to the hash digest used to validate the signatures.
+ * @return The total supply.
+ */
+ function getMetaTransactionMessageHash(
+ bytes4 functionSelector,
+ bytes calldata arguments,
+ uint256 expiration,
+ bytes32 salt
+ ) external view returns (bytes32 messageHash, bool valid) {
+ // Construct the meta-transaction's message hash based on relevant context.
+ messageHash = keccak256(
+ abi.encodePacked(
+ address(this), functionSelector, expiration, salt, arguments
+ )
+ );
+
+ // The meta-transaction is valid if it has not been used and is not expired.
+ valid = (
+ !_executedMetaTxs[messageHash] && (expiration == 0 || now <= expiration)
+ );
+ }
+
+ /**
+ * @notice View function to get the total dToken supply.
+ * @return The total supply.
+ */
+ function totalSupply() external view returns (uint256 dTokenTotalSupply) {
+ dTokenTotalSupply = _totalSupply;
+ }
+
+ /**
+ * @notice View function to get the total dToken supply, denominated in the
+ * underlying token.
+ * @return The total supply.
+ */
+ function totalSupplyUnderlying() external view returns (
+ uint256 dTokenTotalSupplyInUnderlying
+ ) {
+ (uint256 dTokenExchangeRate, ,) = _getExchangeRates(true);
+
+ // Determine total value of all issued dTokens, denominated as underlying.
+ dTokenTotalSupplyInUnderlying = _toUnderlying(
+ _totalSupply, dTokenExchangeRate, false
+ );
+ }
+
+ /**
+ * @notice View function to get the total dToken balance of an account.
+ * @param account address The account to check the dToken balance for.
+ * @return The balance of the given account.
+ */
+ function balanceOf(address account) external view returns (uint256 dTokens) {
+ dTokens = _balances[account];
+ }
+
+ /**
+ * @notice View function to get the dToken balance of an account, denominated
+ * in the underlying equivalent value.
+ * @param account address The account to check the balance for.
+ * @return The total underlying-equivalent dToken balance.
+ */
+ function balanceOfUnderlying(
+ address account
+ ) external view returns (uint256 underlyingBalance) {
+ // Get most recent dToken exchange rate by determining accrued interest.
+ (uint256 dTokenExchangeRate, ,) = _getExchangeRates(true);
+
+ // Convert account balance to underlying equivalent using the exchange rate.
+ underlyingBalance = _toUnderlying(
+ _balances[account], dTokenExchangeRate, false
+ );
+ }
+
+ /**
+ * @notice View function to get the total allowance that `spender` has to
+ * transfer dTokens from the `owner` account using `transferFrom`.
+ * @param owner address The account that is granting the allowance.
+ * @param spender address The account that has been granted the allowance.
+ * @return The allowance of the given spender for the given owner.
+ */
+ function allowance(
+ address owner, address spender
+ ) external view returns (uint256 dTokenAllowance) {
+ dTokenAllowance = _allowances[owner][spender];
+ }
+
+ /**
+ * @notice View function to get the current dToken exchange rate (multiplied
+ * by 10^18).
+ * @return The current exchange rate.
+ */
+ function exchangeRateCurrent() external view returns (
+ uint256 dTokenExchangeRate
+ ) {
+ // Get most recent dToken exchange rate by determining accrued interest.
+ (dTokenExchangeRate, ,) = _getExchangeRates(true);
+ }
+
+ /**
+ * @notice View function to get the current dToken interest earned per block
+ * (multiplied by 10^18).
+ * @return The current interest rate.
+ */
+ function supplyRatePerBlock() external view returns (
+ uint256 dTokenInterestRate
+ ) {
+ (dTokenInterestRate,) = _getRatePerBlock();
+ }
+
+ /**
+ * @notice View function to get the block number where accrual was last
+ * performed.
+ * @return The block number where accrual was last performed.
+ */
+ function accrualBlockNumber() external view returns (uint256 blockNumber) {
+ blockNumber = _accrualIndex.block;
+ }
+
+ /**
+ * @notice View function to get the total surplus, or the cToken balance that
+ * exceeds the aggregate underlying value of the total dToken supply.
+ * @return The total surplus in cTokens.
+ */
+ function getSurplus() external view returns (uint256 cTokenSurplus) {
+ // Determine the cToken (cToken underlying value - dToken underlying value).
+ (, cTokenSurplus) = _getSurplus();
+ }
+
+ /**
+ * @notice View function to get the total surplus in the underlying, or the
+ * underlying equivalent of the cToken balance that exceeds the aggregate
+ * underlying value of the total dToken supply.
+ * @return The total surplus, denominated in the underlying.
+ */
+ function getSurplusUnderlying() external view returns (
+ uint256 underlyingSurplus
+ ) {
+ // Determine cToken surplus in underlying (cToken value - dToken value).
+ (underlyingSurplus, ) = _getSurplus();
+ }
+
+ /**
+ * @notice View function to get the interest rate spread taken by the dToken
+ * from the current cToken supply rate per block (multiplied by 10^18).
+ * @return The current interest rate spread.
+ */
+ function getSpreadPerBlock() external view returns (uint256 rateSpread) {
+ (
+ uint256 dTokenInterestRate, uint256 cTokenInterestRate
+ ) = _getRatePerBlock();
+ rateSpread = cTokenInterestRate.sub(dTokenInterestRate);
+ }
+
+ /**
+ * @notice Pure function to get the name of the dToken.
+ * @return The name of the dToken.
+ */
+ function name() external pure returns (string memory dTokenName) {
+ dTokenName = _getDTokenName();
+ }
+
+ /**
+ * @notice Pure function to get the symbol of the dToken.
+ * @return The symbol of the dToken.
+ */
+ function symbol() external pure returns (string memory dTokenSymbol) {
+ dTokenSymbol = _getDTokenSymbol();
+ }
+
+ /**
+ * @notice Pure function to get the number of decimals of the dToken.
+ * @return The number of decimals of the dToken.
+ */
+ function decimals() external pure returns (uint8 dTokenDecimals) {
+ dTokenDecimals = _DECIMALS;
+ }
+
+ /**
+ * @notice Pure function to get the dToken version.
+ * @return The version of the dToken.
+ */
+ function getVersion() external pure returns (uint256 version) {
+ version = _DTOKEN_VERSION;
+ }
+
+ /**
+ * @notice Pure function to get the address of the cToken backing this dToken.
+ * @return The address of the cToken backing this dToken.
+ */
+ function getCToken() external pure returns (address cToken) {
+ cToken = _getCToken();
+ }
+
+ /**
+ * @notice Pure function to get the address of the underlying token of this
+ * dToken.
+ * @return The address of the underlying token for this dToken.
+ */
+ function getUnderlying() external pure returns (address underlying) {
+ underlying = _getUnderlying();
+ }
+
+ /**
+ * @notice Private function to trigger accrual and to update the dToken and
+ * cToken exchange rates in storage if necessary. The `compute` argument can
+ * be set to false if an accrual has already taken place on the cToken before
+ * calling this function.
+ * @param compute bool A flag to indicate whether the cToken exchange rate
+ * needs to be computed - if false, it will simply be read from storage on the
+ * cToken in question.
+ * @return The current dToken and cToken exchange rates.
+ */
+ function _accrue(bool compute) private returns (
+ uint256 dTokenExchangeRate, uint256 cTokenExchangeRate
+ ) {
+ bool alreadyAccrued;
+ (
+ dTokenExchangeRate, cTokenExchangeRate, alreadyAccrued
+ ) = _getExchangeRates(compute);
+
+ if (!alreadyAccrued) {
+ // Update storage with dToken + cToken exchange rates as of current block.
+ AccrualIndex storage accrualIndex = _accrualIndex;
+ accrualIndex.dTokenExchangeRate = _safeUint112(dTokenExchangeRate);
+ accrualIndex.cTokenExchangeRate = _safeUint112(cTokenExchangeRate);
+ accrualIndex.block = uint32(block.number);
+ emit Accrue(dTokenExchangeRate, cTokenExchangeRate);
+ }
+ }
+
+ /**
+ * @notice Private function to mint `amount` tokens by exchanging `exchanged`
+ * tokens to `account` and emit corresponding `Mint` & `Transfer` events.
+ * @param account address The account to mint tokens to.
+ * @param exchanged uint256 The amount of underlying tokens used to mint.
+ * @param amount uint256 The amount of tokens to mint.
+ */
+ function _mint(address account, uint256 exchanged, uint256 amount) private {
+ require(
+ exchanged > 0 && amount > 0, "Mint failed: insufficient funds supplied."
+ );
+ _totalSupply = _totalSupply.add(amount);
+ _balances[account] = _balances[account].add(amount);
+
+ emit Mint(account, exchanged, amount);
+ emit Transfer(address(0), account, amount);
+ }
+
+ /**
+ * @notice Private function to burn `amount` tokens by exchanging `exchanged`
+ * tokens from `account` and emit corresponding `Redeeem` & `Transfer` events.
+ * @param account address The account to burn tokens from.
+ * @param exchanged uint256 The amount of underlying tokens given for burning.
+ * @param amount uint256 The amount of tokens to burn.
+ */
+ function _burn(address account, uint256 exchanged, uint256 amount) private {
+ require(
+ exchanged > 0 && amount > 0, "Redeem failed: insufficient funds supplied."
+ );
+
+ uint256 balancePriorToBurn = _balances[account];
+ require(
+ balancePriorToBurn >= amount, "Supplied amount exceeds account balance."
+ );
+
+ _totalSupply = _totalSupply.sub(amount);
+ _balances[account] = balancePriorToBurn - amount; // overflow checked above
+
+ emit Transfer(account, address(0), amount);
+ emit Redeem(account, exchanged, amount);
+ }
+
+ /**
+ * @notice Private function to move `amount` tokens from `sender` to
+ * `recipient` and emit a corresponding `Transfer` event.
+ * @param sender address The account to transfer tokens from.
+ * @param recipient address The account to transfer tokens to.
+ * @param amount uint256 The amount of tokens to transfer.
+ */
+ function _transfer(
+ address sender, address recipient, uint256 amount
+ ) private {
+ require(sender != address(0), "ERC20: transfer from the zero address");
+ require(recipient != address(0), "ERC20: transfer to the zero address");
+
+ uint256 senderBalance = _balances[sender];
+ require(senderBalance >= amount, "Insufficient funds.");
+
+ _balances[sender] = senderBalance - amount; // overflow checked above.
+ _balances[recipient] = _balances[recipient].add(amount);
+
+ emit Transfer(sender, recipient, amount);
+ }
+
+ /**
+ * @notice Private function to transfer `amount` tokens from `sender` to
+ * `recipient` and to deduct the transferred amount from the allowance of the
+ * caller unless the allowance is set to the maximum amount.
+ * @param sender address The account to transfer tokens from.
+ * @param recipient address The account to transfer tokens to.
+ * @param amount uint256 The amount of tokens to transfer.
+ */
+ function _transferFrom(
+ address sender, address recipient, uint256 amount
+ ) private {
+ _transfer(sender, recipient, amount);
+ uint256 callerAllowance = _allowances[sender][msg.sender];
+ if (callerAllowance != uint256(-1)) {
+ require(callerAllowance >= amount, "Insufficient allowance.");
+ _approve(sender, msg.sender, callerAllowance - amount); // overflow safe.
+ }
+ }
+
+ /**
+ * @notice Private function to set the allowance for `spender` to transfer up
+ * to `value` tokens on behalf of `owner`.
+ * @param owner address The account that has granted the allowance.
+ * @param spender address The account to grant the allowance.
+ * @param value uint256 The size of the allowance to grant.
+ */
+ function _approve(address owner, address spender, uint256 value) private {
+ require(owner != address(0), "ERC20: approve for the zero address");
+ require(spender != address(0), "ERC20: approve to the zero address");
+
+ _allowances[owner][spender] = value;
+ emit Approval(owner, spender, value);
+ }
+
+ /**
+ * @notice Private view function to get the latest dToken and cToken exchange
+ * rates and provide the value for each. The `compute` argument can be set to
+ * false if an accrual has already taken place on the cToken before calling
+ * this function.
+ * @param compute bool A flag to indicate whether the cToken exchange rate
+ * needs to be computed - if false, it will simply be read from storage on the
+ * cToken in question.
+ * @return The dToken and cToken exchange rate, as well as a boolean
+ * indicating if interest accrual has been processed already or needs to be
+ * calculated and placed in storage.
+ */
+ function _getExchangeRates(bool compute) private view returns (
+ uint256 dTokenExchangeRate, uint256 cTokenExchangeRate, bool fullyAccrued
+ ) {
+ // Get the stored accrual block and dToken + cToken exhange rates.
+ AccrualIndex memory accrualIndex = _accrualIndex;
+ uint256 storedDTokenExchangeRate = uint256(accrualIndex.dTokenExchangeRate);
+ uint256 storedCTokenExchangeRate = uint256(accrualIndex.cTokenExchangeRate);
+ uint256 accrualBlock = uint256(accrualIndex.block);
+
+ // Use stored exchange rates if an accrual has already occurred this block.
+ fullyAccrued = (accrualBlock == block.number);
+ if (fullyAccrued) {
+ dTokenExchangeRate = storedDTokenExchangeRate;
+ cTokenExchangeRate = storedCTokenExchangeRate;
+ } else {
+ // Only compute cToken exchange rate if it has not accrued this block.
+ if (compute) {
+ // Get current cToken exchange rate; inheriting contract overrides this.
+ (cTokenExchangeRate,) = _getCurrentCTokenRates();
+ } else {
+ // Otherwise, get the stored cToken exchange rate.
+ cTokenExchangeRate = CTokenInterface(_getCToken()).exchangeRateStored();
+ }
+
+ // Determine the cToken interest earned during the period.
+ uint256 cTokenInterest = (
+ (cTokenExchangeRate.mul(_SCALING_FACTOR)).div(storedCTokenExchangeRate)
+ ).sub(_SCALING_FACTOR);
+
+ // Calculate dToken exchange rate by applying 90% of the cToken interest.
+ dTokenExchangeRate = storedDTokenExchangeRate.mul(
+ _SCALING_FACTOR.add(cTokenInterest.mul(9) / 10)
+ ) / _SCALING_FACTOR;
+ }
+ }
+
+ /**
+ * @notice Private view function to get the total surplus, or cToken
+ * balance that exceeds the total dToken balance.
+ * @return The total surplus, denominated in both the underlying and in the
+ * cToken.
+ */
+ function _getSurplus() private view returns (
+ uint256 underlyingSurplus, uint256 cTokenSurplus
+ ) {
+ // Instantiate the interface for the backing cToken.
+ CTokenInterface cToken = CTokenInterface(_getCToken());
+
+ (
+ uint256 dTokenExchangeRate, uint256 cTokenExchangeRate,
+ ) = _getExchangeRates(true);
+
+ // Determine value of all issued dTokens in the underlying, rounded up.
+ uint256 dTokenUnderlying = _toUnderlying(
+ _totalSupply, dTokenExchangeRate, true
+ );
+
+ // Determine value of all retained cTokens in the underlying, rounded down.
+ uint256 cTokenUnderlying = _toUnderlying(
+ cToken.balanceOf(address(this)), cTokenExchangeRate, false
+ );
+
+ // Determine the size of the surplus in terms of underlying amount.
+ underlyingSurplus = cTokenUnderlying > dTokenUnderlying
+ ? cTokenUnderlying - dTokenUnderlying // overflow checked above
+ : 0;
+
+ // Determine the cToken equivalent of this surplus amount.
+ cTokenSurplus = underlyingSurplus == 0
+ ? 0
+ : _fromUnderlying(underlyingSurplus, cTokenExchangeRate, false);
+ }
+
+ /**
+ * @notice Private view function to get the current dToken and cToken interest
+ * supply rate per block (multiplied by 10^18).
+ * @return The current dToken and cToken interest rates.
+ */
+ function _getRatePerBlock() private view returns (
+ uint256 dTokenSupplyRate, uint256 cTokenSupplyRate
+ ) {
+ (, cTokenSupplyRate) = _getCurrentCTokenRates();
+ dTokenSupplyRate = cTokenSupplyRate.mul(9) / 10;
+ }
+
+ /**
+ * @notice Private view function to determine if a given account has runtime
+ * code or not - in other words, whether or not a contract is deployed to the
+ * account in question. Note that contracts that are in the process of being
+ * deployed will return false on this check.
+ * @param account address The account to check for contract runtime code.
+ * @return Whether or not there is contract runtime code at the account.
+ */
+ function _isContract(address account) private view returns (bool isContract) {
+ uint256 size;
+ assembly { size := extcodesize(account) }
+ isContract = size > 0;
+ }
+
+ /**
+ * @notice Private pure function to verify that a given signature of a digest
+ * resolves to the supplied account. Any error, including incorrect length,
+ * malleable signature types, or unsupported `v` values, will cause a revert.
+ * @param account address The account to validate against.
+ * @param digest bytes32 The digest to use.
+ * @param signature bytes The signature to verify.
+ */
+ function _verifyRecover(
+ address account, bytes32 digest, bytes memory signature
+ ) private pure {
+ // Ensure the signature length is correct.
+ require(
+ signature.length == 65,
+ "Must supply a single 65-byte signature when owner is not a contract."
+ );
+
+ // Divide the signature in r, s and v variables.
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ assembly {
+ r := mload(add(signature, 0x20))
+ s := mload(add(signature, 0x40))
+ v := byte(0, mload(add(signature, 0x60)))
+ }
+
+ require(
+ uint256(s) <= _MAX_UNMALLEABLE_S,
+ "Signature `s` value cannot be potentially malleable."
+ );
+
+ require(v == 27 || v == 28, "Signature `v` value not permitted.");
+
+ require(account == ecrecover(digest, v, r, s), "Invalid signature.");
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaUSDCImplementationV1.sol b/contracts/implementations/token/DharmaUSDCImplementationV1.sol
new file mode 100644
index 0000000..ec612ae
--- /dev/null
+++ b/contracts/implementations/token/DharmaUSDCImplementationV1.sol
@@ -0,0 +1,126 @@
+pragma solidity 0.5.11;
+
+import "@openzeppelin/contracts/math/SafeMath.sol";
+import "./DharmaTokenV1.sol";
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/ERC20Interface.sol";
+import "../../../interfaces/CUSDCInterestRateModelInterface.sol";
+
+
+/**
+ * @title DharmaUSDCImplementationV1
+ * @author 0age (dToken mechanics derived from Compound cTokens, ERC20 methods
+ * derived from Open Zeppelin's ERC20 contract)
+ * @notice Dharma USD Coin is an interest-bearing token, with cUSDC as the
+ * backing token and USD Coin as the underlying token. The dUSDC exchange rate
+ * will initially increase at 90% the rate of the cUSDC exchange rate.
+ */
+contract DharmaUSDCImplementationV1 is DharmaTokenV1 {
+ string internal constant _NAME = "Dharma USD Coin";
+ string internal constant _SYMBOL = "dUSDC";
+ string internal constant _UNDERLYING_NAME = "USD Coin";
+ string internal constant _CTOKEN_SYMBOL = "cUSDC";
+
+ CTokenInterface internal constant _CUSDC = CTokenInterface(
+ 0x39AA39c021dfbaE8faC545936693aC917d5E7563 // mainnet
+ );
+
+ ERC20Interface internal constant _USDC = ERC20Interface(
+ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
+ );
+
+ // Note: this is just an EOA for the initial prototype.
+ address internal constant _VAULT = 0x7e4A8391C728fEd9069B2962699AB416628B19Fa;
+
+ uint256 internal constant _SCALING_FACTOR_SQUARED = 1e36;
+
+ /**
+ * @notice Internal view function to get the current cUSDC exchange rate and
+ * supply rate per block.
+ * @return The current cUSDC exchange rate, or amount of USDC that is
+ * redeemable for each cUSDC, and the cUSDC supply rate per block (with 18
+ * decimal places added to each returned rate).
+ */
+ function _getCurrentCTokenRates() internal view returns (
+ uint256 exchangeRate, uint256 supplyRate
+ ) {
+ // Determine number of blocks that have elapsed since last cUSDC accrual.
+ uint256 blockDelta = block.number.sub(_CUSDC.accrualBlockNumber());
+
+ // Return stored values if accrual has already been performed this block.
+ if (blockDelta == 0) return (
+ _CUSDC.exchangeRateStored(), _CUSDC.supplyRatePerBlock()
+ );
+
+ // Determine total "cash" held by cUSDC contract.
+ uint256 cash = _USDC.balanceOf(address(_CUSDC));
+
+ // Get the latest interest rate model from the cUSDC contract.
+ CUSDCInterestRateModelInterface interestRateModel = (
+ CUSDCInterestRateModelInterface(_CUSDC.interestRateModel())
+ );
+
+ // Get the current stored total borrows, reserves, and reserve factor.
+ uint256 borrows = _CUSDC.totalBorrows();
+ uint256 reserves = _CUSDC.totalReserves();
+ uint256 reserveFactor = _CUSDC.reserveFactorMantissa();
+
+ // Get accumulated borrow interest via interest rate model and block delta.
+ (uint256 err, uint256 borrowRate) = interestRateModel.getBorrowRate(
+ cash, borrows, reserves
+ );
+ require(
+ err == _COMPOUND_SUCCESS, "Interest Rate Model borrow rate check failed."
+ );
+
+ uint256 interest = borrowRate.mul(blockDelta).mul(borrows) / _SCALING_FACTOR;
+
+ // Update total borrows and reserves using calculated accumulated interest.
+ borrows = borrows.add(interest);
+ reserves = reserves.add(reserveFactor.mul(interest) / _SCALING_FACTOR);
+
+ // Get "underlying": (cash + borrows - reserves)
+ uint256 underlying = (cash.add(borrows)).sub(reserves);
+
+ // Determine cUSDC exchange rate: underlying / total supply
+ exchangeRate = (underlying.mul(_SCALING_FACTOR)).div(_CUSDC.totalSupply());
+
+ // Get "borrows per" by dividing total borrows by underlying and scaling up.
+ uint256 borrowsPer = (
+ borrows.mul(_SCALING_FACTOR_SQUARED)
+ ).div(underlying);
+
+ // Supply rate is borrow interest * (1 - reserveFactor) * borrowsPer
+ supplyRate = (
+ interest.mul(_SCALING_FACTOR.sub(reserveFactor)).mul(borrowsPer)
+ ) / _SCALING_FACTOR_SQUARED;
+ }
+
+ function _getUnderlyingName() internal pure returns (string memory underlyingName) {
+ underlyingName = _UNDERLYING_NAME;
+ }
+
+ function _getUnderlying() internal pure returns (address underlying) {
+ underlying = address(_USDC);
+ }
+
+ function _getCTokenSymbol() internal pure returns (string memory cTokenSymbol) {
+ cTokenSymbol = _CTOKEN_SYMBOL;
+ }
+
+ function _getCToken() internal pure returns (address cToken) {
+ cToken = address(_CUSDC);
+ }
+
+ function _getDTokenName() internal pure returns (string memory dTokenName) {
+ dTokenName = _NAME;
+ }
+
+ function _getDTokenSymbol() internal pure returns (string memory dTokenSymbol) {
+ dTokenSymbol = _SYMBOL;
+ }
+
+ function _getVault() internal pure returns (address vault) {
+ vault = _VAULT;
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/DharmaUSDCInitializer.sol b/contracts/implementations/token/DharmaUSDCInitializer.sol
new file mode 100644
index 0000000..d109468
--- /dev/null
+++ b/contracts/implementations/token/DharmaUSDCInitializer.sol
@@ -0,0 +1,71 @@
+pragma solidity 0.5.11;
+
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/ERC20Interface.sol";
+
+
+/**
+ * @title DharmaUSDCInitializer
+ * @author 0age
+ * @notice Initializer for the Dharma USD Coin token.
+ */
+contract DharmaUSDCInitializer {
+ event Accrue(uint256 dTokenExchangeRate, uint256 cTokenExchangeRate);
+
+ // The block number and cToken + dToken exchange rates are updated on accrual.
+ struct AccrualIndex {
+ uint112 dTokenExchangeRate;
+ uint112 cTokenExchangeRate;
+ uint32 block;
+ }
+
+ CTokenInterface internal constant _CUSDC = CTokenInterface(
+ 0x39AA39c021dfbaE8faC545936693aC917d5E7563 // mainnet
+ );
+
+ ERC20Interface internal constant _USDC = ERC20Interface(
+ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
+ );
+
+ uint256 internal constant _MAX_UINT_112 = 5192296858534827628530496329220095;
+
+ // Set block number and dToken + cToken exchange rate in slot zero on accrual.
+ AccrualIndex private _accrualIndex;
+
+ /**
+ * @notice Initialize Dharma USD Coin by approving cUSDC to transfer USDC on
+ * behalf of this contract and setting the initial dUSDC and cUSDC exchange
+ * rates in storage.
+ */
+ function initialize() public {
+ // Approve cToken to transfer underlying for this contract in order to mint.
+ require(
+ _USDC.approve(address(_CUSDC), uint256(-1)),
+ "Initial cUSDC approval failed."
+ );
+
+ // Initial dToken exchange rate is 1-to-1 (dTokens have 8 decimals).
+ uint256 dTokenExchangeRate = 1e16;
+
+ // Accrue cToken interest and retrieve the current cToken exchange rate.
+ uint256 cTokenExchangeRate = _CUSDC.exchangeRateCurrent();
+
+ // Initialize accrual index with current block number and exchange rates.
+ AccrualIndex storage accrualIndex = _accrualIndex;
+ accrualIndex.dTokenExchangeRate = uint112(dTokenExchangeRate);
+ accrualIndex.cTokenExchangeRate = _safeUint112(cTokenExchangeRate);
+ accrualIndex.block = uint32(block.number);
+ emit Accrue(dTokenExchangeRate, cTokenExchangeRate);
+ }
+
+ /**
+ * @notice Internal pure function to convert a uint256 to a uint112, reverting
+ * if the conversion would cause an overflow.
+ * @param input uint256 The unsigned integer to convert.
+ * @return The converted unsigned integer.
+ */
+ function _safeUint112(uint256 input) internal pure returns (uint112 output) {
+ require(input <= _MAX_UINT_112, "Overflow on conversion to uint112.");
+ output = uint112(input);
+ }
+}
\ No newline at end of file
diff --git a/contracts/implementations/token/MockDharmaDaiImplementationV1.sol b/contracts/implementations/token/MockDharmaDaiImplementationV1.sol
new file mode 100644
index 0000000..435af0e
--- /dev/null
+++ b/contracts/implementations/token/MockDharmaDaiImplementationV1.sol
@@ -0,0 +1,163 @@
+pragma solidity 0.5.11;
+
+import "@openzeppelin/contracts/math/SafeMath.sol";
+import "./DharmaTokenV1.sol";
+import "../../../interfaces/CTokenInterface.sol";
+import "../../../interfaces/ERC20Interface.sol";
+import "../../../interfaces/CUSDCInterestRateModelInterface.sol";
+import "../../../interfaces/PotInterface.sol";
+
+
+/**
+ * @title MockDharmaDaiImplementationV1
+ * @author 0age (dToken mechanics derived from Compound cTokens, ERC20 methods
+ * derived from Open Zeppelin's ERC20 contract)
+ * @notice Dharma Dai is an interest-bearing token, with cDai as the backing
+ * token and Dai as the underlying token. The dDai exchange rate will initially
+ * increase at 90% the rate of the cDai exchange rate.
+ */
+contract MockDharmaDaiImplementationV1 is DharmaTokenV1 {
+ string internal constant _NAME = "Dharma Dai";
+ string internal constant _SYMBOL = "dDai";
+ string internal constant _UNDERLYING_NAME = "Dai";
+ string internal constant _CTOKEN_SYMBOL = "cDai";
+
+ CTokenInterface internal constant _CDAI = CTokenInterface(
+ 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 // mainnet
+ );
+
+ ERC20Interface internal constant _DAI = ERC20Interface(
+ 0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
+ );
+
+ // Note: this is just an EOA for the initial prototype.
+ address internal constant _VAULT = 0x7e4A8391C728fEd9069B2962699AB416628B19Fa;
+
+ uint256 internal constant _SCALING_FACTOR_SQUARED = 1e36;
+
+ /**
+ * @notice Internal view function to get the current cDAI exchange rate and
+ * supply rate per block. NOTE: THIS IS MOCKED USING SAI DEPLOYED TO THE DAI
+ * ADDRESS!
+ * @return The current cDAI exchange rate, or amount of Dai that is
+ * redeemable for each cDAI, and the cDAI supply rate per block (with 18
+ * decimal places added to each returned rate).
+ */
+ function _getCurrentCTokenRates() internal view returns (
+ uint256 exchangeRate, uint256 supplyRate
+ ) {
+ // Determine number of blocks that have elapsed since last cDAI accrual.
+ uint256 blockDelta = block.number.sub(_CDAI.accrualBlockNumber());
+
+ // Return stored values if accrual has already been performed this block.
+ if (blockDelta == 0) return (
+ _CDAI.exchangeRateStored(), _CDAI.supplyRatePerBlock()
+ );
+
+ // Determine total "cash" held by cDAI contract.
+ uint256 cash = _DAI.balanceOf(address(_CDAI));
+
+ // Get the latest interest rate model from the cDAI contract.
+ CUSDCInterestRateModelInterface interestRateModel = (
+ CUSDCInterestRateModelInterface(_CDAI.interestRateModel())
+ );
+
+ // Get the current stored total borrows, reserves, and reserve factor.
+ uint256 borrows = _CDAI.totalBorrows();
+ uint256 reserves = _CDAI.totalReserves();
+ uint256 reserveFactor = _CDAI.reserveFactorMantissa();
+
+ // Get accumulated borrow interest via interest rate model and block delta.
+ (uint256 err, uint256 borrowRate) = interestRateModel.getBorrowRate(
+ cash, borrows, reserves
+ );
+ require(
+ err == _COMPOUND_SUCCESS, "Interest Rate Model borrow rate check failed."
+ );
+
+ uint256 interest = borrowRate.mul(blockDelta).mul(borrows) / _SCALING_FACTOR;
+
+ // Update total borrows and reserves using calculated accumulated interest.
+ borrows = borrows.add(interest);
+ reserves = reserves.add(reserveFactor.mul(interest) / _SCALING_FACTOR);
+
+ // Get "underlying": (cash + borrows - reserves)
+ uint256 underlying = (cash.add(borrows)).sub(reserves);
+
+ // Determine cDAI exchange rate: underlying / total supply
+ exchangeRate = (underlying.mul(_SCALING_FACTOR)).div(_CDAI.totalSupply());
+
+ // Get "borrows per" by dividing total borrows by underlying and scaling up.
+ uint256 borrowsPer = (
+ borrows.mul(_SCALING_FACTOR_SQUARED)
+ ).div(underlying);
+
+ // Supply rate is borrow interest * (1 - reserveFactor) * borrowsPer
+ supplyRate = (
+ interest.mul(_SCALING_FACTOR.sub(reserveFactor)).mul(borrowsPer)
+ ) / _SCALING_FACTOR_SQUARED;
+ }
+
+ function _getUnderlyingName() internal pure returns (string memory underlyingName) {
+ underlyingName = _UNDERLYING_NAME;
+ }
+
+ function _getUnderlying() internal pure returns (address underlying) {
+ underlying = address(_DAI);
+ }
+
+ function _getCTokenSymbol() internal pure returns (string memory cTokenSymbol) {
+ cTokenSymbol = _CTOKEN_SYMBOL;
+ }
+
+ function _getCToken() internal pure returns (address cToken) {
+ cToken = address(_CDAI);
+ }
+
+ function _getDTokenName() internal pure returns (string memory dTokenName) {
+ dTokenName = _NAME;
+ }
+
+ function _getDTokenSymbol() internal pure returns (string memory dTokenSymbol) {
+ dTokenSymbol = _SYMBOL;
+ }
+
+ function _getVault() internal pure returns (address vault) {
+ vault = _VAULT;
+ }
+
+ /**
+ * @notice Internal pure function to emulate exponentiation performed by the
+ * Dai Savings Rate contract.
+ * @param x uint256 The number that will be raised to the given power.
+ * @param n uint256 The power to raise that number by.
+ * @param base uint256 The scaling factor that will be applied to n and z.
+ * @return The number raised to the given power.
+ */
+ function _rpow(
+ uint256 x, uint256 n, uint256 base
+ ) internal pure returns (uint256 z) {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ switch x case 0 {switch n case 0 {z := base} default {z := 0}}
+ default {
+ switch mod(n, 2) case 0 { z := base } default { z := x }
+ let half := div(base, 2) // for rounding.
+ for { n := div(n, 2) } n { n := div(n, 2) } {
+ let xx := mul(x, x)
+ if iszero(eq(div(xx, x), x)) { revert(0, 0) }
+ let xxRound := add(xx, half)
+ if lt(xxRound, xx) { revert(0, 0) }
+ x := div(xxRound, base)
+ if mod(n, 2) {
+ let zx := mul(z, x)
+ if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
+ let zxRound := add(zx, half)
+ if lt(zxRound, zx) { revert(0, 0) }
+ z := div(zxRound, base)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/mock/RelayContract.sol b/contracts/mock/RelayContract.sol
deleted file mode 100644
index c6e5018..0000000
--- a/contracts/mock/RelayContract.sol
+++ /dev/null
@@ -1,73 +0,0 @@
-pragma solidity 0.5.11;
-pragma experimental ABIEncoderV2;
-
-
-// A contract that is uniquely associated with one Dharma user,
-// who can use it to store funds and execute transactions "trustlessly".
-contract RelayContract {
- // The public address of the key pair that controls this relay contract.
- address public controller;
-
- // A struct representation of a signature.
- struct ECDSASignature {
- uint8 v;
- bytes32 r;
- bytes32 s;
- }
-
- // A struct representing the parameters required for to execute a transaction.
- struct transactionParameters {
- address to;
- bytes data;
- uint value;
- ECDSASignature signature;
- address signer;
- uint nonce;
- }
-
- // Events related to setting the controller variable.
- event SetControllerAttempt(address candidate);
- event SetControllerSuccess(address candidate);
- event SetControllerFailure(address candidate);
-
- // Events related to executing transactions.
- event ExecuteTransactionAttempt(
- address to,
- address signer
- );
- event ExecuteTransactionSuccess(
- address to,
- address signer
- );
-
- // The prefix used for all signed messages.
- bytes constant internal PREFIX = "\x19Ethereum Signed Message:\n32";
-
- // A function that can only be executed once, by the original deployer.
- function setController(address candidate) public {
- emit SetControllerAttempt(candidate);
-
- if (msg.sender == controller) {
- controller = candidate;
-
- emit SetControllerSuccess(candidate);
- } else {
- emit SetControllerFailure(candidate);
- }
- }
-
- // A function that returns the controller of the current contract.
- function getController() public view returns (address) {
- return controller;
- }
-
- function recoverSignerAddress(
- bytes32 prefixedHash,
- ECDSASignature memory signature
- ) public view returns (address signer) {
- return ecrecover(prefixedHash, signature.v, signature.r, signature.s);
- }
-
- // Payable fallback function
- function () external payable {}
-}
\ No newline at end of file
diff --git a/contracts/mock/RelayContractV2.sol b/contracts/mock/RelayContractV2.sol
deleted file mode 100644
index f42f495..0000000
--- a/contracts/mock/RelayContractV2.sol
+++ /dev/null
@@ -1,133 +0,0 @@
-pragma solidity 0.5.11;
-pragma experimental ABIEncoderV2;
-
-import "@openzeppelin/contracts/ownership/Ownable.sol";
-import "./RelayContract.sol";
-
-
-// V2 of Relay Contracts
-contract RelayContractV2 is RelayContract, Ownable {
- // A list of the hash of completed transactions,
- // to prevent replay attacks.
- mapping (bytes32 => bool) public completedTransactions;
-
- // Emitted when funds are paid to this contract.
- event ETHReceived(
- address payee,
- uint256 value
- );
-
- // Events related to force-changing the controller variable.
- event ForceChangeControllerSuccess(
- address candidate,
- address sender
- );
-
- // Takes in the address of the owner, and the address of the controller.
- // The owner is an offline address for emergency use.
- constructor(address ownerIn, address controllerIn) public payable {
- controller = controllerIn;
- transferOwnership(ownerIn);
- }
-
- // Given parameters for a transaction, execute that transaction.
- function executeTransaction(
- transactionParameters memory parameters
- ) public
- {
- address to = parameters.to;
- bytes memory data = parameters.data;
- uint value = parameters.value;
- address signer = parameters.signer;
-
- // An attempt has been made to execute a transaction; log an event.
- emit ExecuteTransactionAttempt(to, signer);
-
- // Prevent unsigned transactions or replay attacks.
- requireUniqueAndSignedByController(parameters);
-
- // Execute the transaction.
- (bool ok, ) = to.call.value(value)(data);
- require(ok, "Transaction failed during execution");
-
- // The execution was successfully submitted; log a success event.
- emit ExecuteTransactionSuccess(to, signer);
- }
-
- // Allows an array of transactions to be executed serially.
- function executeTransactions(
- transactionParameters[] memory transactions
- ) public
- {
- for (uint8 i = 0 ; i < transactions.length; i++) {
- executeTransaction(transactions[i]);
- }
- }
-
- // Reverts if the transaction was not signed by the controller,
- // of if the transaction has already been submitted.
- function requireUniqueAndSignedByController(
- transactionParameters memory parameters
- ) public returns (bool) {
- address to = parameters.to;
- bytes memory data = parameters.data;
- uint value = parameters.value;
- address signer = parameters.signer;
- uint nonce = parameters.nonce;
- ECDSASignature memory signature = parameters.signature;
-
- // The person who signed the data must be the controller of the contract.
- require(signer == controller);
-
- // Ethereum prefixed hash of the data.
- bytes32 prefixedHash = getHash(to, data, value, nonce);
-
- // Prevent replay attacks.
- requireIsUniqueTransaction(prefixedHash);
-
- // We verify that the given signer address signed the hash.
- address recoveredSigner = recoverSignerAddress(prefixedHash, signature);
-
- require(
- recoveredSigner == signer,
- "Controller is not authorized to execute transaction"
- );
- }
-
- function getHash(
- address to,
- bytes memory data,
- uint value,
- uint nonce
- ) public view returns (bytes32 prefixedHash) {
- // A hash of all the relevant data.
- bytes32 hash = keccak256(abi.encodePacked(to, data, value, nonce));
-
- // Ethereum prefixed hash of the data.
- return keccak256(abi.encodePacked(PREFIX, hash));
- }
-
- function requireIsUniqueTransaction(bytes32 prefixedHash) public {
- require(
- !completedTransactions[prefixedHash],
- "Nonce has already been used for these transaction parameters"
- );
-
- // Store that this transaction has completed.
- completedTransactions[prefixedHash] = true;
- }
-
- function forceChangeController(address candidate) public onlyOwner {
- controller = candidate;
-
- emit ForceChangeControllerSuccess(candidate, msg.sender);
- }
-
- // Payable fallback function
- function () external payable {
- emit ETHReceived(
- msg.sender,
- msg.value
- );
- }
-}
\ No newline at end of file
diff --git a/contracts/proxies/token/DharmaDai.sol b/contracts/proxies/token/DharmaDai.sol
new file mode 100644
index 0000000..ee7a4fe
--- /dev/null
+++ b/contracts/proxies/token/DharmaDai.sol
@@ -0,0 +1,55 @@
+pragma solidity 0.5.11; // optimization runs: 200, evm version: petersburg
+
+
+/**
+ * @title DharmaDai
+ * @author 0age
+ * @notice Dharma Dai is an upgradeable ERC20 token that delegates all logic to
+ * an implementation contract specified by a hard-coded "upgrade beacon"
+ * contract.
+ */
+contract DharmaDai {
+ // Set upgrade beacon address as a constant (i.e. not in contract storage).
+ address private constant _UPGRADE_BEACON = address(
+ 0x0000000000ccCf289727C20269911159a7bf9eBd
+ );
+
+ /**
+ * @notice In the fallback, delegate execution to the implementation set on
+ * the upgrade beacon.
+ */
+ function () external payable {
+ // Get the current implementation address from the upgrade beacon.
+ (bool ok, bytes memory returnData) = _UPGRADE_BEACON.staticcall("");
+
+ // Revert and pass along revert message if call to upgrade beacon reverts.
+ if (!ok) {
+ assembly {
+ returndatacopy(0, 0, returndatasize)
+ revert(0, returndatasize)
+ }
+ }
+
+ // Put implementation address returned from the upgrade beacon on the stack.
+ address implementation = abi.decode(returnData, (address));
+
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+ calldatacopy(0, 0, calldatasize)
+
+ // Delegatecall to the implementation, supplying calldata and gas.
+ // Out and outsize are set to zero - instead, use the return buffer.
+ let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
+
+ // Copy the returned data from the return buffer.
+ returndatacopy(0, 0, returndatasize)
+
+ switch result
+ // Delegatecall returns 0 on error.
+ case 0 { revert(0, returndatasize) }
+ default { return(0, returndatasize) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/proxies/token/DharmaUSDC.sol b/contracts/proxies/token/DharmaUSDC.sol
new file mode 100644
index 0000000..8c0f395
--- /dev/null
+++ b/contracts/proxies/token/DharmaUSDC.sol
@@ -0,0 +1,55 @@
+pragma solidity 0.5.11; // optimization runs: 200, evm version: petersburg
+
+
+/**
+ * @title DharmaUSDC
+ * @author 0age
+ * @notice Dharma USD Coin is an upgradeable ERC20 token that delegates all
+ * logic to an implementation contract specified by a hard-coded "upgrade
+ *beacon" contract.
+ */
+contract DharmaUSDC {
+ // Set upgrade beacon address as a constant (i.e. not in contract storage).
+ address private constant _UPGRADE_BEACON = address(
+ 0x00000000000274bE4365Aa18CfDC9A22A947f67D
+ );
+
+ /**
+ * @notice In the fallback, delegate execution to the implementation set on
+ * the upgrade beacon.
+ */
+ function () external payable {
+ // Get the current implementation address from the upgrade beacon.
+ (bool ok, bytes memory returnData) = _UPGRADE_BEACON.staticcall("");
+
+ // Revert and pass along revert message if call to upgrade beacon reverts.
+ if (!ok) {
+ assembly {
+ returndatacopy(0, 0, returndatasize)
+ revert(0, returndatasize)
+ }
+ }
+
+ // Put implementation address returned from the upgrade beacon on the stack.
+ address implementation = abi.decode(returnData, (address));
+
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+ calldatacopy(0, 0, calldatasize)
+
+ // Delegatecall to the implementation, supplying calldata and gas.
+ // Out and outsize are set to zero - instead, use the return buffer.
+ let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
+
+ // Copy the returned data from the return buffer.
+ returndatacopy(0, 0, returndatasize)
+
+ switch result
+ // Delegatecall returns 0 on error.
+ case 0 { revert(0, returndatasize) }
+ default { return(0, returndatasize) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/test/BalanceChecker.sol b/contracts/test/BalanceChecker.sol
new file mode 100644
index 0000000..0efc63d
--- /dev/null
+++ b/contracts/test/BalanceChecker.sol
@@ -0,0 +1,89 @@
+pragma solidity 0.5.11;
+
+import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import "../../interfaces/CTokenInterface.sol";
+import "../../interfaces/DTokenInterface.sol";
+
+
+/**
+ * @title BalanceChecker
+ */
+contract BalanceChecker {
+ IERC20 internal constant _DDAI = IERC20(
+ 0x00000000001876eB1444c986fD502e618c587430 // mainnet
+ );
+
+ IERC20 internal constant _DUSDC = IERC20(
+ 0x00000000008943c65cAf789FFFCF953bE156f6f8 // mainnet
+ );
+
+ IERC20 internal constant _DAI = IERC20(
+ 0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
+ );
+
+ IERC20 internal constant _USDC = IERC20(
+ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
+ );
+
+ IERC20 internal constant _SAI = IERC20(
+ 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359 // mainnet
+ );
+
+ IERC20 internal constant _CSAI = IERC20(
+ 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC // mainnet
+ );
+
+ IERC20 internal constant _CDAI = IERC20(
+ 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 // mainnet
+ );
+
+ IERC20 internal constant _CUSDC = IERC20(
+ 0x39AA39c021dfbaE8faC545936693aC917d5E7563 // mainnet
+ );
+
+ function getBalances(address wallet) external view returns (
+ uint256 dDaiBalance,
+ uint256 dUSDCBalance,
+ uint256 daiBalance,
+ uint256 usdcBalance,
+ uint256 saiBalance,
+ uint256 cSaiBalance,
+ uint256 cDaiBalance,
+ uint256 cUSDCBalance,
+ uint256 etherBalance
+ ) {
+ dDaiBalance = _DDAI.balanceOf(wallet);
+ dUSDCBalance = _DUSDC.balanceOf(wallet);
+ daiBalance = _DAI.balanceOf(wallet);
+ usdcBalance = _USDC.balanceOf(wallet);
+ saiBalance = _SAI.balanceOf(wallet);
+ cSaiBalance = _CSAI.balanceOf(wallet);
+ cDaiBalance = _CDAI.balanceOf(wallet);
+ cUSDCBalance = _CUSDC.balanceOf(wallet);
+ etherBalance = wallet.balance;
+ }
+
+ function getUnderlyingBalances(address wallet) external returns (
+ uint256 dDaiExchangeRate,
+ uint256 dUSDCExchangeRate,
+ uint256 cSaiExchangeRate,
+ uint256 cDaiExchangeRate,
+ uint256 cUSDCExchangeRate,
+ uint256 dDaiBalanceUnderlying,
+ uint256 dUSDCBalanceUnderlying,
+ uint256 cSaiBalanceUnderlying,
+ uint256 cDaiBalanceUnderlying,
+ uint256 cUSDCBalanceUnderlying
+ ) {
+ dDaiExchangeRate = DTokenInterface(address(_DDAI)).exchangeRateCurrent();
+ dUSDCExchangeRate = DTokenInterface(address(_DUSDC)).exchangeRateCurrent();
+ cSaiExchangeRate = CTokenInterface(address(_CSAI)).exchangeRateCurrent();
+ cDaiExchangeRate = CTokenInterface(address(_CDAI)).exchangeRateCurrent();
+ cUSDCExchangeRate = CTokenInterface(address(_CUSDC)).exchangeRateCurrent();
+ dDaiBalanceUnderlying = DTokenInterface(address(_DDAI)).balanceOfUnderlying(wallet);
+ dUSDCBalanceUnderlying = DTokenInterface(address(_DUSDC)).balanceOfUnderlying(wallet);
+ cSaiBalanceUnderlying = CTokenInterface(address(_CSAI)).balanceOfUnderlying(wallet);
+ cDaiBalanceUnderlying = CTokenInterface(address(_CDAI)).balanceOfUnderlying(wallet);
+ cUSDCBalanceUnderlying = CTokenInterface(address(_CUSDC)).balanceOfUnderlying(wallet);
+ }
+}
\ No newline at end of file
diff --git a/contracts/upgradeability/token/DharmaDaiUpgradeBeacon.sol b/contracts/upgradeability/token/DharmaDaiUpgradeBeacon.sol
new file mode 100644
index 0000000..75f7337
--- /dev/null
+++ b/contracts/upgradeability/token/DharmaDaiUpgradeBeacon.sol
@@ -0,0 +1,38 @@
+pragma solidity 0.5.11; // optimization runs: 200, evm version: petersburg
+
+
+/**
+ * @title DharmaDaiUpgradeBeacon
+ * @author 0age
+ * @notice This contract holds the address of the current implementation for
+ * Dharma Dai and lets a controller update that address in storage.
+ */
+contract DharmaDaiUpgradeBeacon {
+ // The implementation address is held in storage slot zero.
+ address private _implementation;
+
+ // The controller that can update the implementation is set as a constant.
+ address private constant _CONTROLLER = address(
+ 0x00000000001E980d286bE7f5f978f4Cc33128202
+ );
+
+ /**
+ * @notice In the fallback function, allow only the controller to update the
+ * implementation address - for all other callers, return the current address.
+ * Note that this requires inline assembly, as Solidity fallback functions do
+ * not natively take arguments or return values.
+ */
+ function () external {
+ // Return implementation address for all callers other than the controller.
+ if (msg.sender != _CONTROLLER) {
+ // Load implementation from storage slot zero into memory and return it.
+ assembly {
+ mstore(0, sload(0))
+ return(0, 32)
+ }
+ } else {
+ // Set implementation - put first word in calldata in storage slot zero.
+ assembly { sstore(0, calldataload(0)) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/upgradeability/token/DharmaUSDCUpgradeBeacon.sol b/contracts/upgradeability/token/DharmaUSDCUpgradeBeacon.sol
new file mode 100644
index 0000000..692da40
--- /dev/null
+++ b/contracts/upgradeability/token/DharmaUSDCUpgradeBeacon.sol
@@ -0,0 +1,38 @@
+pragma solidity 0.5.11; // optimization runs: 200, evm version: petersburg
+
+
+/**
+ * @title DharmaUSDCUpgradeBeacon
+ * @author 0age
+ * @notice This contract holds the address of the current implementation for
+ * Dharma USD Coin and lets a controller update that address in storage.
+ */
+contract DharmaUSDCUpgradeBeacon {
+ // The implementation address is held in storage slot zero.
+ address private _implementation;
+
+ // The controller that can update the implementation is set as a constant.
+ address private constant _CONTROLLER = address(
+ 0x0000000000796dC3aA12EB9FE3B6e8F4D92cc966
+ );
+
+ /**
+ * @notice In the fallback function, allow only the controller to update the
+ * implementation address - for all other callers, return the current address.
+ * Note that this requires inline assembly, as Solidity fallback functions do
+ * not natively take arguments or return values.
+ */
+ function () external {
+ // Return implementation address for all callers other than the controller.
+ if (msg.sender != _CONTROLLER) {
+ // Load implementation from storage slot zero into memory and return it.
+ assembly {
+ mstore(0, sload(0))
+ return(0, 32)
+ }
+ } else {
+ // Set implementation - put first word in calldata in storage slot zero.
+ assembly { sstore(0, calldataload(0)) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/account-recovery/DharmaAccountRecoveryManager.sol b/extra-contracts/account-recovery/DharmaAccountRecoveryManager.sol
similarity index 100%
rename from contracts/account-recovery/DharmaAccountRecoveryManager.sol
rename to extra-contracts/account-recovery/DharmaAccountRecoveryManager.sol
diff --git a/contracts/helpers/FactoryFactFinder.sol b/extra-contracts/helpers/FactoryFactFinder.sol
similarity index 100%
rename from contracts/helpers/FactoryFactFinder.sol
rename to extra-contracts/helpers/FactoryFactFinder.sol
diff --git a/contracts/helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol b/extra-contracts/helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol
similarity index 100%
rename from contracts/helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol
rename to extra-contracts/helpers/SmartWalletFactoryV1UserSigningKeyUpdater.sol
diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol b/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol
similarity index 100%
rename from contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol
rename to extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV0.sol
diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol b/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol
similarity index 100%
rename from contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol
rename to extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV1.sol
diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol b/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol
similarity index 100%
rename from contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol
rename to extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV2.sol
diff --git a/contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol b/extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol
similarity index 100%
rename from contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol
rename to extra-contracts/implementations/smart-wallet/DharmaSmartWalletImplementationV5.sol
diff --git a/contracts/registries/DharmaKeyRegistryV1.sol b/extra-contracts/registries/DharmaKeyRegistryV1.sol
similarity index 100%
rename from contracts/registries/DharmaKeyRegistryV1.sol
rename to extra-contracts/registries/DharmaKeyRegistryV1.sol
diff --git a/interfaces/CDaiInterestRateModelInterface.sol b/interfaces/CDaiInterestRateModelInterface.sol
new file mode 100644
index 0000000..23e10cc
--- /dev/null
+++ b/interfaces/CDaiInterestRateModelInterface.sol
@@ -0,0 +1,12 @@
+pragma solidity 0.5.11;
+
+
+interface CDaiInterestRateModelInterface {
+ function getBorrowRate(
+ uint256 cash, uint256 borrows, uint256 reserves
+ ) external view returns (uint256 borrowRate);
+
+ function getSupplyRate(
+ uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactor
+ ) external view returns (uint256 supplyRate);
+}
\ No newline at end of file
diff --git a/interfaces/CTokenInterface.sol b/interfaces/CTokenInterface.sol
index ec9d9f6..2757e5b 100644
--- a/interfaces/CTokenInterface.sol
+++ b/interfaces/CTokenInterface.sol
@@ -3,26 +3,24 @@ pragma solidity 0.5.11;
interface CTokenInterface {
function mint(uint256 mintAmount) external returns (uint256 err);
-
function redeem(uint256 redeemAmount) external returns (uint256 err);
-
function redeemUnderlying(uint256 redeemAmount) external returns (uint256 err);
-
- function balanceOf(address account) external returns (uint256 balance);
-
+ function accrueInterest() external returns (uint256 err);
+ function transfer(address recipient, uint256 value) external returns (bool);
+ function transferFrom(address sender, address recipient, uint256 value) external returns (bool);
+ function approve(address spender, uint256 amount) external returns (bool);
function balanceOfUnderlying(address account) external returns (uint256 balance);
-
- function borrow(uint256 borrowAmount) external returns (uint256 err);
-
- function repayBorrow(uint256 borrowAmount) external returns (uint256 err);
-
- // NOTE: we could use borrowBalanceStored if interest has already been accrued
- function borrowBalanceCurrent(address account) external returns (uint256 err);
-
- function getAccountSnapshot(address account) external view returns (
- uint256 err,
- uint256 cTokenBalance,
- uint256 borrowBalance,
- uint256 exchangeRateMantissa
- ); // balanceOfUnderlying = (cTokenBalance * exchangeRateMantissa) / 1e18
+ function exchangeRateCurrent() external returns (uint256 exchangeRate);
+
+ function getCash() external view returns (uint256);
+ function totalSupply() external view returns (uint256 supply);
+ function totalBorrows() external view returns (uint256 borrows);
+ function totalReserves() external view returns (uint256 reserves);
+ function interestRateModel() external view returns (address model);
+ function reserveFactorMantissa() external view returns (uint256 factor);
+ function supplyRatePerBlock() external view returns (uint256 rate);
+ function exchangeRateStored() external view returns (uint256 rate);
+ function accrualBlockNumber() external view returns (uint256 blockNumber);
+ function balanceOf(address account) external view returns (uint256 balance);
+ function allowance(address owner, address spender) external view returns (uint256);
}
\ No newline at end of file
diff --git a/interfaces/CUSDCInterestRateModelInterface.sol b/interfaces/CUSDCInterestRateModelInterface.sol
new file mode 100644
index 0000000..57b679f
--- /dev/null
+++ b/interfaces/CUSDCInterestRateModelInterface.sol
@@ -0,0 +1,8 @@
+pragma solidity 0.5.11;
+
+
+interface CUSDCInterestRateModelInterface {
+ function getBorrowRate(
+ uint256 cash, uint256 borrows, uint256 reserves
+ ) external view returns (uint256 err, uint256 borrowRate);
+}
\ No newline at end of file
diff --git a/interfaces/DTokenInterface.sol b/interfaces/DTokenInterface.sol
new file mode 100644
index 0000000..9869295
--- /dev/null
+++ b/interfaces/DTokenInterface.sol
@@ -0,0 +1,62 @@
+pragma solidity 0.5.11;
+
+/**
+ * @title DTokenInterface
+ * @author 0age
+ * @notice Interface for dTokens (in addition to the standard ERC20 interface).
+ */
+interface DTokenInterface {
+ // Events bear similarity to Compound's supply-related events.
+ event Mint(address minter, uint256 mintAmount, uint256 mintDTokens);
+ event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemDTokens);
+ event Accrue(uint256 dTokenExchangeRate, uint256 cTokenExchangeRate);
+ event CollectSurplus(uint256 surplusAmount, uint256 surplusCTokens);
+
+ // The block number and cToken + dToken exchange rates are updated on accrual.
+ struct AccrualIndex {
+ uint112 dTokenExchangeRate;
+ uint112 cTokenExchangeRate;
+ uint32 block;
+ }
+
+ // These external functions trigger accrual on the dToken and backing cToken.
+ function mint(uint256 underlyingToSupply) external returns (uint256 dTokensMinted);
+ function redeem(uint256 dTokensToBurn) external returns (uint256 underlyingReceived);
+ function redeemUnderlying(uint256 underlyingToReceive) external returns (uint256 dTokensBurned);
+ function pullSurplus() external returns (uint256 cTokenSurplus);
+
+ // These external functions only trigger accrual on the dToken.
+ function mintViaCToken(uint256 cTokensToSupply) external returns (uint256 dTokensMinted);
+ function redeemToCToken(uint256 dTokensToBurn) external returns (uint256 cTokensReceived);
+ function redeemUnderlyingToCToken(uint256 underlyingToReceive) external returns (uint256 dTokensBurned);
+ function accrueInterest() external;
+ function transferUnderlying(address recipient, uint256 underlyingEquivalentAmount) external returns (bool success);
+ function transferUnderlyingFrom(address sender, address recipient, uint256 underlyingEquivalentAmount) external returns (bool success);
+
+ // This function provides basic meta-tx support and does not trigger accrual.
+ function modifyAllowanceViaMetaTransaction(
+ address owner,
+ address spender,
+ uint256 value,
+ bool increase,
+ uint256 expiration,
+ bytes32 salt,
+ bytes calldata signatures
+ ) external returns (bool success);
+
+ // View and pure functions do not trigger accrual on the dToken or the cToken.
+ function getMetaTransactionMessageHash(
+ bytes4 functionSelector, bytes calldata arguments, uint256 expiration, bytes32 salt
+ ) external view returns (bytes32 digest, bool valid);
+ function totalSupplyUnderlying() external view returns (uint256);
+ function balanceOfUnderlying(address account) external view returns (uint256 underlyingBalance);
+ function exchangeRateCurrent() external view returns (uint256 dTokenExchangeRate);
+ function supplyRatePerBlock() external view returns (uint256 dTokenInterestRate);
+ function accrualBlockNumber() external view returns (uint256 blockNumber);
+ function getSurplus() external view returns (uint256 cTokenSurplus);
+ function getSurplusUnderlying() external view returns (uint256 underlyingSurplus);
+ function getSpreadPerBlock() external view returns (uint256 rateSpread);
+ function getVersion() external pure returns (uint256 version);
+ function getCToken() external pure returns (address cToken);
+ function getUnderlying() external pure returns (address underlying);
+}
\ No newline at end of file
diff --git a/interfaces/DharmaSmartWalletImplementationV7Interface.sol b/interfaces/DharmaSmartWalletImplementationV7Interface.sol
new file mode 100644
index 0000000..3e6b790
--- /dev/null
+++ b/interfaces/DharmaSmartWalletImplementationV7Interface.sol
@@ -0,0 +1,106 @@
+pragma solidity 0.5.11;
+
+
+interface DharmaSmartWalletImplementationV7Interface {
+ // Fires when a new user signing key is set on the smart wallet.
+ event NewUserSigningKey(address userSigningKey);
+
+ // Fires when an error occurs as part of an attempted action.
+ event ExternalError(address indexed source, string revertReason);
+
+ // The smart wallet recognizes DAI, USDC, ETH, and SAI as supported assets.
+ enum AssetType {
+ DAI,
+ USDC,
+ ETH,
+ SAI
+ }
+
+ // Actions, or protected methods (i.e. not deposits) each have an action type.
+ enum ActionType {
+ Cancel,
+ SetUserSigningKey,
+ Generic,
+ GenericAtomicBatch,
+ SAIWithdrawal,
+ USDCWithdrawal,
+ ETHWithdrawal,
+ SetEscapeHatch,
+ RemoveEscapeHatch,
+ DisableEscapeHatch,
+ DAIWithdrawal,
+ SignatureVerification,
+ DAIBorrow,
+ USDCBorrow
+ }
+
+ function initialize(address userSigningKey) external;
+
+ function repayAndDeposit() external;
+
+ function withdrawDai(
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok);
+
+ function withdrawUSDC(
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external returns (bool ok);
+
+ function cancel(
+ uint256 minimumActionGas,
+ bytes calldata signature
+ ) external;
+
+ function setUserSigningKey(
+ address userSigningKey,
+ uint256 minimumActionGas,
+ bytes calldata userSignature,
+ bytes calldata dharmaSignature
+ ) external;
+
+ function migrateSaiToDai() external;
+
+ function migrateCSaiToDDai() external;
+
+ function migrateCDaiToDDai() external;
+
+ function migrateCUSDCToDUSDC() external;
+
+ function getBalances() external view returns (
+ uint256 daiBalance,
+ uint256 usdcBalance,
+ uint256 etherBalance,
+ uint256 dDaiUnderlyingDaiBalance,
+ uint256 dUsdcUnderlyingUsdcBalance,
+ uint256 dEtherUnderlyingEtherBalance // always returns zero
+ );
+
+ function getUserSigningKey() external view returns (address userSigningKey);
+
+ function getNonce() external view returns (uint256 nonce);
+
+ function getNextCustomActionID(
+ ActionType action,
+ uint256 amount,
+ address recipient,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID);
+
+ function getCustomActionID(
+ ActionType action,
+ uint256 amount,
+ address recipient,
+ uint256 nonce,
+ uint256 minimumActionGas
+ ) external view returns (bytes32 actionID);
+
+ function getVersion() external pure returns (uint256 version);
+}
\ No newline at end of file
diff --git a/interfaces/ERC1271Interface.sol b/interfaces/ERC1271Interface.sol
new file mode 100644
index 0000000..a14fd0c
--- /dev/null
+++ b/interfaces/ERC1271Interface.sol
@@ -0,0 +1,8 @@
+pragma solidity 0.5.11;
+
+
+interface ERC1271Interface {
+ function isValidSignature(
+ bytes calldata data, bytes calldata signature
+ ) external view returns (bytes4 magicValue);
+}
\ No newline at end of file
diff --git a/interfaces/ERC20Interface.sol b/interfaces/ERC20Interface.sol
new file mode 100644
index 0000000..fa9afe4
--- /dev/null
+++ b/interfaces/ERC20Interface.sol
@@ -0,0 +1,14 @@
+pragma solidity 0.5.11;
+
+interface ERC20Interface {
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ function transfer(address recipient, uint256 amount) external returns (bool);
+ function allowance(address owner, address spender) external view returns (uint256);
+ function approve(address spender, uint256 amount) external returns (bool);
+ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
+
+ function totalSupply() external view returns (uint256);
+ function balanceOf(address account) external view returns (uint256);
+}
diff --git a/interfaces/PotInterface.sol b/interfaces/PotInterface.sol
new file mode 100644
index 0000000..7af173d
--- /dev/null
+++ b/interfaces/PotInterface.sol
@@ -0,0 +1,9 @@
+pragma solidity 0.5.11;
+
+
+interface PotInterface {
+ function chi() external view returns (uint256);
+ function dsr() external view returns (uint256);
+ function rho() external view returns (uint256);
+ function pie(address account) external view returns (uint256);
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index d624dcf..dfe1ff9 100644
--- a/package.json
+++ b/package.json
@@ -1,31 +1,50 @@
{
- "name": "dharma-smart-wallet",
- "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",
- "dependencies": {
- "@openzeppelin/contracts": "2.3.0",
- "ethereumjs-util": "6.1.0",
- "ethlint": "1.2.5",
- "ganache-cli": "6.7.0",
- "ganache-cli-coverage": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz",
- "js-sha256": "0.9.0",
- "solhint": "2.3.0",
- "solidity-coverage": "0.6.7",
- "truffle": "5.1.4",
- "web3": "1.2.1"
- },
- "scripts": {
- "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 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 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
+ "name": "dharma-smart-wallet",
+ "version": "1.5.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",
+ "dependencies": {
+ "@openzeppelin/contracts": "2.3.0",
+ "ethereumjs-util": "6.1.0",
+ "ethlint": "1.2.5",
+ "ganache-cli": "6.7.0",
+ "ganache-cli-coverage": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz",
+ "js-sha256": "0.9.0",
+ "solhint": "2.3.0",
+ "solidity-coverage": "0.6.7",
+ "truffle": "5.1.4",
+ "web3": "1.2.1"
+ },
+ "devDependencies": {
+ "husky": "^4.2.1",
+ "lint-staged": "^9.2.1",
+ "prettier": "1.16.4",
+ "pretty-quick": "^2.0.1"
+ },
+ "scripts": {
+ "all": "export TESTING_CONTEXT=development ; ./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": "export TESTING_CONTEXT=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 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": "export TESTING_CONTEXT=development ; ./node_modules/.bin/truffle compile && node scripts/test/ci.js",
+ "prettier": "prettier --write"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "*.{js,css,json,md}": [
+ "prettier --debug-check",
+ "prettier --write",
+ "git add"
+ ]
+ }
+}
diff --git a/scripts/test/ci.js b/scripts/test/ci.js
index 4e4b4eb..39d8852 100644
--- a/scripts/test/ci.js
+++ b/scripts/test/ci.js
@@ -1,20 +1,16 @@
-const connectionConfig = require('../../truffle-config.js')
-
-const connection = connectionConfig.networks['development']
-
-let web3Provider = connection.provider
-
// import tests
-var deployMockExternal = require('./deployMockExternal.js')
-var deploy = require('./deploy.js')
-var test = require('./test.js')
+const deployMockExternal = require("./deployMockExternal.js");
+const deploy = require("./deploy");
+const test = require("./test");
// run tests
async function runTests() {
- await deployMockExternal.test(web3Provider, 'development')
- await deploy.test(web3Provider, 'development')
- await test.test(web3Provider, 'development')
- process.exit(0)
+ const context = process.env.TESTING_CONTEXT;
+
+ await deployMockExternal.test(context);
+ await deploy.test(context);
+ await test.test(context);
+ process.exit(0);
}
-runTests()
+runTests();
diff --git a/scripts/test/constants.js b/scripts/test/constants.js
index 03d8364..a91f9a2 100644
--- a/scripts/test/constants.js
+++ b/scripts/test/constants.js
@@ -1,537 +1,600 @@
module.exports = Object.freeze({
- NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
- NULL_BYTES_32: (
- '0x0000000000000000000000000000000000000000000000000000000000000000'
- ),
- EMPTY_HASH: (
- '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
- ),
- FULL_APPROVAL: (
- '115792089237316195423570985008687907853269984665640564039457584007913129639935'
- ),
- KEYLESS_CREATE2_DEPLOYER_ADDRESS: (
- '0x4c8D290a1B368ac4728d83a9e8321fC3af2b39b1'
- ),
- KEYLESS_CREATE2_DEPLOYMENT_TRANSACTION: (
- '0xf87e8085174876e800830186a08080ad601f80600e600039806000f350fe600036818237' +
- '80368234f58015156014578182fd5b80825250506014600cf31ba022222222222222222222' +
- '22222222222222222222222222222222222222222222a02222222222222222222222222222' +
- '222222222222222222222222222222222222'
- ),
- KEYLESS_CREATE2_ADDRESS: (
- '0x7A0D94F55792C434d74a40883C6ed8545E406D12'
- ),
- KEYLESS_CREATE2_RUNTIME_HASH: (
- '0x60003681823780368234f58015156014578182fd5b80825250506014600cf3'
- ),
- INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS: (
- '0xcfA3A7637547094fF06246817a35B8333C315196'
- ),
- IMMUTABLE_CREATE2_FACTORY_ADDRESS: (
- '0x0000000000FFe8B47B3e2130213B802212439497'
- ),
- IMMUTABLE_CREATE2_FACTORY_SALT: (
- '0x0000000000000000000000000000000000000000f4b0218f13a6440a6f020000'
- ),
- IMMUTABLE_CREATE2_FACTORY_CREATION_CODE: (
- '0x608060405234801561001057600080fd5b50610833806100206000396000f3fe60806040' +
- '526004361061003f5760003560e01c806308508b8f1461004457806364e030871461009857' +
- '806385cf97ab14610138578063a49a7c90146101bc575b600080fd5b348015610050576000' +
- '80fd5b506100846004803603602081101561006757600080fd5b503573ffffffffffffffff' +
- 'ffffffffffffffffffffffff166101ec565b604080519115158252519081900360200190f3' +
- '5b61010f600480360360408110156100ae57600080fd5b8135919081019060408101602082' +
- '01356401000000008111156100d057600080fd5b8201836020820111156100e257600080fd' +
- '5b8035906020019184600183028401116401000000008311171561010457600080fd5b5090' +
- '92509050610217565b6040805173ffffffffffffffffffffffffffffffffffffffff909216' +
- '8252519081900360200190f35b34801561014457600080fd5b5061010f6004803603604081' +
- '101561015b57600080fd5b8135919081019060408101602082013564010000000081111561' +
- '017d57600080fd5b82018360208201111561018f57600080fd5b8035906020019184600183' +
- '02840111640100000000831117156101b157600080fd5b509092509050610592565b348015' +
- '6101c857600080fd5b5061010f600480360360408110156101df57600080fd5b5080359060' +
- '20013561069e565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020' +
- '819052604090205460ff1690565b600083606081901c33148061024c57507fffffffffffff' +
- 'ffffffffffffffffffffffffffff0000000000000000000000008116155b6102a157604051' +
- '7f08c379a00000000000000000000000000000000000000000000000000000000081526004' +
- '01808060200182810382526045815260200180610774604591396060019150506040518091' +
- '0390fd5b606084848080601f01602080910402602001604051908101604052809392919081' +
- '81526020018383808284376000920182905250604051855195965090943094508b93508692' +
- '506020918201918291908401908083835b6020831061033557805182527fffffffffffffff' +
- 'ffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161' +
- '02f8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffffffffffffffff018019909216911617905260408051929094018281037fffff' +
- 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001835280855282' +
- '51928201929092207fff000000000000000000000000000000000000000000000000000000' +
- '000000008383015260609890981b7fffffffffffffffffffffffffffffffffffffffff0000' +
- '00000000000000000000166021830152603582019690965260558082019790975282518082' +
- '03909701875260750182525084519484019490942073ffffffffffffffffffffffffffffff' +
- 'ffffffffff81166000908152938490529390922054929350505060ff16156104a757604051' +
- '7f08c379a00000000000000000000000000000000000000000000000000000000081526004' +
- '0180806020018281038252603f815260200180610735603f91396040019150506040518091' +
- '0390fd5b81602001825188818334f5955050508073ffffffffffffffffffffffffffffffff' +
- 'ffffffff168473ffffffffffffffffffffffffffffffffffffffff161461053a576040517f' +
- '08c379a0000000000000000000000000000000000000000000000000000000008152600401' +
- '8080602001828103825260468152602001806107b960469139606001915050604051809103' +
- '90fd5b50505073ffffffffffffffffffffffffffffffffffffffff81166000908152602081' +
- '90526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'ffffff001660011790559392505050565b6000308484846040516020018083838082843760' +
- '408051919093018181037fffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffe001825280845281516020928301207fff000000000000000000000000000000' +
- '000000000000000000000000000000008383015260609990991b7fffffffffffffffffffff' +
- 'ffffffffffffffffffff000000000000000000000000166021820152603581019790975260' +
- '558088019890985282518088039098018852607590960182525085519585019590952073ff' +
- 'ffffffffffffffffffffffffffffffffffffff811660009081529485905294909320549394' +
- '50505060ff909116159050610697575060005b9392505050565b604080517fff0000000000' +
- '00000000000000000000000000000000000000000000000000006020808301919091523060' +
- '601b6021830152603582018590526055808301859052835180840390910181526075909201' +
- '835281519181019190912073ffffffffffffffffffffffffffffffffffffffff8116600090' +
- '8152918290529190205460ff161561072e575060005b9291505056fe496e76616c69642063' +
- '6f6e7472616374206372656174696f6e202d20636f6e74726163742068617320616c726561' +
- '6479206265656e206465706c6f7965642e496e76616c69642073616c74202d206669727374' +
- '203230206279746573206f66207468652073616c74206d757374206d617463682063616c6c' +
- '696e6720616464726573732e4661696c656420746f206465706c6f7920636f6e7472616374' +
- '207573696e672070726f76696465642073616c7420616e6420696e697469616c697a617469' +
- '6f6e20636f64652ea265627a7a723058202bdc55310d97c4088f18acf04253db593f091405' +
- '9f0c781a9df3624dcef0d1cf64736f6c634300050a0032'
- ),
- IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH: (
- '0x767db8f19b71e367540fa372e8e81e4dcb7ca8feede0ae58a0c0bd08b7320dee'
- ),
- ETH_WHALE_ADDRESS: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
- SAI_WHALE_ADDRESS: '0x76B03EB651153a81fA1f212f2f59329B4180A46F',
- DAI_WHALE_ADDRESS: '0x8134d518e0CeF5388136c0De43d7E12278701Ac5',
- USDC_WHALE_ADDRESS: '0x035e742A7E62253C606b9028eeB65178B44F1e7E',
- SAI_MAINNET_ADDRESS: '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359',
- DAI_MAINNET_ADDRESS: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
- USDC_MAINNET_ADDRESS: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
- CSAI_MAINNET_ADDRESS: '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC',
- 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'
- ),
- UPGRADE_BEACON_ENVOY_ADDRESS: (
- '0x000000000067503c398F4c9652530DBC4eA95C02'
- ),
- UPGRADE_BEACON_ENVOY_SALT: (
- '0x00000000000000000000000000000000000000003b4cf3f5b304150b79010000'
- ),
- UPGRADE_BEACON_ENVOY_CREATION_CODE: (
- '0x608060405234801561001057600080fd5b5061020d806100206000396000f3fe608060' +
- '405234801561001057600080fd5b506004361061002b5760003560e01c806315ac72ca14' +
- '610030575b600080fd5b6100566004803603602081101561004657600080fd5b50356001' +
- '600160a01b0316610072565b604080516001600160a01b03909216825251908190036020' +
- '0190f35b60405160009081906060906001600160a01b0385169083818181855afa915050' +
- '3d80600081146100be576040519150601f19603f3d011682016040523d82523d60006020' +
- '84013e6100c3565b606091505b50915091508181906101535760405162461bcd60e51b81' +
- '526004018080602001828103825283818151815260200191508051906020019080838360' +
- '005b83811015610118578181015183820152602001610100565b50505050905090810190' +
- '601f1680156101455780820380516001836020036101000a031916815260200191505b50' +
- '9250505060405180910390fd5b5080516020146101945760405162461bcd60e51b815260' +
- '04018080602001828103825260258152602001806101b460259139604001915050604051' +
- '80910390fd5b8080602001905160208110156101a957600080fd5b505194935050505056' +
- 'fe52657475726e2064617461206d7573742062652065786163746c792033322062797465' +
- '732ea265627a7a72315820107734a2fcd1d762a5f847530eab7552a2346f80ce0afa3765' +
- '70475d354bab3264736f6c634300050b0032'
- ),
- UPGRADE_BEACON_ENVOY_RUNTIME_CODE: (
- '0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806315' +
- 'ac72ca14610030575b600080fd5b6100566004803603602081101561004657600080fd5b' +
- '50356001600160a01b0316610072565b604080516001600160a01b039092168252519081' +
- '900360200190f35b60405160009081906060906001600160a01b0385169083818181855a' +
- 'fa9150503d80600081146100be576040519150601f19603f3d011682016040523d82523d' +
- '6000602084013e6100c3565b606091505b50915091508181906101535760405162461bcd' +
- '60e51b815260040180806020018281038252838181518152602001915080519060200190' +
- '80838360005b83811015610118578181015183820152602001610100565b505050509050' +
- '90810190601f1680156101455780820380516001836020036101000a0319168152602001' +
- '91505b509250505060405180910390fd5b5080516020146101945760405162461bcd60e5' +
- '1b81526004018080602001828103825260258152602001806101b4602591396040019150' +
- '5060405180910390fd5b8080602001905160208110156101a957600080fd5b5051949350' +
- '50505056fe52657475726e2064617461206d7573742062652065786163746c7920333220' +
- '62797465732ea265627a7a72315820107734a2fcd1d762a5f847530eab7552a2346f80ce' +
- '0afa376570475d354bab3264736f6c634300050b0032'
- ),
- UPGRADE_BEACON_CONTROLLER_ADDRESS: (
- '0x00000000002226C940b74d674B85E4bE05539663'
- ),
- UPGRADE_BEACON_CONTROLLER_SALT: (
- '0x00000000000000000000000000000000000000002401b098eebfab0f53080000'
- ),
- UPGRADE_BEACON_CONTROLLER_METADATA: (
- ['20446861726d6155706772616465426561636f6e436f6e74726f6c6c65722020']
- ),
- KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS: (
- '0x00000000011dF015e8aD00D7B2486a88C2Eb8210'
- ),
- KEY_RING_UPGRADE_BEACON_CONTROLLER_SALT: (
- '0x00000000000000000000000000000000000000003080ac79bc49c20d5a000000'
- ),
- KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA: (
- ['20446861726d614b657952696e67426561636f6e436f6e74726f6c6c65722020']
- ),
- KEY_RING_UPGRADE_BEACON_ADDRESS: (
- '0x0000000000BDA2152794ac8c76B2dc86cbA57cad'
- ),
- KEY_RING_UPGRADE_BEACON_SALT: (
- '0x0000000000000000000000000000000000000000ca2bc7ce5bd506089c100000'
- ),
- KEY_RING_UPGRADE_BEACON_METADATA: (
- ['202020446861726d614b657952696e6755706772616465426561636f6e202020']
- ),
- UPGRADE_BEACON_ADDRESS: (
- '0x000000000026750c571ce882B17016557279ADaa'
- ),
- UPGRADE_BEACON_SALT: (
- '0x000000000000000000000000000000000000000078c916fd79282f00051f0000'
- ),
- UPGRADE_BEACON_METADATA: (
- ['202020202020446861726d6155706772616465426561636f6e20202020202020']
- ),
- KEY_REGISTRY_ADDRESS: (
- '0x000000005D7065eB9716a410070Ee62d51092C98'
- ),
- KEY_REGISTRY_SALT: (
- '0x00000000000000000000000000000000000000003dafd25120eca50e14000000'
- ),
- KEY_REGISTRY_METADATA: (
- ['202020202020446861726d614b65795265676973747279563120202020202020']
- ),
- KEY_REGISTRY_V2_ADDRESS: (
- '0x000000000D38df53b45C5733c7b34000dE0BDF52'
- ),
- KEY_REGISTRY_V2_SALT: (
- '0x0000000000000000000000000000000000000000035383a4848e750d83000000'
- ),
- KEY_REGISTRY_V2_METADATA: (
- ['202020202020446861726d614b65795265676973747279563220202020202020']
- ),
- ACCOUNT_RECOVERY_MANAGER_ADDRESS: (
- '0x00000000004cDa75701EeA02D1F2F9BDcE54C10D'
- ),
- ACCOUNT_RECOVERY_MANAGER_SALT: (
- '0x000000000000000000000000000000000000000000f9460080747d0837020000'
- ),
- ACCOUNT_RECOVERY_MANAGER_METADATA: (
- ['2020446861726d614163636f756e745265636f766572794d616e616765722020']
- ),
- ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS: (
- '0x0000000000DfEd903aD76996FC07BF89C0127B1E'
- ),
- ACCOUNT_RECOVERY_MANAGER_V2_SALT: (
- '0x000000000000000000000000000000000000000009adfe40acf37300b2020000'
- ),
- ACCOUNT_RECOVERY_MANAGER_V2_METADATA: (
- ['20446861726d614163636f756e745265636f766572794d616e61676572563220']
- ),
- UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS: (
- '0x00000000008A10a98969A000D1C0AbA90F858D6a'
- ),
- UPGRADE_BEACON_CONTROLLER_MANAGER_SALT: (
- '0x000000000000000000000000000000000000000002661332276954010e060000'
- ),
- UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA: (
- ['2055706772616465426561636f6e436f6e74726f6c6c65724d616e6167657220']
- ),
- FACTORY_ADDRESS: (
- '0xfc00C80b0000007F73004edB00094caD80626d8D'
- ),
- FACTORY_SALT: (
- '0x0000000000000000000000000000000000000000e3c18f17dda93a0e08000000'
- ),
- FACTORY_METADATA: (
- [
- '202020446861726d61536d61727457616c6c6574466163746f72793120202020',
- '20202020202055706772616465426561636f6e50726f78795631202020202020'
- ]
- ),
- KEY_RING_FACTORY_ADDRESS: (
- '0x00DD005247B300f700cFdfF89C00e2aCC94c7b00'
- ),
- KEY_RING_FACTORY_SALT: (
- '0x00000000000000000000000000000000000000001429fc672990fb0320000000'
- ),
- KEY_RING_FACTORY_METADATA: (
- [
- '2020202020446861726d614b657952696e67466163746f727956312020202020',
- '20204b657952696e6755706772616465426561636f6e50726f78795631202020'
- ]
- ),
- KEY_RING_FACTORY_V2_ADDRESS: (
- '0x2484000059004afB720000dc738434fA6200F49D'
- ),
- KEY_RING_FACTORY_V2_SALT: (
- '0x00000000000000000000000000000000000000008b0de996664c5e0c18000000'
- ),
- KEY_RING_FACTORY_V2_METADATA: (
- [
- '2020202020446861726d614b657952696e67466163746f727956322020202020',
- '20204b657952696e6755706772616465426561636f6e50726f78795631202020'
- ]
- ),
- KEY_REGISTRY_MIMIC_ADDRESS: (
- '0x00000000D1dBC357A3f3D0f1F934D0186Ba40396'
- ),
- KEY_REGISTRY_MIMIC_SALT: (
- '0x000000000000000000000000000000000000000033a95ffc488dbf0114000000'
- ),
- KEY_REGISTRY_MIMIC_METADATA: (
- ['20202020446861726d614b6579526567697374727956314d696d696320202020']
- ),
- DHARMA_SMART_WALLET_IMPLEMENTATION_V1_ADDRESS: (
- '0x0000000010A653849F221A573E00f3A37C8C4082'
- ),
- DHARMA_SMART_WALLET_IMPLEMENTATION_V1_SALT: (
- '0x0000000000000000000000000000000000000000dfdbded845e0d00ca0000000'
- ),
- DHARMA_SMART_WALLET_IMPLEMENTATION_V1_METADATA: (
- ['446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e31']
- ),
- DHARMA_SMART_WALLET_IMPLEMENTATION_V3_METADATA: (
- ['446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e33']
- ),
- DHARMA_SMART_WALLET_IMPLEMENTATION_V5_METADATA: (
- ['446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e35']
- ),
- ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS: (
- '0x00000000009f22dA6fEB6735614563B9Af0339fB'
- ),
- ADHARMA_SMART_WALLET_IMPLEMENTATION_SALT: (
- '0x00000000000000000000000000000000000000003d317829ae4acc0b21020000'
- ),
- ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA: (
- ['41646861726d61536d61727457616c6c6574496d706c656d656e746174696f6e']
- ),
- ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS: (
- '0x000000000053d1F0F8aA88b9001Bec1B49445B3c'
- ),
- ADHARMA_KEY_RING_IMPLEMENTATION_SALT: (
- '0x0000000000000000000000000000000000000000935331d823b26c05182f0000'
- ),
- ADHARMA_KEY_RING_IMPLEMENTATION_METADATA: (
- ['202041646861726d614b657952696e67496d706c656d656e746174696f6e2020']
- ),
- ESCAPE_HATCH_REGISTRY_ADDRESS: (
- '0x00000000005280B515004B998a944630B6C663f8'
- ),
- ESCAPE_HATCH_REGISTRY_SALT: (
- '0x000000000000000000000000000000000000000082eb6220dd97c70002000000'
- ),
- ESCAPE_HATCH_REGISTRY_METADATA: (
- ['202020446861726d614573636170654861746368526567697374727920202020']
- ),
- INDESTRUCTIBLE_REGISTRY_ADDRESS: (
- '0x0000000000f55ff05D0080fE17A63b16596Fd59f'
- ),
- INDESTRUCTIBLE_REGISTRY_RUNTIME_HASH: (
- '0xadca137a47625f8ad1da20be107380101474374dc6c31ad0b8c1807558ea3c29'
- ),
- INDESTRUCTIBLE_REGISTRY_CREATION_TX: (
- '0x64e030870000000000000000000000000000000000000000a4ab82b860e6cb06780400' +
- '000000000000000000000000000000000000000000000000000000000000000040000000' +
- '000000000000000000000000000000000000000000000000000000046b60806040523480' +
- '1561001057600080fd5b5061044b806100206000396000f3fe6080604052348015610010' +
- '57600080fd5b50600436106100415760003560e01c80632c82288c146100465780633215' +
- '14321461008d5780636cf9ed9b146100c2575b600080fd5b610079600480360360208110' +
- '1561005c57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166100' +
- 'f5565b604080519115158252519081900360200190f35b6100c060048036036020811015' +
- '6100a357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610120' +
- '565b005b610079600480360360208110156100d857600080fd5b503573ffffffffffffff' +
- 'ffffffffffffffffffffffffff166101ce565b73ffffffffffffffffffffffffffffffff' +
- 'ffffffff1660009081526020819052604090205460ff1690565b610129816101df565b15' +
- '61017f576040517f08c379a0000000000000000000000000000000000000000000000000' +
- '00000000815260040180806020018281038252602c8152602001806103eb602c91396040' +
- '0191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff1660' +
- '0090815260208190526040902080547fffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffffffffffffff00166001179055565b60006101d9826101df565b9291505056' +
- '5b6000813b8061024f57604080517f08c379a00000000000000000000000000000000000' +
- '0000000000000000000000815260206004820152601260248201527f4e6f20636f646520' +
- '6174207461726765742e0000000000000000000000000000604482015290519081900360' +
- '640190fd5b60006060826040519080825280601f01601f19166020018201604052801561' +
- '027e576020820181803883390190505b50905060208101915082600083873c8183018281' +
- '116102fe57604080517f08c379a000000000000000000000000000000000000000000000' +
- '000000000000815260206004820152601c60248201527f536166654d6174683a20616464' +
- '6974696f6e206f766572666c6f772e00000000604482015290519081900360640190fd5b' +
- '60016000845b838110156103dd57805160f81c915082156103c7578160fe148061032857' +
- '508160f3145b8061033357508160fd145b8061033e5750816056145b8061034757508115' +
- '5b1561035557600092506103d5565b605f821180156103655750608082105b1561039357' +
- '81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa101' +
- '6103d5565b8160f214806103a257508160f4145b806103ad57508160ff145b156103c257' +
- '60019750505050505050506103e5565b6103d5565b81605b14156103d557600192505b60' +
- '0101610304565b505050505050505b91905056fe537570706c6965642074617267657420' +
- '697320706f74656e7469616c6c7920646573747275637469626c652ea265627a7a723158' +
- '20ba911a72b86ff753e41edde9621dd5f1c6169f5332418733e233da6d6678696564736f' +
- '6c634300050b0032000000000000000000000000000000000000000000'
- ),
- CONTRACT_NAMES: {
- '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': 'SAI',
- '0x6B175474E89094C44Da98b954EedeAC495271d0F': 'DAI',
- '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': 'USDC',
- '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC': 'CSAI',
- '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643': 'CDAI',
- '0x39AA39c021dfbaE8faC545936693aC917d5E7563': 'CUSDC',
- '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5': 'CETH',
- '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B': 'Comptroller'
- },
- EVENT_DETAILS: {
- // keccak256 of NewUserSigningKey(address) -> userSigningKey
- '0x7083aac3cab97f1219cedd0ab328a5b138a10b0fc72dd9348f1dc50199b21fda': {
- name: 'NewUserSigningKey',
- abi: [
- {
- type: 'address',
- name: 'userSigningKey'
- }
- ]
- },
- // ExternalError(address,string) -> source, reason
- '0x5bbd5ab79029b89a22c80c7b7bfdc2f0c8e3f0d2a7330c7148cabc044250674b': {
- name: 'ExternalError',
- abi: [
- {
- type: 'address',
- name: 'source',
- indexed: true
- }, {
- type: 'string',
- name: 'reason'
- }
- ]
+ NULL_ADDRESS: "0x0000000000000000000000000000000000000000",
+ NULL_BYTES_32:
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
+ EMPTY_HASH:
+ "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
+ FULL_APPROVAL:
+ "115792089237316195423570985008687907853269984665640564039457584007913129639935",
+ KEYLESS_CREATE2_DEPLOYER_ADDRESS:
+ "0x4c8D290a1B368ac4728d83a9e8321fC3af2b39b1",
+ KEYLESS_CREATE2_DEPLOYMENT_TRANSACTION:
+ "0xf87e8085174876e800830186a08080ad601f80600e600039806000f350fe600036818237" +
+ "80368234f58015156014578182fd5b80825250506014600cf31ba022222222222222222222" +
+ "22222222222222222222222222222222222222222222a02222222222222222222222222222" +
+ "222222222222222222222222222222222222",
+ KEYLESS_CREATE2_ADDRESS: "0x7A0D94F55792C434d74a40883C6ed8545E406D12",
+ KEYLESS_CREATE2_RUNTIME_HASH:
+ "0x60003681823780368234f58015156014578182fd5b80825250506014600cf3",
+ INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS:
+ "0xcfA3A7637547094fF06246817a35B8333C315196",
+ IMMUTABLE_CREATE2_FACTORY_ADDRESS:
+ "0x0000000000FFe8B47B3e2130213B802212439497",
+ IMMUTABLE_CREATE2_FACTORY_SALT:
+ "0x0000000000000000000000000000000000000000f4b0218f13a6440a6f020000",
+ IMMUTABLE_CREATE2_FACTORY_CREATION_CODE:
+ "0x608060405234801561001057600080fd5b50610833806100206000396000f3fe60806040" +
+ "526004361061003f5760003560e01c806308508b8f1461004457806364e030871461009857" +
+ "806385cf97ab14610138578063a49a7c90146101bc575b600080fd5b348015610050576000" +
+ "80fd5b506100846004803603602081101561006757600080fd5b503573ffffffffffffffff" +
+ "ffffffffffffffffffffffff166101ec565b604080519115158252519081900360200190f3" +
+ "5b61010f600480360360408110156100ae57600080fd5b8135919081019060408101602082" +
+ "01356401000000008111156100d057600080fd5b8201836020820111156100e257600080fd" +
+ "5b8035906020019184600183028401116401000000008311171561010457600080fd5b5090" +
+ "92509050610217565b6040805173ffffffffffffffffffffffffffffffffffffffff909216" +
+ "8252519081900360200190f35b34801561014457600080fd5b5061010f6004803603604081" +
+ "101561015b57600080fd5b8135919081019060408101602082013564010000000081111561" +
+ "017d57600080fd5b82018360208201111561018f57600080fd5b8035906020019184600183" +
+ "02840111640100000000831117156101b157600080fd5b509092509050610592565b348015" +
+ "6101c857600080fd5b5061010f600480360360408110156101df57600080fd5b5080359060" +
+ "20013561069e565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020" +
+ "819052604090205460ff1690565b600083606081901c33148061024c57507fffffffffffff" +
+ "ffffffffffffffffffffffffffff0000000000000000000000008116155b6102a157604051" +
+ "7f08c379a00000000000000000000000000000000000000000000000000000000081526004" +
+ "01808060200182810382526045815260200180610774604591396060019150506040518091" +
+ "0390fd5b606084848080601f01602080910402602001604051908101604052809392919081" +
+ "81526020018383808284376000920182905250604051855195965090943094508b93508692" +
+ "506020918201918291908401908083835b6020831061033557805182527fffffffffffffff" +
+ "ffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161" +
+ "02f8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffff" +
+ "ffffffffffffffffffffffff018019909216911617905260408051929094018281037fffff" +
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001835280855282" +
+ "51928201929092207fff000000000000000000000000000000000000000000000000000000" +
+ "000000008383015260609890981b7fffffffffffffffffffffffffffffffffffffffff0000" +
+ "00000000000000000000166021830152603582019690965260558082019790975282518082" +
+ "03909701875260750182525084519484019490942073ffffffffffffffffffffffffffffff" +
+ "ffffffffff81166000908152938490529390922054929350505060ff16156104a757604051" +
+ "7f08c379a00000000000000000000000000000000000000000000000000000000081526004" +
+ "0180806020018281038252603f815260200180610735603f91396040019150506040518091" +
+ "0390fd5b81602001825188818334f5955050508073ffffffffffffffffffffffffffffffff" +
+ "ffffffff168473ffffffffffffffffffffffffffffffffffffffff161461053a576040517f" +
+ "08c379a0000000000000000000000000000000000000000000000000000000008152600401" +
+ "8080602001828103825260468152602001806107b960469139606001915050604051809103" +
+ "90fd5b50505073ffffffffffffffffffffffffffffffffffffffff81166000908152602081" +
+ "90526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
+ "ffffff001660011790559392505050565b6000308484846040516020018083838082843760" +
+ "408051919093018181037fffffffffffffffffffffffffffffffffffffffffffffffffffff" +
+ "ffffffffffe001825280845281516020928301207fff000000000000000000000000000000" +
+ "000000000000000000000000000000008383015260609990991b7fffffffffffffffffffff" +
+ "ffffffffffffffffffff000000000000000000000000166021820152603581019790975260" +
+ "558088019890985282518088039098018852607590960182525085519585019590952073ff" +
+ "ffffffffffffffffffffffffffffffffffffff811660009081529485905294909320549394" +
+ "50505060ff909116159050610697575060005b9392505050565b604080517fff0000000000" +
+ "00000000000000000000000000000000000000000000000000006020808301919091523060" +
+ "601b6021830152603582018590526055808301859052835180840390910181526075909201" +
+ "835281519181019190912073ffffffffffffffffffffffffffffffffffffffff8116600090" +
+ "8152918290529190205460ff161561072e575060005b9291505056fe496e76616c69642063" +
+ "6f6e7472616374206372656174696f6e202d20636f6e74726163742068617320616c726561" +
+ "6479206265656e206465706c6f7965642e496e76616c69642073616c74202d206669727374" +
+ "203230206279746573206f66207468652073616c74206d757374206d617463682063616c6c" +
+ "696e6720616464726573732e4661696c656420746f206465706c6f7920636f6e7472616374" +
+ "207573696e672070726f76696465642073616c7420616e6420696e697469616c697a617469" +
+ "6f6e20636f64652ea265627a7a723058202bdc55310d97c4088f18acf04253db593f091405" +
+ "9f0c781a9df3624dcef0d1cf64736f6c634300050a0032",
+ IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH:
+ "0x767db8f19b71e367540fa372e8e81e4dcb7ca8feede0ae58a0c0bd08b7320dee",
+ ETH_WHALE_ADDRESS: "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe",
+ SAI_WHALE_ADDRESS: "0x76B03EB651153a81fA1f212f2f59329B4180A46F",
+ DAI_WHALE_ADDRESS: "0x8134d518e0CeF5388136c0De43d7E12278701Ac5",
+ USDC_WHALE_ADDRESS: "0x035e742A7E62253C606b9028eeB65178B44F1e7E",
+ SAI_MAINNET_ADDRESS: "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359",
+ DAI_MAINNET_ADDRESS: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
+ USDC_MAINNET_ADDRESS: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
+ CSAI_MAINNET_ADDRESS: "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC",
+ CDAI_MAINNET_ADDRESS: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
+ CUSDC_MAINNET_ADDRESS: "0x39AA39c021dfbaE8faC545936693aC917d5E7563",
+ CETH_MAINNET_ADDRESS: "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5",
+ DDAI_MAINNET_ADDRESS: "0x00000000001876eB1444c986fD502e618c587430",
+ DUSDC_MAINNET_ADDRESS: "0x00000000008943c65cAf789FFFCF953bE156f6f8",
+ DAI_MIGRATOR_MAINNET_ADDRESS: "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849",
+ MOCK_USDC_BLACKLISTED_ADDRESS: "0x6000000000000000000000000000000000000006",
+ COMPTROLLER_MAINNET_ADDRESS: "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B",
+ UPGRADE_BEACON_ENVOY_ADDRESS: "0x000000000067503c398F4c9652530DBC4eA95C02",
+ UPGRADE_BEACON_ENVOY_SALT:
+ "0x00000000000000000000000000000000000000003b4cf3f5b304150b79010000",
+ UPGRADE_BEACON_ENVOY_CREATION_CODE:
+ "0x608060405234801561001057600080fd5b5061020d806100206000396000f3fe608060" +
+ "405234801561001057600080fd5b506004361061002b5760003560e01c806315ac72ca14" +
+ "610030575b600080fd5b6100566004803603602081101561004657600080fd5b50356001" +
+ "600160a01b0316610072565b604080516001600160a01b03909216825251908190036020" +
+ "0190f35b60405160009081906060906001600160a01b0385169083818181855afa915050" +
+ "3d80600081146100be576040519150601f19603f3d011682016040523d82523d60006020" +
+ "84013e6100c3565b606091505b50915091508181906101535760405162461bcd60e51b81" +
+ "526004018080602001828103825283818151815260200191508051906020019080838360" +
+ "005b83811015610118578181015183820152602001610100565b50505050905090810190" +
+ "601f1680156101455780820380516001836020036101000a031916815260200191505b50" +
+ "9250505060405180910390fd5b5080516020146101945760405162461bcd60e51b815260" +
+ "04018080602001828103825260258152602001806101b460259139604001915050604051" +
+ "80910390fd5b8080602001905160208110156101a957600080fd5b505194935050505056" +
+ "fe52657475726e2064617461206d7573742062652065786163746c792033322062797465" +
+ "732ea265627a7a72315820107734a2fcd1d762a5f847530eab7552a2346f80ce0afa3765" +
+ "70475d354bab3264736f6c634300050b0032",
+ UPGRADE_BEACON_ENVOY_RUNTIME_CODE:
+ "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806315" +
+ "ac72ca14610030575b600080fd5b6100566004803603602081101561004657600080fd5b" +
+ "50356001600160a01b0316610072565b604080516001600160a01b039092168252519081" +
+ "900360200190f35b60405160009081906060906001600160a01b0385169083818181855a" +
+ "fa9150503d80600081146100be576040519150601f19603f3d011682016040523d82523d" +
+ "6000602084013e6100c3565b606091505b50915091508181906101535760405162461bcd" +
+ "60e51b815260040180806020018281038252838181518152602001915080519060200190" +
+ "80838360005b83811015610118578181015183820152602001610100565b505050509050" +
+ "90810190601f1680156101455780820380516001836020036101000a0319168152602001" +
+ "91505b509250505060405180910390fd5b5080516020146101945760405162461bcd60e5" +
+ "1b81526004018080602001828103825260258152602001806101b4602591396040019150" +
+ "5060405180910390fd5b8080602001905160208110156101a957600080fd5b5051949350" +
+ "50505056fe52657475726e2064617461206d7573742062652065786163746c7920333220" +
+ "62797465732ea265627a7a72315820107734a2fcd1d762a5f847530eab7552a2346f80ce" +
+ "0afa376570475d354bab3264736f6c634300050b0032",
+ UPGRADE_BEACON_CONTROLLER_ADDRESS:
+ "0x00000000002226C940b74d674B85E4bE05539663",
+ UPGRADE_BEACON_CONTROLLER_SALT:
+ "0x00000000000000000000000000000000000000002401b098eebfab0f53080000",
+ UPGRADE_BEACON_CONTROLLER_METADATA: [
+ "20446861726d6155706772616465426561636f6e436f6e74726f6c6c65722020"
+ ],
+ KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS:
+ "0x00000000011dF015e8aD00D7B2486a88C2Eb8210",
+ KEY_RING_UPGRADE_BEACON_CONTROLLER_SALT:
+ "0x00000000000000000000000000000000000000003080ac79bc49c20d5a000000",
+ KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA: [
+ "20446861726d614b657952696e67426561636f6e436f6e74726f6c6c65722020"
+ ],
+ DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_ADDRESS:
+ "0x00000000001E980d286bE7f5f978f4Cc33128202",
+ DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_SALT:
+ "0x00000000000000000000000000000000000000003fcbb8f03bf3de073e010000",
+ DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_METADATA: [
+ "446861726d6144616955706772616465426561636f6e436f6e74726f6c6c6572"
+ ],
+ DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_ADDRESS:
+ "0x0000000000796dC3aA12EB9FE3B6e8F4D92cc966",
+ DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_SALT:
+ "0x00000000000000000000000000000000000000000fc2eed291fd750bd0020000",
+ DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_METADATA: [
+ "446861726d615553444355706772616465426561636f6e436f6e74726f6c6c72"
+ ],
+ UPGRADE_BEACON_ADDRESS: "0x000000000026750c571ce882B17016557279ADaa",
+ UPGRADE_BEACON_SALT:
+ "0x000000000000000000000000000000000000000078c916fd79282f00051f0000",
+ UPGRADE_BEACON_METADATA: [
+ "202020202020446861726d6155706772616465426561636f6e20202020202020"
+ ],
+ KEY_RING_UPGRADE_BEACON_ADDRESS:
+ "0x0000000000BDA2152794ac8c76B2dc86cbA57cad",
+ KEY_RING_UPGRADE_BEACON_SALT:
+ "0x0000000000000000000000000000000000000000ca2bc7ce5bd506089c100000",
+ KEY_RING_UPGRADE_BEACON_METADATA: [
+ "202020446861726d614b657952696e6755706772616465426561636f6e202020"
+ ],
+ DHARMA_DAI_UPGRADE_BEACON_ADDRESS:
+ "0x0000000000ccCf289727C20269911159a7bf9eBd",
+ DHARMA_DAI_UPGRADE_BEACON_SALT:
+ "0x000000000000000000000000000000000000000030229e8953db57001f000000",
+ DHARMA_DAI_UPGRADE_BEACON_METADATA: [
+ "2020202020446861726d6144616955706772616465426561636f6e2020202020"
+ ],
+ DHARMA_USDC_UPGRADE_BEACON_ADDRESS:
+ "0x00000000000274bE4365Aa18CfDC9A22A947f67D",
+ DHARMA_USDC_UPGRADE_BEACON_SALT:
+ "0x00000000000000000000000000000000000000004961b57384658b027f080000",
+ DHARMA_USDC_UPGRADE_BEACON_METADATA: [
+ "20202020446861726d615553444355706772616465426561636f6e2020202020"
+ ],
+ DHARMA_DAI_ADDRESS: "0x00000000001876eB1444c986fD502e618c587430",
+ DHARMA_DAI_SALT:
+ "0x00000000000000000000000000000000000000004ed68ad580a29b000c0a0000",
+ DHARMA_DAI_METADATA: [
+ "20202020202020446861726d6120446169202864446169292020202020202020"
+ ],
+ DHARMA_DAI_IMPLEMENTATION_V1_ADDRESS:
+ "0x00000000580090B7b5B593AB408000b1AbB5f78d",
+ DHARMA_DAI_IMPLEMENTATION_V1_SALT:
+ "0x0000000000000000000000000000000000000000e576fa39d46b480fd5010000",
+ DHARMA_DAI_IMPLEMENTATION_V1_METADATA: [
+ "2020446861726d612044616920496d706c656d656e746174696f6e2056312020"
+ ],
+ DHARMA_USDC_IMPLEMENTATION_V1_ADDRESS:
+ "0x00000000de26576A3700bb87d61BFbEE335C8b56",
+ DHARMA_USDC_IMPLEMENTATION_V1_SALT:
+ "0x00000000000000000000000000000000000000002e6250385076920b57000000",
+ DHARMA_USDC_IMPLEMENTATION_V1_METADATA: [
+ "446861726d612055534420436f696e20496d706c656d656e746174696f6e2031"
+ ],
+ DHARMA_USDC_ADDRESS: "0x00000000008943c65cAf789FFFCF953bE156f6f8",
+ DHARMA_USDC_SALT:
+ "0x0000000000000000000000000000000000000000f1507216069e1c0f60090000",
+ DHARMA_USDC_METADATA: [
+ "20202020446861726d612055534420436f696e20286455534443292020202020"
+ ],
+ KEY_REGISTRY_ADDRESS: "0x000000005D7065eB9716a410070Ee62d51092C98",
+ KEY_REGISTRY_SALT:
+ "0x00000000000000000000000000000000000000003dafd25120eca50e14000000",
+ KEY_REGISTRY_METADATA: [
+ "202020202020446861726d614b65795265676973747279563120202020202020"
+ ],
+ KEY_REGISTRY_V2_ADDRESS: "0x000000000D38df53b45C5733c7b34000dE0BDF52",
+ KEY_REGISTRY_V2_SALT:
+ "0x0000000000000000000000000000000000000000035383a4848e750d83000000",
+ KEY_REGISTRY_V2_METADATA: [
+ "202020202020446861726d614b65795265676973747279563220202020202020"
+ ],
+ ACCOUNT_RECOVERY_MANAGER_ADDRESS:
+ "0x00000000004cDa75701EeA02D1F2F9BDcE54C10D",
+ ACCOUNT_RECOVERY_MANAGER_SALT:
+ "0x000000000000000000000000000000000000000000f9460080747d0837020000",
+ ACCOUNT_RECOVERY_MANAGER_METADATA: [
+ "2020446861726d614163636f756e745265636f766572794d616e616765722020"
+ ],
+ ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS:
+ "0x0000000000DfEd903aD76996FC07BF89C0127B1E",
+ ACCOUNT_RECOVERY_MANAGER_V2_SALT:
+ "0x000000000000000000000000000000000000000009adfe40acf37300b2020000",
+ ACCOUNT_RECOVERY_MANAGER_V2_METADATA: [
+ "20446861726d614163636f756e745265636f766572794d616e61676572563220"
+ ],
+ UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS:
+ "0x00000000008A10a98969A000D1C0AbA90F858D6a",
+ UPGRADE_BEACON_CONTROLLER_MANAGER_SALT:
+ "0x000000000000000000000000000000000000000002661332276954010e060000",
+ UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA: [
+ "2055706772616465426561636f6e436f6e74726f6c6c65724d616e6167657220"
+ ],
+ FACTORY_ADDRESS: "0xfc00C80b0000007F73004edB00094caD80626d8D",
+ FACTORY_SALT:
+ "0x0000000000000000000000000000000000000000e3c18f17dda93a0e08000000",
+ FACTORY_METADATA: [
+ "202020446861726d61536d61727457616c6c6574466163746f72793120202020",
+ "20202020202055706772616465426561636f6e50726f78795631202020202020"
+ ],
+ KEY_RING_FACTORY_ADDRESS: "0x00DD005247B300f700cFdfF89C00e2aCC94c7b00",
+ KEY_RING_FACTORY_SALT:
+ "0x00000000000000000000000000000000000000001429fc672990fb0320000000",
+ KEY_RING_FACTORY_METADATA: [
+ "2020202020446861726d614b657952696e67466163746f727956312020202020",
+ "20204b657952696e6755706772616465426561636f6e50726f78795631202020"
+ ],
+ REVERT_REASON_HELPER_METADATA: [
+ "cc6f0e10e5acac6b087faf256f191349c398a4fc1e1ca52f2372ad1ecffc2704"
+ ],
+ KEY_RING_FACTORY_V2_ADDRESS: "0x2484000059004afB720000dc738434fA6200F49D",
+ KEY_RING_FACTORY_V2_SALT:
+ "0x00000000000000000000000000000000000000008b0de996664c5e0c18000000",
+ KEY_RING_FACTORY_V2_METADATA: [
+ "2020202020446861726d614b657952696e67466163746f727956322020202020",
+ "20204b657952696e6755706772616465426561636f6e50726f78795631202020"
+ ],
+ KEY_REGISTRY_MIMIC_ADDRESS: "0x00000000D1dBC357A3f3D0f1F934D0186Ba40396",
+ KEY_REGISTRY_MIMIC_SALT:
+ "0x000000000000000000000000000000000000000033a95ffc488dbf0114000000",
+ KEY_REGISTRY_MIMIC_METADATA: [
+ "20202020446861726d614b6579526567697374727956314d696d696320202020"
+ ],
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V1_ADDRESS:
+ "0x0000000010A653849F221A573E00f3A37C8C4082",
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V1_SALT:
+ "0x0000000000000000000000000000000000000000dfdbded845e0d00ca0000000",
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V1_METADATA: [
+ "446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e31"
+ ],
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V3_METADATA: [
+ "446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e33"
+ ],
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V5_METADATA: [
+ "446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e35"
+ ],
+ DHARMA_SMART_WALLET_IMPLEMENTATION_V7_METADATA: [
+ "446861726d61536d61727457616c6c6574496d706c656d656e746174696f6e37"
+ ],
+ ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS:
+ "0x00000000009f22dA6fEB6735614563B9Af0339fB",
+ ADHARMA_SMART_WALLET_IMPLEMENTATION_SALT:
+ "0x00000000000000000000000000000000000000003d317829ae4acc0b21020000",
+ ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA: [
+ "41646861726d61536d61727457616c6c6574496d706c656d656e746174696f6e"
+ ],
+ ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS:
+ "0x000000000053d1F0F8aA88b9001Bec1B49445B3c",
+ ADHARMA_KEY_RING_IMPLEMENTATION_SALT:
+ "0x0000000000000000000000000000000000000000935331d823b26c05182f0000",
+ ADHARMA_KEY_RING_IMPLEMENTATION_METADATA: [
+ "202041646861726d614b657952696e67496d706c656d656e746174696f6e2020"
+ ],
+ ESCAPE_HATCH_REGISTRY_ADDRESS: "0x00000000005280B515004B998a944630B6C663f8",
+ ESCAPE_HATCH_REGISTRY_SALT:
+ "0x000000000000000000000000000000000000000082eb6220dd97c70002000000",
+ ESCAPE_HATCH_REGISTRY_METADATA: [
+ "202020446861726d614573636170654861746368526567697374727920202020"
+ ],
+ INDESTRUCTIBLE_REGISTRY_ADDRESS:
+ "0x0000000000f55ff05D0080fE17A63b16596Fd59f",
+ INDESTRUCTIBLE_REGISTRY_RUNTIME_HASH:
+ "0xadca137a47625f8ad1da20be107380101474374dc6c31ad0b8c1807558ea3c29",
+ REVERT_REASON_HELPER_ADDRESS: "0xE24257338d0c15f3Dd00Ed59fcA9e50CfB167bA8",
+ INDESTRUCTIBLE_REGISTRY_CREATION_TX:
+ "0x64e030870000000000000000000000000000000000000000a4ab82b860e6cb06780400" +
+ "000000000000000000000000000000000000000000000000000000000000000040000000" +
+ "000000000000000000000000000000000000000000000000000000046b60806040523480" +
+ "1561001057600080fd5b5061044b806100206000396000f3fe6080604052348015610010" +
+ "57600080fd5b50600436106100415760003560e01c80632c82288c146100465780633215" +
+ "14321461008d5780636cf9ed9b146100c2575b600080fd5b610079600480360360208110" +
+ "1561005c57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166100" +
+ "f5565b604080519115158252519081900360200190f35b6100c060048036036020811015" +
+ "6100a357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610120" +
+ "565b005b610079600480360360208110156100d857600080fd5b503573ffffffffffffff" +
+ "ffffffffffffffffffffffffff166101ce565b73ffffffffffffffffffffffffffffffff" +
+ "ffffffff1660009081526020819052604090205460ff1690565b610129816101df565b15" +
+ "61017f576040517f08c379a0000000000000000000000000000000000000000000000000" +
+ "00000000815260040180806020018281038252602c8152602001806103eb602c91396040" +
+ "0191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff1660" +
+ "0090815260208190526040902080547fffffffffffffffffffffffffffffffffffffffff" +
+ "ffffffffffffffffffffff00166001179055565b60006101d9826101df565b9291505056" +
+ "5b6000813b8061024f57604080517f08c379a00000000000000000000000000000000000" +
+ "0000000000000000000000815260206004820152601260248201527f4e6f20636f646520" +
+ "6174207461726765742e0000000000000000000000000000604482015290519081900360" +
+ "640190fd5b60006060826040519080825280601f01601f19166020018201604052801561" +
+ "027e576020820181803883390190505b50905060208101915082600083873c8183018281" +
+ "116102fe57604080517f08c379a000000000000000000000000000000000000000000000" +
+ "000000000000815260206004820152601c60248201527f536166654d6174683a20616464" +
+ "6974696f6e206f766572666c6f772e00000000604482015290519081900360640190fd5b" +
+ "60016000845b838110156103dd57805160f81c915082156103c7578160fe148061032857" +
+ "508160f3145b8061033357508160fd145b8061033e5750816056145b8061034757508115" +
+ "5b1561035557600092506103d5565b605f821180156103655750608082105b1561039357" +
+ "81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa101" +
+ "6103d5565b8160f214806103a257508160f4145b806103ad57508160ff145b156103c257" +
+ "60019750505050505050506103e5565b6103d5565b81605b14156103d557600192505b60" +
+ "0101610304565b505050505050505b91905056fe537570706c6965642074617267657420" +
+ "697320706f74656e7469616c6c7920646573747275637469626c652ea265627a7a723158" +
+ "20ba911a72b86ff753e41edde9621dd5f1c6169f5332418733e233da6d6678696564736f" +
+ "6c634300050b0032000000000000000000000000000000000000000000",
+ CONTRACT_NAMES: {
+ "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359": "SAI",
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F": "DAI",
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": "USDC",
+ "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC": "CSAI",
+ "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643": "CDAI",
+ "0x39AA39c021dfbaE8faC545936693aC917d5E7563": "CUSDC",
+ "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5": "CETH",
+ "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B": "Comptroller",
+ "0x00000000001876eB1444c986fD502e618c587430": "DDAI",
+ "0x0000000000946A7848C50C8f0AE1BB2792602Cb7": "DUSDC"
},
- // SmartWalletDeployed(address,address) -> wallet, userSigningKey
- '0x6e60d84846384a1994833ed675b0a0f76bef64943304debf6e42a9706d1a7dd7': {
- name: 'SmartWalletDeployed',
- abi: [
+ COMPTROLLER_ABI: [
{
- type: 'address',
- name: 'wallet'
- }, {
- type: 'address',
- name: 'userSigningKey'
- }
- ]
- },
- // Approval(address,address,uint256) -> owner, spender, value
- '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925': {
- name: 'Approval',
- abi: [
+ constant: true,
+ inputs: [
+ {
+ internalType: "address",
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "getAccountLiquidity",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "err",
+ type: "uint256"
+ },
+ {
+ internalType: "uint256",
+ name: "liquidity",
+ type: "uint256"
+ },
+ {
+ internalType: "uint256",
+ name: "shortfall",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
{
- type: 'address',
- name: 'owner',
- indexed: true
- }, {
- type: 'address',
- name: 'spender',
- indexed: true
- }, {
- type: 'uint256',
- name: 'value'
+ constant: false,
+ inputs: [
+ {
+ internalType: "address[]",
+ name: "cTokens",
+ type: "address[]"
+ }
+ ],
+ name: "enterMarkets",
+ outputs: [
+ {
+ internalType: "uint256[]",
+ name: "errs",
+ type: "uint256[]"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
}
- ]
- },
- // Transfer(address,address,uint256) -> to, from, value
- '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef': {
- name: 'Transfer',
- abi: [
- {
- type: 'address',
- name: 'from',
- indexed: true
- }, {
- type: 'address',
- name: 'to',
- indexed: true
- }, {
- type: 'uint256',
- name: 'value'
+ ],
+ EVENT_DETAILS: {
+ // keccak256 of NewUserSigningKey(address) -> userSigningKey
+ "0x7083aac3cab97f1219cedd0ab328a5b138a10b0fc72dd9348f1dc50199b21fda": {
+ name: "NewUserSigningKey",
+ abi: [
+ {
+ type: "address",
+ name: "userSigningKey"
+ }
+ ]
+ },
+ // ExternalError(address,string) -> source, reason
+ "0x5bbd5ab79029b89a22c80c7b7bfdc2f0c8e3f0d2a7330c7148cabc044250674b": {
+ name: "ExternalError",
+ abi: [
+ {
+ type: "address",
+ name: "source",
+ indexed: true
+ },
+ {
+ type: "string",
+ name: "reason"
+ }
+ ]
+ },
+ // SmartWalletDeployed(address,address) -> wallet, userSigningKey
+ "0x6e60d84846384a1994833ed675b0a0f76bef64943304debf6e42a9706d1a7dd7": {
+ name: "SmartWalletDeployed",
+ abi: [
+ {
+ type: "address",
+ name: "wallet"
+ },
+ {
+ type: "address",
+ name: "userSigningKey"
+ }
+ ]
+ },
+ // Approval(address,address,uint256) -> owner, spender, value
+ "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
+ name: "Approval",
+ abi: [
+ {
+ type: "address",
+ name: "owner",
+ indexed: true
+ },
+ {
+ type: "address",
+ name: "spender",
+ indexed: true
+ },
+ {
+ type: "uint256",
+ name: "value"
+ }
+ ]
+ },
+ // Transfer(address,address,uint256) -> to, from, value
+ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
+ name: "Transfer",
+ abi: [
+ {
+ type: "address",
+ name: "from",
+ indexed: true
+ },
+ {
+ type: "address",
+ name: "to",
+ indexed: true
+ },
+ {
+ type: "uint256",
+ name: "value"
+ }
+ ]
+ },
+ // Mint(address,uint256,uint256) -> minter, mintTokens, mintAmount
+ "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f": {
+ name: "Mint",
+ abi: [
+ {
+ type: "address",
+ name: "minter"
+ },
+ {
+ type: "uint256",
+ name: "mintTokens"
+ },
+ {
+ type: "uint256",
+ name: "mintAmount"
+ }
+ ]
+ },
+ // Redeem(address,uint256,uint256) -> redeemer, redeemTokens, redeemAmount
+ "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929": {
+ name: "Redeem",
+ abi: [
+ {
+ type: "address",
+ name: "redeemer"
+ },
+ {
+ type: "uint256",
+ name: "redeemTokens"
+ },
+ {
+ type: "uint256",
+ name: "redeemAmount"
+ }
+ ]
+ },
+ // MarketEntered(address,address) -> cToken, account
+ "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5": {
+ name: "MarketEntered",
+ abi: [
+ {
+ type: "address",
+ name: "cToken"
+ },
+ {
+ type: "address",
+ name: "account"
+ }
+ ]
+ },
+ // AccrueInterest(uint256,uint256,uint256) ->
+ // interestAccumulated, borrowIndex, totalBorrows
+ "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9": {
+ name: "AccrueInterest",
+ abi: [
+ {
+ type: "uint256",
+ name: "interestAccumulated"
+ },
+ {
+ type: "uint256",
+ name: "borrowIndex"
+ },
+ {
+ type: "uint256",
+ name: "totalBorrows"
+ }
+ ]
+ },
+ "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0": {
+ name: "Failure",
+ abi: [
+ {
+ type: "uint256",
+ name: "error"
+ },
+ {
+ type: "uint256",
+ name: "info"
+ },
+ {
+ type: "uint256",
+ name: "detail"
+ }
+ ]
}
- ]
},
- // Mint(address,uint256,uint256) -> minter, mintTokens, mintAmount
- '0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f': {
- name: 'Mint',
- abi: [
- {
- type: 'address',
- name: 'minter'
- }, {
- type: 'uint256',
- name: 'mintTokens'
- }, {
- type: 'uint256',
- name: 'mintAmount'
- }
- ]
- },
- // Redeem(address,uint256,uint256) -> redeemer, redeemTokens, redeemAmount
- '0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929': {
- name: 'Redeem',
- abi: [
- {
- type: 'address',
- name: 'redeemer'
- }, {
- type: 'uint256',
- name: 'redeemTokens'
- }, {
- type: 'uint256',
- name: 'redeemAmount'
- }
- ]
- },
- // MarketEntered(address,address) -> cToken, account
- '0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5': {
- name: 'MarketEntered',
- abi: [
- {
- type: 'address',
- name: 'cToken'
- }, {
- type: 'address',
- name: 'account'
- }
- ]
- },
- // AccrueInterest(uint256,uint256,uint256) ->
- // interestAccumulated, borrowIndex, totalBorrows
- '0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9': {
- name: 'AccrueInterest',
- abi: [
- {
- type: 'uint256',
- name: 'interestAccumulated'
- }, {
- type: 'uint256',
- name: 'borrowIndex'
- }, {
- type: 'uint256',
- name: 'totalBorrows'
- }
- ]
- },
- '0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0': {
- name: 'Failure',
- abi: [
- {
- type: 'uint256',
- name: 'error'
- }, {
- type: 'uint256',
- name: 'info'
- }, {
- type: 'uint256',
- name: 'detail'
- }
- ]
- }
- },
- METADATA_IDENTIFIER: '627a7a72315820',
- MOCK_OWNER_PRIVATE_KEYS: [
- '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
- '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
- '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
- '0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',
- '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'
- ]
-})
+ METADATA_IDENTIFIER: "627a7a72315820",
+ MOCK_OWNER_PRIVATE_KEYS: [
+ "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+ "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ ]
+});
diff --git a/scripts/test/contracts/account-recovery/testAccountRecoveryManager.js b/scripts/test/contracts/account-recovery/testAccountRecoveryManager.js
new file mode 100644
index 0000000..b46ec7f
--- /dev/null
+++ b/scripts/test/contracts/account-recovery/testAccountRecoveryManager.js
@@ -0,0 +1,873 @@
+const constants = require("../../constants");
+const assert = require("assert");
+
+async function testAccountRecoveryManager(
+ tester,
+ contract,
+ smartWalletAddress
+) {
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot transfer ownership from a non-owner`,
+ contract,
+ "transferOwnership",
+ "send",
+ [tester.addressTwo],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot initiate recovery with null smart wallet`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [constants.NULL_ADDRESS, tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot initiate recovery with null new key`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can initiate recovery timelock`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [constants.UPGRADE_BEACON_ADDRESS, tester.addressTwo, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can initiate another recovery timelock`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [smartWalletAddress, tester.addressTwo, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can initiate a third recovery timelock`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [tester.address, tester.addressTwo, 0]
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery cannot be cancelled with no smart wallet",
+ contract,
+ "cancelAccountRecovery",
+ "send",
+ [constants.NULL_ADDRESS, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery cannot be cancelled with no user signing key",
+ contract,
+ "cancelAccountRecovery",
+ "send",
+ [tester.address, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery can be cancelled",
+ contract,
+ "cancelAccountRecovery",
+ "send",
+ [tester.address, tester.addressTwo],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery cannot be cancelled if it is already cancelled",
+ contract,
+ "cancelAccountRecovery",
+ "send",
+ [tester.address, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery cannot be cancelled if no timelock exists",
+ contract,
+ "cancelAccountRecovery",
+ "send",
+ [tester.addressTwo, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery can be reinitiated",
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [
+ tester.address,
+ tester.addressTwo,
+ 1 // extraTime in seconds - add one to ensure that timelock is extended
+ ],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot initiate recovery disablement with null smart wallet`,
+ contract,
+ "initiateAccountRecoveryDisablement",
+ "send",
+ [constants.NULL_ADDRESS, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can initiate recovery disablement timelock`,
+ contract,
+ "initiateAccountRecoveryDisablement",
+ "send",
+ [tester.address, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call recover with null new key`,
+ contract,
+ "recover",
+ "send",
+ [constants.NULL_ADDRESS, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call recover with null new key`,
+ contract,
+ "recover",
+ "send",
+ [tester.address, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call recover prior to timelock completion`,
+ contract,
+ "recover",
+ "send",
+ [constants.UPGRADE_BEACON_ADDRESS, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery prior to timelock completion`,
+ contract,
+ "disableAccountRecovery",
+ "send",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if account recovery is disabled`,
+ contract,
+ "accountRecoveryDisabled",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ // advance time by 3 days
+ await tester.advanceTime(60 * 60 * 24 * 3 + 5);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call recover after timelock completion`,
+ contract,
+ "recover",
+ "send",
+ [constants.UPGRADE_BEACON_ADDRESS, tester.addressTwo]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot recover an unowned smart wallet`,
+ contract,
+ "recover",
+ "send",
+ [smartWalletAddress, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot recover an EOA`,
+ contract,
+ "recover",
+ "send",
+ [tester.address, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery with null smart wallet`,
+ contract,
+ "disableAccountRecovery",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call disableAccountRecovery after timelock completion`,
+ contract,
+ "disableAccountRecovery",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if account recovery is disabled`,
+ contract,
+ "accountRecoveryDisabled",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot recover an account that has disabled recovery`,
+ contract,
+ "recover",
+ "send",
+ [tester.address, tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval with no selector`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xaaaaaaaa", 10000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval with no selector`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval before timelock completion`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0xe950c085", 1000],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration with no selector`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to with expiration over one month`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 30, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one hour`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 3000, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 30000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xaaaaaaaa", 300000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration with no selector`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration before timelock completion`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can initiate recovery disablement timelock`,
+ contract,
+ "initiateAccountRecoveryDisablement",
+ "send",
+ [tester.addressTwo, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot cancel disablement with null address`,
+ contract,
+ "cancelAccountRecoveryDisablement",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can cancel recovery disablement timelock`,
+ contract,
+ "cancelAccountRecoveryDisablement",
+ "send",
+ [tester.addressTwo]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can re-initiate recovery disablement timelock`,
+ contract,
+ "initiateAccountRecoveryDisablement",
+ "send",
+ [tester.addressTwo, 1]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot shorten a timelock`,
+ contract,
+ "initiateAccountRecoveryDisablement",
+ "send",
+ [tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot initiate recovery with massive extraTime`,
+ contract,
+ "initiateAccountRecovery",
+ "send",
+ [tester.address, tester.addressTwo, constants.FULL_APPROVAL],
+ false
+ );
+
+ // advance time by 2 weeks
+ await tester.advanceTime(60 * 60 * 24 * 7 * 2 + 5);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery after timelock expiration`,
+ contract,
+ "disableAccountRecovery",
+ "send",
+ [tester.addressTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot set a role to the null tester.address`,
+ contract,
+ "setRole",
+ "send",
+ [0, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can set a role`,
+ contract,
+ "setRole",
+ "send",
+ [0, tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can set a role that is already set`,
+ contract,
+ "setRole",
+ "send",
+ [0, tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if the caller has a role`,
+ contract,
+ "isRole",
+ "call",
+ [0],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check for an operator role`,
+ contract,
+ "getOperator",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check for a recoverer role`,
+ contract,
+ "getRecoverer",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, constants.NULL_ADDRESS);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check for a canceller role`,
+ contract,
+ "getCanceller",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, constants.NULL_ADDRESS);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check for a disabler role`,
+ contract,
+ "getDisabler",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, constants.NULL_ADDRESS);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check for a pauser role`,
+ contract,
+ "getPauser",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, constants.NULL_ADDRESS);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can remove a role`,
+ contract,
+ "removeRole",
+ "send",
+ [0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if the caller has a role`,
+ contract,
+ "isRole",
+ "call",
+ [0],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if a role is paused`,
+ contract,
+ "isPaused",
+ "call",
+ [0],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot pause a role if not owner or pauser`,
+ contract,
+ "pause",
+ "send",
+ [0],
+ false,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can set a role`,
+ contract,
+ "setRole",
+ "send",
+ [4, tester.addressTwo]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot unpause an unpaused role`,
+ contract,
+ "unpause",
+ "send",
+ [0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can pause an unpaused role`,
+ contract,
+ "pause",
+ "send",
+ [0],
+ true,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot pause a paused role`,
+ contract,
+ "pause",
+ "send",
+ [0],
+ false,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can pause the pauser role`,
+ contract,
+ "pause",
+ "send",
+ [4]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 pauser cannot call a paused role`,
+ contract,
+ "pause",
+ "send",
+ [4],
+ false,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can check if a role is paused`,
+ contract,
+ "isPaused",
+ "call",
+ [0],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can unpause a paused role`,
+ contract,
+ "unpause",
+ "send",
+ [0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can get an empty timelock`,
+ contract,
+ "getTimelock",
+ "call",
+ ["0x01020304", "0x"],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.ok(!value.completed);
+ assert.ok(!value.expired);
+ assert.strictEqual(value.completionTime, "0");
+ assert.strictEqual(value.expirationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can get an empty default timelock interval`,
+ contract,
+ "getDefaultTimelockInterval",
+ "call",
+ ["0x01020304"],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can get an empty default timelock expiration`,
+ contract,
+ "getDefaultTimelockExpiration",
+ "call",
+ ["0x01020304"],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval with no selector`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot create timelock with excessive duration`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", constants.FULL_APPROVAL, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10000, 5]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot shorten existing initiateModifyTimelockInterval timelock`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10000, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to change a duration`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10001, 5]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xaaaaaaaa", 10000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval with no selector`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval before timelock completion`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0xe950c085", 1000],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration with no selector`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to with expiration over one month`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 30, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 30, 0]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration with no selector`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration before timelock completion`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300],
+ false
+ );
+
+ // advance time by 2 weeks
+ await tester.advanceTime(60 * 60 * 24 * 7 * 2 + 5);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call modifyTimelockInterval`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0xaaaaaaaa", 10000]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 can call modifyTimelockExpiration`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300000]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration if expiration is too short`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 30],
+ false
+ );
+}
+
+module.exports = {
+ testAccountRecoveryManager
+};
diff --git a/scripts/test/contracts/indestructible-registry/testIndestructibleRegistry.js b/scripts/test/contracts/indestructible-registry/testIndestructibleRegistry.js
new file mode 100644
index 0000000..32a2090
--- /dev/null
+++ b/scripts/test/contracts/indestructible-registry/testIndestructibleRegistry.js
@@ -0,0 +1,241 @@
+const constants = require("../../constants");
+const { newContractAndSwapMetadataHash } = require("../../testHelpers");
+
+const IndestructibleRegistryArtifact = require("../../../../build/contracts/IndestructibleRegistry.json");
+
+async function testIndestructibleRegistry(tester, contracts) {
+ const {
+ DharmaSmartWalletImplementationV6,
+ DharmaSmartWalletImplementationV7,
+ DharmaKeyRingImplementationV1
+ } = contracts;
+
+ const IndestructibleRegistryDeployer = newContractAndSwapMetadataHash(
+ IndestructibleRegistryArtifact
+ );
+
+ const IndestructibleRegistry = await tester.runTest(
+ `IndestructibleRegistry contract deployment`,
+ IndestructibleRegistryDeployer,
+ "",
+ "deploy"
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register itself as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [IndestructibleRegistry.options.address]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the upgrade beacon as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the upgrade beacon controller as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the key ring upgrade beacon as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.KEY_RING_UPGRADE_BEACON_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the key ring upgrade beacon controller as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the upgrade beacon envoy as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_ENVOY_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the account recovery manager V2 as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS]
+ );
+
+ /*
+ await tester.runTest(
+ 'IndestructibleRegistry can register DharmaKeyRegistryV1 as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [constants.KEY_REGISTRY_ADDRESS]
+ )
+ */
+
+ await tester.runTest(
+ "IndestructibleRegistry can register DharmaKeyRegistryV2 as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.KEY_REGISTRY_V2_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register DharmaEscapeHatchRegistry as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ESCAPE_HATCH_REGISTRY_ADDRESS]
+ );
+
+ await tester.runTest(
+ "WARNING: IndestructibleRegistry CANNOT register the smart wallet factory as indestructible (even though it is in fact NOT destructible)",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.FACTORY_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the Adharma smart wallet implementation as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the Adharma key ring implementation as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS]
+ );
+
+ /*
+ await tester.runTest(
+ 'IndestructibleRegistry can register V0 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV0.options.address]
+ )
+
+ await runTest(
+ 'IndestructibleRegistry can register V0 key ring implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaKeyRingImplementationV0.options.address]
+ )
+ */
+
+ /*
+ await tester.runTest(
+ 'IndestructibleRegistry can register V1 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV1.options.address]
+ )
+ */
+
+ if (tester.context !== "coverage") {
+ /*
+ await tester.runTest(
+ 'IndestructibleRegistry can register V2 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV2.options.address]
+ )
+
+ await runTest(
+ 'IndestructibleRegistry can register V3 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV3.options.address]
+ )
+
+ await runTest(
+ 'IndestructibleRegistry can register V4 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV4.options.address]
+ )
+
+
+ await tester.runTest(
+ 'IndestructibleRegistry can register V5 implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaSmartWalletImplementationV5.options.address]
+ )
+ */
+
+ await tester.runTest(
+ "IndestructibleRegistry can register V6 implementation as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [DharmaSmartWalletImplementationV6.options.address]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register V7 implementation as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [DharmaSmartWalletImplementationV7.options.address]
+ );
+
+ await tester.runTest(
+ "IndestructibleRegistry can register V1 key ring implementation as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [DharmaKeyRingImplementationV1.options.address]
+ );
+ }
+
+ /*
+ await runTest(
+ 'IndestructibleRegistry can register V2 key ring implementation as indestructible',
+ IndestructibleRegistry,
+ 'registerAsIndestructible',
+ 'send',
+ [DharmaKeyRingImplementationV2.options.address]
+ )
+ */
+
+ await tester.runTest(
+ "IndestructibleRegistry can register the upgrade beacon controller manager as indestructible",
+ IndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS]
+ );
+}
+
+module.exports = {
+ testIndestructibleRegistry
+};
diff --git a/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryMultisigDeployer.js b/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryMultisigDeployer.js
new file mode 100644
index 0000000..9f18448
--- /dev/null
+++ b/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryMultisigDeployer.js
@@ -0,0 +1,69 @@
+async function testDharmaAccountRecoveryMultisigDeployer(tester, contract) {
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig contract deployment fails if threshold is not met`,
+ contract,
+ "",
+ "deploy",
+ [["0x0000000000000000000000000000000000000001"]],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig contract deployment fails if sigs are out of order`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000001"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig contract deployment fails with too many owners`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000001",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000006",
+ "0x0000000000000000000000000000000000000007",
+ "0x0000000000000000000000000000000000000008",
+ "0x0000000000000000000000000000000000000009",
+ "0x000000000000000000000000000000000000000a",
+ "0x000000000000000000000000000000000000000b"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig contract deployment`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour
+ ]
+ ]
+ );
+}
+
+module.exports = {
+ testDharmaAccountRecoveryMultisigDeployer
+};
diff --git a/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryOperatorMultisigDeployer.js b/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryOperatorMultisigDeployer.js
new file mode 100644
index 0000000..9331d3d
--- /dev/null
+++ b/scripts/test/contracts/multisig-deployers/testDharmaAccountRecoveryOperatorMultisigDeployer.js
@@ -0,0 +1,57 @@
+async function testDharmaAccountRecoveryOperatorMultisigDeployer(
+ tester,
+ contract
+) {
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig contract deployment fails if threshold is not met`,
+ contract,
+ "",
+ "deploy",
+ [["0x0000000000000000000000000000000000000001"]],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig contract deployment fails if sigs are out of order`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000001"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig contract deployment fails with too many owners`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000001",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000006",
+ "0x0000000000000000000000000000000000000007",
+ "0x0000000000000000000000000000000000000008",
+ "0x0000000000000000000000000000000000000009",
+ "0x000000000000000000000000000000000000000a",
+ "0x000000000000000000000000000000000000000b"
+ ]
+ ],
+ false
+ );
+}
+
+module.exports = {
+ testDharmaAccountRecoveryOperatorMultisigDeployer
+};
diff --git a/scripts/test/contracts/multisig-deployers/testDharmaKeyRegistryMultisigDeployer.js b/scripts/test/contracts/multisig-deployers/testDharmaKeyRegistryMultisigDeployer.js
new file mode 100644
index 0000000..aec9273
--- /dev/null
+++ b/scripts/test/contracts/multisig-deployers/testDharmaKeyRegistryMultisigDeployer.js
@@ -0,0 +1,70 @@
+async function testDharmaKeyRegistryMultisigDeployer(tester, contract) {
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig contract deployment fails if threshold is not met`,
+ contract,
+ "",
+ "deploy",
+ [["0x0000000000000000000000000000000000000001"]],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig contract deployment fails if sigs are out of order`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000001"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig contract deployment fails with too many owners`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000001",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000006",
+ "0x0000000000000000000000000000000000000007",
+ "0x0000000000000000000000000000000000000008",
+ "0x0000000000000000000000000000000000000009",
+ "0x000000000000000000000000000000000000000a",
+ "0x000000000000000000000000000000000000000b"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig contract deployment`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]
+ ]
+ );
+}
+
+module.exports = {
+ testDharmaKeyRegistryMultisigDeployer
+};
diff --git a/scripts/test/contracts/multisig-deployers/testDharmaUpgradeMultisigDeployer.js b/scripts/test/contracts/multisig-deployers/testDharmaUpgradeMultisigDeployer.js
new file mode 100644
index 0000000..7ddd18a
--- /dev/null
+++ b/scripts/test/contracts/multisig-deployers/testDharmaUpgradeMultisigDeployer.js
@@ -0,0 +1,70 @@
+async function testDharmaUpgradeMultisigDeployer(tester, contract) {
+ await tester.runTest(
+ `DharmaUpgradeMultisig contract deployment fails if threshold is not met`,
+ contract,
+ "",
+ "deploy",
+ [["0x0000000000000000000000000000000000000001"]],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig contract deployment fails if sigs are out of order`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000001"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig contract deployment fails with too many owners`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ "0x0000000000000000000000000000000000000001",
+ "0x0000000000000000000000000000000000000002",
+ "0x0000000000000000000000000000000000000003",
+ "0x0000000000000000000000000000000000000004",
+ "0x0000000000000000000000000000000000000005",
+ "0x0000000000000000000000000000000000000006",
+ "0x0000000000000000000000000000000000000007",
+ "0x0000000000000000000000000000000000000008",
+ "0x0000000000000000000000000000000000000009",
+ "0x000000000000000000000000000000000000000a",
+ "0x000000000000000000000000000000000000000b"
+ ]
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig contract deployment`,
+ contract,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]
+ ]
+ );
+}
+
+module.exports = {
+ testDharmaUpgradeMultisigDeployer
+};
diff --git a/scripts/test/contracts/registries/testKeyRegistryV2.js b/scripts/test/contracts/registries/testKeyRegistryV2.js
new file mode 100644
index 0000000..a7d9e53
--- /dev/null
+++ b/scripts/test/contracts/registries/testKeyRegistryV2.js
@@ -0,0 +1,299 @@
+const { web3 } = require("../../web3");
+const constants = require("../../constants");
+const assert = require("assert");
+
+async function testKeyRegistryV2(tester, contract, unownedKeyRegistryAddress) {
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the initial global key correctly",
+ contract,
+ "getGlobalKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 attempt to get an unset specific key throws",
+ contract,
+ "getSpecificKey",
+ "call",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the global key when requesting unset key",
+ contract,
+ "getKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a new empty global key",
+ contract,
+ "setGlobalKey",
+ "send",
+ [constants.NULL_ADDRESS, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ const message =
+ contract.options.address +
+ tester.addressTwo.slice(2) +
+ web3.utils
+ .asciiToHex(
+ "This signature demonstrates that the supplied signing key is valid."
+ )
+ .slice(2);
+
+ const newKeySignature = tester.signHashedPrefixedHashedHexString(
+ message,
+ tester.addressTwo
+ );
+
+ const badNewKeySignature = tester.signHashedPrefixedHashedHexString(
+ "0x12",
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a new global key unless called by owner",
+ contract,
+ "setGlobalKey",
+ "send",
+ [tester.addressTwo, newKeySignature],
+ false,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set an empty global key",
+ contract,
+ "setGlobalKey",
+ "send",
+ [constants.NULL_ADDRESS, newKeySignature],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a new global key with a bad signature",
+ contract,
+ "setGlobalKey",
+ "send",
+ [tester.addressTwo, badNewKeySignature],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 can set a new global key correctly",
+ contract,
+ "setGlobalKey",
+ "send",
+ [tester.addressTwo, newKeySignature]
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the new global key correctly",
+ contract,
+ "getGlobalKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a new specific key unless called by owner",
+ contract,
+ "setSpecificKey",
+ "send",
+ [tester.address, unownedKeyRegistryAddress],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets global key for a user if no specific key set",
+ contract,
+ "getKeyForUser",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 can set a new specific key",
+ contract,
+ "setSpecificKey",
+ "send",
+ [tester.address, unownedKeyRegistryAddress]
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets specific key for user if one is set",
+ contract,
+ "getKeyForUser",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.strictEqual(value, unownedKeyRegistryAddress);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the new specific key correctly",
+ contract,
+ "getSpecificKey",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.strictEqual(value, unownedKeyRegistryAddress);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the specific key when requesting set key",
+ contract,
+ "getKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, unownedKeyRegistryAddress);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot reuse a specific key",
+ contract,
+ "setSpecificKey",
+ "send",
+ [tester.address, unownedKeyRegistryAddress],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 new owner cannot accept ownership before added",
+ contract,
+ "acceptOwnership",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot prepare to transfer to the null address",
+ contract,
+ "transferOwnership",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 can prepare to transfer to a new owner",
+ contract,
+ "transferOwnership",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 can cancel an ownership transfer",
+ contract,
+ "cancelOwnershipTransfer"
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 new owner cannot accept ownership after cancellation",
+ contract,
+ "acceptOwnership",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 can prepare to transfer to a new owner again",
+ contract,
+ "transferOwnership",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 new owner can accept ownership",
+ contract,
+ "acceptOwnership"
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the new owner",
+ contract,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the global key correctly",
+ contract,
+ "getGlobalKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
+
+ const messageV2 =
+ contract.options.address +
+ tester.address.slice(2) +
+ web3.utils
+ .asciiToHex(
+ "This signature demonstrates that the supplied signing key is valid."
+ )
+ .slice(2);
+
+ const v2KeySignature = tester.signHashedPrefixedHashedHexString(
+ messageV2,
+ tester.address
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a previously used global key",
+ contract,
+ "setGlobalKey",
+ "send",
+ [tester.address, v2KeySignature],
+ false
+ );
+}
+
+module.exports = {
+ testKeyRegistryV2
+};
diff --git a/scripts/test/contracts/upgradeability/testPerformingUpgrade.js b/scripts/test/contracts/upgradeability/testPerformingUpgrade.js
new file mode 100644
index 0000000..f85631f
--- /dev/null
+++ b/scripts/test/contracts/upgradeability/testPerformingUpgrade.js
@@ -0,0 +1,179 @@
+const constants = require("../../constants");
+const assert = require("assert");
+
+async function testPerformingUpgrade(
+ tester,
+ contract, // new implementation
+ userSmartWalletContract,
+ upgradeBeaconControllerContract,
+ upgradeBeaconAddress,
+ newImplementationVersion,
+ initial = false
+) {
+ let nonce;
+ let userSigningKey;
+ let oldImplementation;
+ let oldImplementationCodeHash;
+ let newImplementationCodeHash;
+
+ if (!initial) {
+ await tester.runTest(
+ "User Smart Wallet can check the user signing key prior to upgrade",
+ userSmartWalletContract,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ userSigningKey = value;
+ }
+ );
+
+ await tester.runTest(
+ "User Smart Wallet can get the nonce prior to upgrade",
+ userSmartWalletContract,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ nonce = value;
+ }
+ );
+ }
+
+ await tester.runTest(
+ "DharmaUpgradeBeacon current implementation can be retrieved",
+ upgradeBeaconControllerContract,
+ "getImplementation",
+ "call",
+ [upgradeBeaconAddress],
+ true,
+ value => {
+ oldImplementation = value;
+ }
+ );
+
+ await tester.runTest(
+ "Old implementation code hash can be retrieved",
+ tester.MockCodeCheck,
+ "hash",
+ "call",
+ [oldImplementation],
+ true,
+ value => {
+ oldImplementationCodeHash = value;
+ }
+ );
+
+ await tester.runTest(
+ "New implementation code hash can be retrieved",
+ tester.MockCodeCheck,
+ "hash",
+ "call",
+ [contract.options.address],
+ true,
+ value => {
+ newImplementationCodeHash = value;
+ }
+ );
+
+ await tester.runTest(
+ `Dharma Upgrade Beacon Controller can upgrade to V${newImplementationVersion.toString()} implementation`,
+ upgradeBeaconControllerContract,
+ "upgrade",
+ "send",
+ [upgradeBeaconAddress, contract.options.address],
+ true,
+ receipt => {
+ if (tester.context !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.upgradeBeacon,
+ upgradeBeaconAddress
+ );
+
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.oldImplementation,
+ oldImplementation
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues
+ .oldImplementationCodeHash,
+ oldImplementationCodeHash
+ );
+
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.newImplementation,
+ contract.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues
+ .newImplementationCodeHash,
+ newImplementationCodeHash
+ );
+ }
+ }
+ );
+
+ await tester.runTest(
+ "DharmaUpgradeBeacon has the new implementation set",
+ upgradeBeaconControllerContract,
+ "getImplementation",
+ "call",
+ [upgradeBeaconAddress],
+ true,
+ value => {
+ assert.strictEqual(value, contract.options.address);
+ }
+ );
+
+ await tester.runTest(
+ `UpgradeBeaconImplementationCheck deployment`,
+ tester.UpgradeBeaconImplementationCheckDeployer,
+ "",
+ "deploy",
+ [upgradeBeaconAddress, contract.options.address]
+ );
+
+ if (!initial) {
+ await tester.runTest(
+ `V${newImplementationVersion.toString()} User Smart Wallet can get the new version (${newImplementationVersion.toString()})`,
+ userSmartWalletContract,
+ "getVersion",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, newImplementationVersion.toString());
+ }
+ );
+
+ await tester.runTest(
+ `V${newImplementationVersion.toString()} user smart wallet still has the same user signing key set`,
+ userSmartWalletContract,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, userSigningKey);
+ }
+ );
+
+ await tester.runTest(
+ `V${newImplementationVersion.toString()} User Smart Wallet nonce is still set to value from before upgrade`,
+ userSmartWalletContract,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, nonce);
+ }
+ );
+ }
+}
+
+module.exports = {
+ testPerformingUpgrade
+};
diff --git a/scripts/test/contracts/upgradeability/testUpgradeBeaconController.js b/scripts/test/contracts/upgradeability/testUpgradeBeaconController.js
new file mode 100644
index 0000000..d4f914a
--- /dev/null
+++ b/scripts/test/contracts/upgradeability/testUpgradeBeaconController.js
@@ -0,0 +1,216 @@
+const constants = require("../../constants");
+const assert = require("assert");
+
+async function testUpgradeBeaconController(
+ tester,
+ contract,
+ smartWalletControllerContract,
+ keyRingControllerContract,
+ envoyContract,
+ smartWalletUpgradeBeaconAddress,
+ keyRingUpgradeBeaconAddress,
+ badBeaconAddress
+) {
+ await tester.runTest(
+ `DharmaUpgradeBeaconController initially gets zero for lastImplementation`,
+ contract,
+ "getCodeHashAtLastUpgrade",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.strictEqual(value, constants.NULL_BYTES_32);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot call upgrade from non-owner account`,
+ contract,
+ "upgrade",
+ "send",
+ [
+ smartWalletUpgradeBeaconAddress,
+ smartWalletControllerContract.options.address
+ ],
+ false,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can set implementation on upgrade beacon contract`,
+ smartWalletControllerContract,
+ "upgrade",
+ "send",
+ [
+ smartWalletUpgradeBeaconAddress,
+ smartWalletControllerContract.options.address
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingUpgradeBeaconController can set implementation on key ring upgrade beacon contract`,
+ keyRingControllerContract,
+ "upgrade",
+ "send",
+ [
+ keyRingUpgradeBeaconAddress,
+ smartWalletControllerContract.options.address
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconEnvoy throws when given invalid beacon`,
+ envoyContract,
+ "getImplementation",
+ "call",
+ [envoyContract.options.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconEnvoy throws when given non-contract beacon`,
+ envoyContract,
+ "getImplementation",
+ "call",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconEnvoy can get the implementation of a valid beacon`,
+ envoyContract,
+ "getImplementation",
+ "call",
+ [keyRingUpgradeBeaconAddress],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ smartWalletControllerContract.options.address
+ );
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set null implementation on an upgrade beacon contract`,
+ contract,
+ "upgrade",
+ "send",
+ [smartWalletUpgradeBeaconAddress, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set non-contract implementation`,
+ contract,
+ "upgrade",
+ "send",
+ [smartWalletUpgradeBeaconAddress, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set null address beacon`,
+ contract,
+ "upgrade",
+ "send",
+ [constants.NULL_ADDRESS, smartWalletControllerContract.options.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set non-contract address beacon`,
+ contract,
+ "upgrade",
+ "send",
+ [tester.address, smartWalletControllerContract.options.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set unowned bad beacon`,
+ contract,
+ "upgrade",
+ "send",
+ [badBeaconAddress, smartWalletControllerContract.options.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot set unowned beacon (Note that it still logs an event!)`,
+ contract,
+ "upgrade",
+ "send",
+ [
+ smartWalletUpgradeBeaconAddress,
+ smartWalletControllerContract.options.address
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can get implementation of a beacon`,
+ contract,
+ "getImplementation",
+ "call",
+ [smartWalletUpgradeBeaconAddress],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ smartWalletControllerContract.options.address
+ );
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can get owner`,
+ contract,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can call isOwner and value is ok`,
+ contract,
+ "isOwner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController cannot transfer ownership to null address`,
+ contract,
+ "transferOwnership",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can transfer ownership`,
+ contract,
+ "transferOwnership",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can renounce ownership`,
+ contract,
+ "renounceOwnership"
+ );
+}
+
+module.exports = {
+ testUpgradeBeaconController
+};
diff --git a/scripts/test/contracts/upgradeability/testUpgradeBeaconControllerManager.js b/scripts/test/contracts/upgradeability/testUpgradeBeaconControllerManager.js
new file mode 100644
index 0000000..f090a96
--- /dev/null
+++ b/scripts/test/contracts/upgradeability/testUpgradeBeaconControllerManager.js
@@ -0,0 +1,1009 @@
+const constants = require("../../constants");
+const assert = require("assert");
+
+async function testUpgradeBeaconControllerManagerPartOne(tester, contract) {
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot transfer ownership from a non-owner`,
+ contract,
+ "transferOwnership",
+ "send",
+ [tester.addressTwo],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null controller`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [constants.NULL_ADDRESS, tester.address, tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null beacon`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null implementation`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [tester.address, tester.addressTwo, constants.NULL_ADDRESS, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with non-contract implementation`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [tester.address, tester.addressTwo, tester.address, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with massive extraTime`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [
+ tester.address,
+ tester.addressTwo,
+ contract.options.address,
+ constants.FULL_APPROVAL
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can initiate upgrade timelock`,
+ contract,
+ "initiateUpgrade",
+ "send",
+ [tester.address, tester.addressTwo, contract.options.address, 0]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get an empty timelock`,
+ contract,
+ "getTimelock",
+ "call",
+ ["0x01020304", "0x"],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.ok(!value.completed);
+ assert.ok(!value.expired);
+ assert.strictEqual(value.completionTime, "0");
+ assert.strictEqual(value.expirationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get an empty default timelock interval`,
+ contract,
+ "getDefaultTimelockInterval",
+ "call",
+ ["0x01020304"],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get an empty default timelock expiration`,
+ contract,
+ "getDefaultTimelockExpiration",
+ "call",
+ ["0x01020304"],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot upgrade before timelock is complete`,
+ contract,
+ "upgrade",
+ "send",
+ [tester.address, tester.addressTwo, contract.options.address],
+ false
+ );
+
+ // advance time by 7 days
+ await tester.advanceTime(60 * 60 * 24 * 7 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot upgrade an unowned controller`,
+ contract,
+ "upgrade",
+ "send",
+ [tester.address, tester.addressTwo, contract.options.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot transfer controller ownership before accepting ownership`,
+ contract,
+ "transferControllerOwnership",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot agree to accept ownership of null controller`,
+ contract,
+ "agreeToAcceptControllerOwnership",
+ "send",
+ [constants.NULL_ADDRESS, true],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can agree to accept ownership`,
+ contract,
+ "agreeToAcceptControllerOwnership",
+ "send",
+ [tester.address, true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer with null controller`,
+ contract,
+ "initiateTransferControllerOwnership",
+ "send",
+ [constants.NULL_ADDRESS, tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer with null new owner`,
+ contract,
+ "initiateTransferControllerOwnership",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer if new owner has not accepted`,
+ contract,
+ "initiateTransferControllerOwnership",
+ "send",
+ [tester.address, tester.addressTwo, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can initiate controller ownership transfer if new owner has accepted`,
+ contract,
+ "initiateTransferControllerOwnership",
+ "send",
+ [tester.address, tester.address, 0]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot transfer controller ownership prior to timelock completion`,
+ contract,
+ "transferControllerOwnership",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ // advance time by 4 weeks
+ await tester.advanceTime(60 * 60 * 24 * 7 * 4 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot transfer unowned controller ownership`,
+ contract,
+ "transferControllerOwnership",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot heartbeat from non-heartbeater`,
+ contract,
+ "heartbeat",
+ "send",
+ [],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can heartbeat`,
+ contract,
+ "heartbeat"
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot set new heartbeater to null address`,
+ contract,
+ "newHeartbeater",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can set new heartbeater`,
+ contract,
+ "newHeartbeater",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot arm Adharma Contingency from non-owner when not expired`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when not armed`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can arm an Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can disarm Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [false]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can re-arm Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency from non-owner when not expired`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when it doesn't own controllers`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot roll back prior to first upgrade`,
+ contract,
+ "rollback",
+ "send",
+ [tester.address, tester.address, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot exit Adharma Contingency when not active`,
+ contract,
+ "exitAdharmaContingency",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ /*
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can activate Adharma Contingency`,
+ contract,
+ 'activateAdharmaContingency',
+ 'send',
+ []
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner cannot arm Adharma Contingency while active`,
+ contract,
+ 'armAdharmaContingency',
+ 'send',
+ [true]
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Contingency when activated`,
+ contract,
+ 'activateAdharmaContingency',
+ 'send',
+ [],
+ false
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can disarm Adharma Contingency`,
+ contract,
+ 'armAdharmaContingency',
+ 'send',
+ [false]
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot exit Contingency before 48 hours`,
+ contract,
+ 'exitAdharmaContingency',
+ 'send',
+ [
+ DharmaSmartWalletImplementationV6.options.address,
+ DharmaKeyRingImplementationV1.options.address
+ ],
+ false
+ )
+
+ // advance time by 2 days
+ await tester.advanceTime((60 * 60 * 24 * 2) + 5)
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot exit Contingency to null address`,
+ contract,
+ 'exitAdharmaContingency',
+ 'send',
+ [constants.NULL_ADDRESS, DharmaKeyRingImplementationV1.options.address],
+ false
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot exit Contingency to non-contract address`,
+ contract,
+ 'exitAdharmaContingency',
+ 'send',
+ [address, address],
+ false
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can exit Contingency after 48 hours`,
+ contract,
+ 'exitAdharmaContingency',
+ 'send',
+ [
+ DharmaSmartWalletImplementationV6.options.address,
+ DharmaKeyRingImplementationV1.options.address
+ ]
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can arm Adharma Contingency again`,
+ contract,
+ 'armAdharmaContingency',
+ 'send',
+ [true]
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can activate fake Adharma Contingency again`,
+ contract,
+ 'activateAdharmaContingency',
+ 'send',
+ []
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can roll back from fake Adharma Contingency`,
+ contract,
+ 'rollback',
+ 'send',
+ [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS, constants.UPGRADE_BEACON_ADDRESS, 0]
+ )
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can "roll forward" after roll back`,
+ contract,
+ 'rollback',
+ 'send',
+ [constants.UPGRADE_BEACON_ADDRESS, constants.UPGRADE_BEACON_ADDRESS]
+ )
+ */
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get heartbeat status`,
+ contract,
+ "heartbeatStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.expired);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager get contingency status when armed but not activated`,
+ contract,
+ "contingencyStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.armed);
+ assert.ok(!value.activated);
+ assert.strictEqual(value.activationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager gets 0 for non-existent total implementations`,
+ contract,
+ "getTotalPriorImplementations",
+ "call",
+ [tester.address, tester.address],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot get a prior implementation with no index`,
+ contract,
+ "getPriorImplementation",
+ "call",
+ [tester.address, tester.address, 100],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot rollback to implementation with no index`,
+ contract,
+ "rollback",
+ "send",
+ [tester.address, tester.address, 100],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot block rollback to implementation with no index`,
+ contract,
+ "blockRollback",
+ "send",
+ [tester.address, tester.address, 100],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockInterval with no selector`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot create timelock with excessive duration`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", constants.FULL_APPROVAL, 0],
+ false // TODO: move this outside of Controller manager
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to set a timelock`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10000, 5]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot shorten existing initiateModifyTimelockInterval timelock`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10000, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to change a duration`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xe950c085", 10001, 5]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockInterval",
+ "send",
+ ["0xaaaaaaaa", 10000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockInterval with no selector`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockInterval before timelock completion`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0xe950c085", 1000],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration with no selector`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration to with expiration over one month`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 5443200, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 30, 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockExpiration to set a timelock`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300000, 0]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockExpiration to set a timelock on another function`,
+ contract,
+ "initiateModifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 30, 0]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration with no selector`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0x00000000", 0],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration before timelock completion`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300],
+ false
+ );
+
+ // advance time by 4 weeks
+ await tester.advanceTime(60 * 60 * 24 * 7 * 4 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call modifyTimelockInterval`,
+ contract,
+ "modifyTimelockInterval",
+ "send",
+ ["0xaaaaaaaa", 10000]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call modifyTimelockExpiration`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xd7ce3c6f", 300000]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration if expiration is too short`,
+ contract,
+ "modifyTimelockExpiration",
+ "send",
+ ["0xe950c085", 30],
+ false
+ );
+}
+
+async function testUpgradeBeaconControllerManagerPartTwo(
+ tester,
+ contract,
+ upgradeBeaconControllerContract,
+ keyRingUpgradeBeaconControllerContract,
+ upgradeBeaconAddress,
+ adharmaSmartWalletImplementationAddress,
+ smartWalletImplementationAddress,
+ keyRingImplementationAddress
+) {
+ // Transfer smart wallet controller ownership to coverage manager
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can transfer ownership to manager`,
+ upgradeBeaconControllerContract,
+ "transferOwnership",
+ "send",
+ [contract.options.address]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when it doesn't own keyring controller`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingUpgradeBeaconController can transfer ownership to manager`,
+ keyRingUpgradeBeaconControllerContract,
+ "transferOwnership",
+ "send",
+ [contract.options.address]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can activate Adharma Contingency`,
+ contract,
+ "activateAdharmaContingency"
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get contingency status when activated`,
+ contract,
+ "contingencyStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.armed);
+ assert.ok(value.activated);
+ //assert.strictEqual(value.activationTime, '?')
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can re-arm an active Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when already active`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager now gets a prior implementation count`,
+ contract,
+ "getTotalPriorImplementations",
+ "call",
+ [upgradeBeaconControllerContract.options.address, upgradeBeaconAddress],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can get the initial prior implementation`,
+ contract,
+ "getPriorImplementation",
+ "call",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(
+ value.priorImplementation,
+ adharmaSmartWalletImplementationAddress
+ );
+ assert.ok(value.rollbackAllowed);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call "exitAdharmaContingency" before 48 hours has elapsed`,
+ contract,
+ "exitAdharmaContingency",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can rollback to initial prior implementation`,
+ contract,
+ "rollback",
+ "send",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contingency status is exited after rollback`,
+ contract,
+ "contingencyStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.armed);
+ assert.ok(!value.activated);
+ assert.strictEqual(value.activationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot rollback to implementation with no index`,
+ contract,
+ "rollback",
+ "send",
+ [tester.address, tester.address, 100],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can re-arm an Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contingency status shows armed`,
+ contract,
+ "contingencyStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.armed);
+ assert.ok(!value.activated);
+ assert.strictEqual(value.activationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can rollback to initial prior implementation`,
+ contract,
+ "rollback",
+ "send",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contingency status shows no longer armed`,
+ contract,
+ "contingencyStatus",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.armed);
+ assert.ok(!value.activated);
+ assert.strictEqual(value.activationTime, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can block rollback to prior implementation`,
+ contract,
+ "blockRollback",
+ "send",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot block a blocked rollback`,
+ contract,
+ "blockRollback",
+ "send",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot rollback to a blocked rollback`,
+ contract,
+ "rollback",
+ "send",
+ [
+ upgradeBeaconControllerContract.options.address,
+ upgradeBeaconAddress,
+ 0
+ ],
+ false
+ );
+
+ // advance time by 90 days
+ await tester.advanceTime(60 * 60 * 24 * 90 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager deadman switch can arm an Adharma Contingency`,
+ contract,
+ "armAdharmaContingency",
+ "send",
+ [true],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager deadman switch can activate an Adharma Contingency`,
+ contract,
+ "activateAdharmaContingency",
+ "send",
+ [],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ // advance time by 2 days
+ await tester.advanceTime(60 * 60 * 24 * 2 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call exitAdharmaContingency with null implementation`,
+ contract,
+ "exitAdharmaContingency",
+ "send",
+ [constants.NULL_ADDRESS, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager cannot call exitAdharmaContingency with non-contract implementation`,
+ contract,
+ "exitAdharmaContingency",
+ "send",
+ [tester.address, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can call exitAdharmaContingency`,
+ contract,
+ "exitAdharmaContingency",
+ "send",
+ [smartWalletImplementationAddress, keyRingImplementationAddress]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can have an EOA accept controller ownership`,
+ contract,
+ "agreeToAcceptControllerOwnership",
+ "send",
+ [upgradeBeaconControllerContract.options.address, true]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can initiate timelock for transferring controller ownership`,
+ contract,
+ "initiateTransferControllerOwnership",
+ "send",
+ [upgradeBeaconControllerContract.options.address, tester.address, 0]
+ );
+
+ // advance time by 4 weeks
+ await tester.advanceTime(60 * 60 * 24 * 7 * 4 + 5);
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager can transfer controller ownership`,
+ contract,
+ "transferControllerOwnership",
+ "send",
+ [upgradeBeaconControllerContract.options.address, tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can get new owner`,
+ upgradeBeaconControllerContract,
+ "isOwner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+}
+
+module.exports = {
+ testUpgradeBeaconControllerManagerPartOne,
+ testUpgradeBeaconControllerManagerPartTwo
+};
diff --git a/scripts/test/deploy.js b/scripts/test/deploy.js
index dc4b26c..818ee35 100644
--- a/scripts/test/deploy.js
+++ b/scripts/test/deploy.js
@@ -1,13 +1,34 @@
-var assert = require('assert')
-var fs = require('fs')
-var util = require('ethereumjs-util')
-const constants = require('./constants.js')
+var assert = require("assert");
+var fs = require("fs");
+var util = require("ethereumjs-util");
+const constants = require("./constants.js");
+const { web3 } = require("./web3");
+const {
+ Tester,
+ swapMetadataHash,
+ newContractAndSwapMetadataHash
+} = require("./testHelpers");
+const {
+ testIndestructibleRegistry
+} = require("./contracts/indestructible-registry/testIndestructibleRegistry");
+const {
+ testDharmaUpgradeMultisigDeployer
+} = require("./contracts/multisig-deployers/testDharmaUpgradeMultisigDeployer");
+const {
+ testDharmaAccountRecoveryMultisigDeployer
+} = require("./contracts/multisig-deployers/testDharmaAccountRecoveryMultisigDeployer");
+const {
+ testDharmaAccountRecoveryOperatorMultisigDeployer
+} = require("./contracts/multisig-deployers/testDharmaAccountRecoveryOperatorMultisigDeployer");
+const {
+ testDharmaKeyRegistryMultisigDeployer
+} = require("./contracts/multisig-deployers/testDharmaKeyRegistryMultisigDeployer");
let DharmaUpgradeBeaconArtifact;
let DharmaUpgradeBeaconControllerArtifact;
let DharmaUpgradeBeaconEnvoyArtifact;
let DharmaKeyRingUpgradeBeaconArtifact;
-let DharmaKeyRegistryV1Artifact;
+//let DharmaKeyRegistryV1Artifact;
let DharmaKeyRegistryV2Artifact;
let DharmaAccountRecoveryManagerV2Artifact;
let DharmaSmartWalletFactoryV1Artifact;
@@ -18,373 +39,331 @@ let DharmaUpgradeBeaconControllerManagerArtifact;
let DharmaKeyRingFactoryV2Artifact;
let DharmaEscapeHatchRegistryArtifact;
-const DharmaUpgradeMultisigArtifact = require('../../build/contracts/DharmaUpgradeMultisig.json')
-const DharmaAccountRecoveryMultisigArtifact = require('../../build/contracts/DharmaAccountRecoveryMultisig.json')
-const DharmaAccountRecoveryOperatorMultisigArtifact = require('../../build/contracts/DharmaAccountRecoveryOperatorMultisig.json')
-const DharmaKeyRegistryMultisigArtifact = require('../../build/contracts/DharmaKeyRegistryMultisig.json')
-const DharmaTestingMultisigArtifact = require('../../build/contracts/DharmaTestingMultisig.json')
+let DharmaDaiUpgradeBeaconArtifact;
+let DharmaDaiArtifact;
-const DharmaSmartWalletImplementationV0Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV0.json')
-const DharmaSmartWalletImplementationV1Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV1.json')
-const DharmaSmartWalletImplementationV2Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV2.json')
+let DharmaUSDCUpgradeBeaconArtifact;
+let DharmaUSDCArtifact;
+
+let SmartWalletRevertReasonHelperV1Artifact;
+
+const DharmaDaiInitializerArtifact = require("../../build/contracts/DharmaDaiInitializer.json");
+const DharmaDaiImplementationV1Artifact = require("../../build/contracts/MockDharmaDaiImplementationV1.json");
+
+const DharmaUSDCInitializerArtifact = require("../../build/contracts/DharmaUSDCInitializer.json");
+const DharmaUSDCImplementationV1Artifact = require("../../build/contracts/DharmaUSDCImplementationV1.json");
+
+const DharmaUpgradeMultisigArtifact = require("../../build/contracts/DharmaUpgradeMultisig.json");
+const DharmaAccountRecoveryMultisigArtifact = require("../../build/contracts/DharmaAccountRecoveryMultisig.json");
+const DharmaAccountRecoveryOperatorMultisigArtifact = require("../../build/contracts/DharmaAccountRecoveryOperatorMultisig.json");
+const DharmaKeyRegistryMultisigArtifact = require("../../build/contracts/DharmaKeyRegistryMultisig.json");
+const DharmaTestingMultisigArtifact = require("../../build/contracts/DharmaTestingMultisig.json");
+
+//const DharmaSmartWalletImplementationV0Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV0.json')
+//const DharmaSmartWalletImplementationV1Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV1.json')
+//const DharmaSmartWalletImplementationV2Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV2.json')
//const DharmaSmartWalletImplementationV3Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV3.json')
//const DharmaSmartWalletImplementationV4Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV4.json')
-const DharmaSmartWalletImplementationV5Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV5.json')
+//const DharmaSmartWalletImplementationV5Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV5.json')
+const DharmaSmartWalletImplementationV6Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV6.json");
+const DharmaSmartWalletImplementationV7Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV7.json");
//const DharmaKeyRingImplementationV0Artifact = require('../../build/contracts/DharmaKeyRingImplementationV0.json')
-const DharmaKeyRingImplementationV1Artifact = require('../../build/contracts/DharmaKeyRingImplementationV1.json')
+const DharmaKeyRingImplementationV1Artifact = require("../../build/contracts/DharmaKeyRingImplementationV1.json");
//const DharmaKeyRingImplementationV2Artifact = require('../../build/contracts/DharmaKeyRingImplementationV2.json')
-const UpgradeBeaconImplementationCheckArtifact = require('../../build/contracts/UpgradeBeaconImplementationCheck.json')
-const BadBeaconArtifact = require('../../build/contracts/BadBeacon.json')
-const BadBeaconTwoArtifact = require('../../build/contracts/BadBeaconTwo.json')
-const MockCodeCheckArtifact = require('../../build/contracts/MockCodeCheck.json')
-const IERC20Artifact = require('../../build/contracts/IERC20.json')
-
-const DharmaUpgradeBeaconControllerCoverageArtifact = require('../../build/contracts/DharmaUpgradeBeaconController.json')
-const DharmaUpgradeBeaconControllerManagerCoverageArtifact = require('../../build/contracts/DharmaUpgradeBeaconControllerManager.json')
+const UpgradeBeaconImplementationCheckArtifact = require("../../build/contracts/UpgradeBeaconImplementationCheck.json");
+const BadBeaconArtifact = require("../../build/contracts/BadBeacon.json");
+const BadBeaconTwoArtifact = require("../../build/contracts/BadBeaconTwo.json");
+const MockCodeCheckArtifact = require("../../build/contracts/MockCodeCheck.json");
+const IERC20Artifact = require("../../build/contracts/IERC20.json");
+
+const DharmaUpgradeBeaconControllerCoverageArtifact = require("../../build/contracts/DharmaUpgradeBeaconController.json");
+const DharmaUpgradeBeaconControllerManagerCoverageArtifact = require("../../build/contracts/DharmaUpgradeBeaconControllerManager.json");
+
+const ImmutableCreate2FactoryArtifact = require("../../build/contracts/ImmutableCreate2Factory.json");
+const IndestructibleRegistryArtifact = require("../../build/contracts/IndestructibleRegistry.json");
+const CodeHashCacheArtifact = require("../../build/contracts/CodeHashCache.json");
+
+async function test(testingContext) {
+ if (testingContext === "coverage") {
+ DharmaUpgradeBeaconEnvoyArtifact = require("../../../build/contracts/DharmaUpgradeBeaconEnvoy.json");
+ DharmaUpgradeBeaconControllerArtifact = require("../../../build/contracts/DharmaUpgradeBeaconController.json");
+ DharmaUpgradeBeaconArtifact = require("../../../build/contracts/DharmaUpgradeBeacon.json");
+ DharmaKeyRingUpgradeBeaconArtifact = require("../../../build/contracts/DharmaKeyRingUpgradeBeacon.json");
+ DharmaDaiUpgradeBeaconArtifact = require("../../../build/contracts/DharmaDaiUpgradeBeacon.json");
+ DharmaUSDCUpgradeBeaconArtifact = require("../../../build/contracts/DharmaUSDCUpgradeBeacon.json");
+ //DharmaKeyRegistryV1Artifact = require('../../../build/contracts/DharmaKeyRegistryV1.json')
+ DharmaKeyRegistryV2Artifact = require("../../../build/contracts/DharmaKeyRegistryV2.json");
+ DharmaSmartWalletFactoryV1Artifact = require("../../../build/contracts/DharmaSmartWalletFactoryV1.json");
+ DharmaKeyRingFactoryV2Artifact = require("../../../build/contracts/DharmaKeyRingFactoryV2.json");
+ UpgradeBeaconProxyV1Artifact = require("../../../build/contracts/UpgradeBeaconProxyV1.json");
+ DharmaAccountRecoveryManagerV2Artifact = require("../../../build/contracts/DharmaAccountRecoveryManagerV2.json");
+ AdharmaSmartWalletImplementationArtifact = require("../../../build/contracts/AdharmaSmartWalletImplementation.json");
+ AdharmaKeyRingImplementationArtifact = require("../../../build/contracts/AdharmaKeyRingImplementation.json");
+ DharmaUpgradeBeaconControllerManagerArtifact = require("../../../build/contracts/DharmaUpgradeBeaconControllerManager.json");
+ DharmaEscapeHatchRegistryArtifact = require("../../../build/contracts/DharmaEscapeHatchRegistry.json");
+ DharmaDaiUpgradeBeaconArtifact = require("../../../build/contracts/DharmaDaiUpgradeBeacon.json");
+ DharmaDaiArtifact = require("../../../build/contracts/DharmaDai.json");
+ DharmaUSDCUpgradeBeaconArtifact = require("../../../build/contracts/DharmaUSDCUpgradeBeacon.json");
+ DharmaUSDCArtifact = require("../../../build/contracts/DharmaUSDC.json");
+ SmartWalletRevertReasonHelperV1Artifact = require("../../../build/contracts/SmartWalletRevertReasonHelperV1.json");
+ } else {
+ DharmaUpgradeBeaconEnvoyArtifact = require("../../build/contracts/DharmaUpgradeBeaconEnvoy.json");
+ DharmaUpgradeBeaconControllerArtifact = require("../../build/contracts/DharmaUpgradeBeaconController.json");
+ DharmaUpgradeBeaconArtifact = require("../../build/contracts/DharmaUpgradeBeacon.json");
+ DharmaKeyRingUpgradeBeaconArtifact = require("../../build/contracts/DharmaKeyRingUpgradeBeacon.json");
+ DharmaDaiUpgradeBeaconArtifact = require("../../build/contracts/DharmaDaiUpgradeBeacon.json");
+ DharmaUSDCUpgradeBeaconArtifact = require("../../build/contracts/DharmaUSDCUpgradeBeacon.json");
+ //DharmaKeyRegistryV1Artifact = require('../../build/contracts/DharmaKeyRegistryV1.json')
+ DharmaKeyRegistryV2Artifact = require("../../build/contracts/DharmaKeyRegistryV2.json");
+ DharmaSmartWalletFactoryV1Artifact = require("../../build/contracts/DharmaSmartWalletFactoryV1.json");
+ DharmaKeyRingFactoryV2Artifact = require("../../build/contracts/DharmaKeyRingFactoryV2.json");
+ UpgradeBeaconProxyV1Artifact = require("../../build/contracts/UpgradeBeaconProxyV1.json");
+ DharmaAccountRecoveryManagerV2Artifact = require("../../build/contracts/DharmaAccountRecoveryManagerV2.json");
+ AdharmaSmartWalletImplementationArtifact = require("../../build/contracts/AdharmaSmartWalletImplementation.json");
+ AdharmaKeyRingImplementationArtifact = require("../../build/contracts/AdharmaKeyRingImplementation.json");
+ DharmaUpgradeBeaconControllerManagerArtifact = require("../../build/contracts/DharmaUpgradeBeaconControllerManager.json");
+ DharmaEscapeHatchRegistryArtifact = require("../../build/contracts/DharmaEscapeHatchRegistry.json");
+ DharmaDaiUpgradeBeaconArtifact = require("../../build/contracts/DharmaDaiUpgradeBeacon.json");
+ DharmaDaiArtifact = require("../../build/contracts/DharmaDai.json");
+ DharmaUSDCUpgradeBeaconArtifact = require("../../build/contracts/DharmaUSDCUpgradeBeacon.json");
+ DharmaUSDCArtifact = require("../../build/contracts/DharmaUSDC.json");
+ SmartWalletRevertReasonHelperV1Artifact = require("../../build/contracts/SmartWalletRevertReasonHelperV1.json");
+ }
-const ImmutableCreate2FactoryArtifact = require('../../build/contracts/ImmutableCreate2Factory.json')
-const IndestructibleRegistryArtifact = require('../../build/contracts/IndestructibleRegistry.json')
-const CodeHashCacheArtifact = require('../../build/contracts/CodeHashCache.json')
+ /*
+ console.log(
+ swapMetadataHash(
+ DharmaSmartWalletImplementationV7Artifact.bytecode,
+ constants.DHARMA_SMART_WALLET_IMPLEMENTATION_V7_METADATA
+ ),
+ web3.utils.keccak256(swapMetadataHash(
+ DharmaSmartWalletImplementationV7Artifact.bytecode,
+ constants.DHARMA_SMART_WALLET_IMPLEMENTATION_V7_METADATA
+ ), {encoding: 'hex'})
+ )
+ process.exit(0)
+ */
-// used to wait for more confirmations
-function longer() {
- return new Promise(resolve => {setTimeout(() => {resolve()}, 500)})
-}
+ const DharmaUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
-function swapMetadataHash(bytecode, newMetadataHashes) {
- const totalBzzrs = bytecode.split(constants.METADATA_IDENTIFIER).length - 1
+ const DharmaUpgradeBeacon = new web3.eth.Contract(
+ DharmaUpgradeBeaconArtifact.abi,
+ constants.UPGRADE_BEACON_ADDRESS
+ );
- if (totalBzzrs !== newMetadataHashes.length) {
- throw("number of metadata hashes to replace must match provided number.")
- }
+ const DharmaKeyRingUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
- let startingPoint = bytecode.length - 1;
+ const DharmaKeyRingUpgradeBeacon = new web3.eth.Contract(
+ DharmaKeyRingUpgradeBeaconArtifact.abi,
+ constants.KEY_RING_UPGRADE_BEACON_ADDRESS
+ );
- for (i = 0; i < totalBzzrs; i++) {
- let replacement = constants.METADATA_IDENTIFIER + newMetadataHashes.slice(i)[0]
- let lastIndex = bytecode.lastIndexOf(
- constants.METADATA_IDENTIFIER, startingPoint
- )
- bytecode = (
- bytecode.slice(0, lastIndex) + replacement + bytecode.slice(
- lastIndex + replacement.length, bytecode.length
- )
- )
- startingPoint = lastIndex - 1;
- }
-
- return bytecode
-}
+ const DharmaAccountRecoveryManagerV2 = new web3.eth.Contract(
+ DharmaAccountRecoveryManagerV2Artifact.abi,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
+ );
-module.exports = {test: async function (provider, testingContext) {
- if (testingContext === 'coverage') {
- DharmaUpgradeBeaconEnvoyArtifact = require('../../../build/contracts/DharmaUpgradeBeaconEnvoy.json')
- DharmaUpgradeBeaconControllerArtifact = require('../../../build/contracts/DharmaUpgradeBeaconController.json')
- DharmaUpgradeBeaconArtifact = require('../../../build/contracts/DharmaUpgradeBeacon.json')
- DharmaKeyRingUpgradeBeaconArtifact = require('../../../build/contracts/DharmaKeyRingUpgradeBeacon.json')
- DharmaKeyRegistryV1Artifact = require('../../../build/contracts/DharmaKeyRegistryV1.json')
- DharmaKeyRegistryV2Artifact = require('../../../build/contracts/DharmaKeyRegistryV2.json')
- DharmaSmartWalletFactoryV1Artifact = require('../../../build/contracts/DharmaSmartWalletFactoryV1.json')
- DharmaKeyRingFactoryV2Artifact = require('../../../build/contracts/DharmaKeyRingFactoryV2.json')
- UpgradeBeaconProxyV1Artifact = require('../../../build/contracts/UpgradeBeaconProxyV1.json')
- DharmaAccountRecoveryManagerV2Artifact = require('../../../build/contracts/DharmaAccountRecoveryManagerV2.json')
- AdharmaSmartWalletImplementationArtifact = require('../../../build/contracts/AdharmaSmartWalletImplementation.json')
- AdharmaKeyRingImplementationArtifact = require('../../../build/contracts/AdharmaKeyRingImplementation.json')
- DharmaUpgradeBeaconControllerManagerArtifact = require('../../../build/contracts/DharmaUpgradeBeaconControllerManager.json')
- DharmaEscapeHatchRegistryArtifact = require('../../../build/contracts/DharmaEscapeHatchRegistry.json')
- } else {
- DharmaUpgradeBeaconEnvoyArtifact = require('../../build/contracts/DharmaUpgradeBeaconEnvoy.json')
- DharmaUpgradeBeaconControllerArtifact = require('../../build/contracts/DharmaUpgradeBeaconController.json')
- DharmaUpgradeBeaconArtifact = require('../../build/contracts/DharmaUpgradeBeacon.json')
- DharmaKeyRingUpgradeBeaconArtifact = require('../../build/contracts/DharmaKeyRingUpgradeBeacon.json')
- DharmaKeyRegistryV1Artifact = require('../../build/contracts/DharmaKeyRegistryV1.json')
- DharmaKeyRegistryV2Artifact = require('../../build/contracts/DharmaKeyRegistryV2.json')
- DharmaSmartWalletFactoryV1Artifact = require('../../build/contracts/DharmaSmartWalletFactoryV1.json')
- DharmaKeyRingFactoryV2Artifact = require('../../build/contracts/DharmaKeyRingFactoryV2.json')
- UpgradeBeaconProxyV1Artifact = require('../../build/contracts/UpgradeBeaconProxyV1.json')
- DharmaAccountRecoveryManagerV2Artifact = require('../../build/contracts/DharmaAccountRecoveryManagerV2.json')
- AdharmaSmartWalletImplementationArtifact = require('../../build/contracts/AdharmaSmartWalletImplementation.json')
- AdharmaKeyRingImplementationArtifact = require('../../build/contracts/AdharmaKeyRingImplementation.json')
- DharmaUpgradeBeaconControllerManagerArtifact = require('../../build/contracts/DharmaUpgradeBeaconControllerManager.json')
- DharmaEscapeHatchRegistryArtifact = require('../../build/contracts/DharmaEscapeHatchRegistry.json')
- }
-
- var web3 = provider
- let passed = 0
- let failed = 0
- let gasUsage = {}
- let counts = {}
-
- /*
- console.log(
- swapMetadataHash(
- DharmaSmartWalletImplementationV5Artifact.bytecode,
- constants.DHARMA_SMART_WALLET_IMPLEMENTATION_V5_METADATA
- ),
- web3.utils.keccak256(swapMetadataHash(
- DharmaSmartWalletImplementationV5Artifact.bytecode,
- constants.DHARMA_SMART_WALLET_IMPLEMENTATION_V5_METADATA
- ), {encoding: 'hex'})
+ /*
+ const DharmaKeyRegistryV1 = new web3.eth.Contract(
+ DharmaKeyRegistryV1Artifact.abi,
+ constants.KEY_REGISTRY_ADDRESS
)
- process.exit(0)
*/
- const DharmaUpgradeBeaconController = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi,
- constants.UPGRADE_BEACON_CONTROLLER_ADDRESS
- )
-
- const DharmaUpgradeBeacon = new web3.eth.Contract(
- DharmaUpgradeBeaconArtifact.abi,
- constants.UPGRADE_BEACON_ADDRESS
- )
-
- const DharmaKeyRingUpgradeBeaconController = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS
- )
+ const DharmaKeyRegistryV2 = new web3.eth.Contract(
+ DharmaKeyRegistryV2Artifact.abi,
+ constants.KEY_REGISTRY_V2_ADDRESS
+ );
- const DharmaKeyRingUpgradeBeacon = new web3.eth.Contract(
- DharmaKeyRingUpgradeBeaconArtifact.abi,
- constants.KEY_RING_UPGRADE_BEACON_ADDRESS
- )
+ const DharmaEscapeHatchRegistry = new web3.eth.Contract(
+ DharmaEscapeHatchRegistryArtifact.abi,
+ constants.ESCAPE_HATCH_REGISTRY_ADDRESS
+ );
- const DharmaAccountRecoveryManagerV2 = new web3.eth.Contract(
- DharmaAccountRecoveryManagerV2Artifact.abi,
- constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
- )
+ const DharmaSmartWalletFactoryV1 = new web3.eth.Contract(
+ DharmaSmartWalletFactoryV1Artifact.abi,
+ constants.FACTORY_ADDRESS
+ );
- const DharmaKeyRegistryV1 = new web3.eth.Contract(
- DharmaKeyRegistryV1Artifact.abi,
- constants.KEY_REGISTRY_ADDRESS
- )
+ const DharmaKeyRingFactoryV2 = new web3.eth.Contract(
+ DharmaKeyRingFactoryV2Artifact.abi,
+ constants.KEY_RING_FACTORY_V2_ADDRESS
+ );
- const DharmaKeyRegistryV2 = new web3.eth.Contract(
- DharmaKeyRegistryV2Artifact.abi,
- constants.KEY_REGISTRY_V2_ADDRESS
- )
+ const ActualIndestructibleRegistry = new web3.eth.Contract(
+ IndestructibleRegistryArtifact.abi,
+ constants.INDESTRUCTIBLE_REGISTRY_ADDRESS
+ );
- const DharmaEscapeHatchRegistry = new web3.eth.Contract(
- DharmaEscapeHatchRegistryArtifact.abi,
- constants.ESCAPE_HATCH_REGISTRY_ADDRESS
- )
+ const DharmaDaiUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
- const DharmaSmartWalletFactoryV1 = new web3.eth.Contract(
- DharmaSmartWalletFactoryV1Artifact.abi,
- constants.FACTORY_ADDRESS
- )
+ const DharmaUSDCUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
- const DharmaKeyRingFactoryV2 = new web3.eth.Contract(
- DharmaKeyRingFactoryV2Artifact.abi,
- constants.KEY_RING_FACTORY_V2_ADDRESS
- )
+ const DharmaDaiInitializer = new web3.eth.Contract(
+ DharmaDaiInitializerArtifact.abi,
+ constants.DHARMA_DAI_ADDRESS
+ );
- const ActualIndestructibleRegistry = new web3.eth.Contract(
- IndestructibleRegistryArtifact.abi,
- constants.INDESTRUCTIBLE_REGISTRY_ADDRESS
- )
+ const DharmaUSDCInitializer = new web3.eth.Contract(
+ DharmaUSDCInitializerArtifact.abi,
+ constants.DHARMA_USDC_ADDRESS
+ );
- const IndestructibleRegistryDeployer = new web3.eth.Contract(
- IndestructibleRegistryArtifact.abi
- )
- IndestructibleRegistryDeployer.options.data = (
- swapMetadataHash(
- IndestructibleRegistryArtifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const SmartWalletRevertReasonHelperV1 = new web3.eth.Contract(
+ SmartWalletRevertReasonHelperV1Artifact.abi,
+ constants.REVERT_REASON_HELPER_ADDRESS
+ );
- const CodeHashCacheDeployer = new web3.eth.Contract(
- CodeHashCacheArtifact.abi
- )
- CodeHashCacheDeployer.options.data = (
- swapMetadataHash(
- CodeHashCacheArtifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const CodeHashCacheDeployer = newContractAndSwapMetadataHash(
+ CodeHashCacheArtifact
+ );
- const DharmaUpgradeMultisigDeployer = new web3.eth.Contract(
- DharmaUpgradeMultisigArtifact.abi
- )
- DharmaUpgradeMultisigDeployer.options.data = (
- DharmaUpgradeMultisigArtifact.bytecode
- )
+ const DharmaUpgradeMultisigDeployer = new web3.eth.Contract(
+ DharmaUpgradeMultisigArtifact.abi
+ );
+ DharmaUpgradeMultisigDeployer.options.data =
+ DharmaUpgradeMultisigArtifact.bytecode;
- const DharmaAccountRecoveryMultisigDeployer = new web3.eth.Contract(
- DharmaAccountRecoveryMultisigArtifact.abi
- )
- DharmaAccountRecoveryMultisigDeployer.options.data = (
- DharmaAccountRecoveryMultisigArtifact.bytecode
- )
+ const DharmaAccountRecoveryMultisigDeployer = new web3.eth.Contract(
+ DharmaAccountRecoveryMultisigArtifact.abi
+ );
+ DharmaAccountRecoveryMultisigDeployer.options.data =
+ DharmaAccountRecoveryMultisigArtifact.bytecode;
- const DharmaAccountRecoveryOperatorMultisigDeployer = new web3.eth.Contract(
- DharmaAccountRecoveryOperatorMultisigArtifact.abi
- )
- DharmaAccountRecoveryOperatorMultisigDeployer.options.data = (
- DharmaAccountRecoveryOperatorMultisigArtifact.bytecode
- )
+ const DharmaAccountRecoveryOperatorMultisigDeployer = new web3.eth.Contract(
+ DharmaAccountRecoveryOperatorMultisigArtifact.abi
+ );
+ DharmaAccountRecoveryOperatorMultisigDeployer.options.data =
+ DharmaAccountRecoveryOperatorMultisigArtifact.bytecode;
- const DharmaKeyRegistryMultisigDeployer = new web3.eth.Contract(
- DharmaKeyRegistryMultisigArtifact.abi
- )
- DharmaKeyRegistryMultisigDeployer.options.data = (
- DharmaKeyRegistryMultisigArtifact.bytecode
- )
+ const DharmaKeyRegistryMultisigDeployer = new web3.eth.Contract(
+ DharmaKeyRegistryMultisigArtifact.abi
+ );
+ DharmaKeyRegistryMultisigDeployer.options.data =
+ DharmaKeyRegistryMultisigArtifact.bytecode;
- const DharmaTestingMultisigDeployer = new web3.eth.Contract(
- DharmaTestingMultisigArtifact.abi
- )
- DharmaTestingMultisigDeployer.options.data = (
- DharmaTestingMultisigArtifact.bytecode
- )
+ const DharmaTestingMultisigDeployer = new web3.eth.Contract(
+ DharmaTestingMultisigArtifact.abi
+ );
+ DharmaTestingMultisigDeployer.options.data =
+ DharmaTestingMultisigArtifact.bytecode;
- const DharmaUpgradeBeaconControllerDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi
- )
- DharmaUpgradeBeaconControllerDeployer.options.data = (
- DharmaUpgradeBeaconControllerArtifact.bytecode
- )
+ const DharmaUpgradeBeaconControllerDeployer = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi
+ );
+ DharmaUpgradeBeaconControllerDeployer.options.data =
+ DharmaUpgradeBeaconControllerArtifact.bytecode;
- const DharmaUpgradeBeaconControllerCoverageDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerCoverageArtifact.abi
- )
- DharmaUpgradeBeaconControllerCoverageDeployer.options.data = (
- DharmaUpgradeBeaconControllerCoverageArtifact.bytecode
- )
+ const DharmaUpgradeBeaconControllerCoverageDeployer = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerCoverageArtifact.abi
+ );
+ DharmaUpgradeBeaconControllerCoverageDeployer.options.data =
+ DharmaUpgradeBeaconControllerCoverageArtifact.bytecode;
- const DharmaUpgradeBeaconControllerManagerDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerManagerArtifact.abi
- )
- DharmaUpgradeBeaconControllerManagerDeployer.options.data = (
- DharmaUpgradeBeaconControllerManagerArtifact.bytecode
- )
+ const DharmaUpgradeBeaconControllerManagerDeployer = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerManagerArtifact.abi
+ );
+ DharmaUpgradeBeaconControllerManagerDeployer.options.data =
+ DharmaUpgradeBeaconControllerManagerArtifact.bytecode;
- const DharmaUpgradeBeaconControllerManagerCoverageDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerManagerCoverageArtifact.abi
- )
- DharmaUpgradeBeaconControllerManagerCoverageDeployer.options.data = (
- DharmaUpgradeBeaconControllerManagerCoverageArtifact.bytecode
- )
+ const DharmaUpgradeBeaconControllerManagerCoverageDeployer = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerManagerCoverageArtifact.abi
+ );
+ DharmaUpgradeBeaconControllerManagerCoverageDeployer.options.data =
+ DharmaUpgradeBeaconControllerManagerCoverageArtifact.bytecode;
- const DharmaUpgradeBeaconDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconArtifact.abi
- )
- DharmaUpgradeBeaconDeployer.options.data = (
- DharmaUpgradeBeaconArtifact.bytecode
- )
+ const DharmaUpgradeBeaconDeployer = new web3.eth.Contract(
+ DharmaUpgradeBeaconArtifact.abi
+ );
+ DharmaUpgradeBeaconDeployer.options.data =
+ DharmaUpgradeBeaconArtifact.bytecode;
- const DharmaKeyRingUpgradeBeaconDeployer = new web3.eth.Contract(
- DharmaKeyRingUpgradeBeaconArtifact.abi
- )
- DharmaKeyRingUpgradeBeaconDeployer.options.data = (
- DharmaKeyRingUpgradeBeaconArtifact.bytecode
- )
+ const DharmaKeyRingUpgradeBeaconDeployer = new web3.eth.Contract(
+ DharmaKeyRingUpgradeBeaconArtifact.abi
+ );
+ DharmaKeyRingUpgradeBeaconDeployer.options.data =
+ DharmaKeyRingUpgradeBeaconArtifact.bytecode;
- const BadBeaconDeployer = new web3.eth.Contract(BadBeaconArtifact.abi)
- BadBeaconDeployer.options.data = BadBeaconArtifact.bytecode
+ const BadBeaconDeployer = new web3.eth.Contract(BadBeaconArtifact.abi);
+ BadBeaconDeployer.options.data = BadBeaconArtifact.bytecode;
- const BadBeaconTwoDeployer = new web3.eth.Contract(BadBeaconTwoArtifact.abi)
- BadBeaconTwoDeployer.options.data = BadBeaconTwoArtifact.bytecode
+ const BadBeaconTwoDeployer = new web3.eth.Contract(
+ BadBeaconTwoArtifact.abi
+ );
+ BadBeaconTwoDeployer.options.data = BadBeaconTwoArtifact.bytecode;
- const UpgradeBeaconProxyV1Deployer = new web3.eth.Contract(
- UpgradeBeaconProxyV1Artifact.abi
- )
- UpgradeBeaconProxyV1Deployer.options.data = (
- UpgradeBeaconProxyV1Artifact.bytecode
- )
+ const UpgradeBeaconProxyV1Deployer = new web3.eth.Contract(
+ UpgradeBeaconProxyV1Artifact.abi
+ );
+ UpgradeBeaconProxyV1Deployer.options.data =
+ UpgradeBeaconProxyV1Artifact.bytecode;
+ /*
const DharmaKeyRegistryV1Deployer = new web3.eth.Contract(
DharmaKeyRegistryV1Artifact.abi
)
DharmaKeyRegistryV1Deployer.options.data = (
DharmaKeyRegistryV1Artifact.bytecode
)
+ */
- const DharmaKeyRegistryV2Deployer = new web3.eth.Contract(
- DharmaKeyRegistryV2Artifact.abi
- )
- DharmaKeyRegistryV2Deployer.options.data = (
- DharmaKeyRegistryV2Artifact.bytecode
- )
+ const DharmaKeyRegistryV2Deployer = new web3.eth.Contract(
+ DharmaKeyRegistryV2Artifact.abi
+ );
+ DharmaKeyRegistryV2Deployer.options.data =
+ DharmaKeyRegistryV2Artifact.bytecode;
- const DharmaSmartWalletFactoryV1Deployer = new web3.eth.Contract(
- DharmaSmartWalletFactoryV1Artifact.abi
- )
- DharmaSmartWalletFactoryV1Deployer.options.data = (
- DharmaSmartWalletFactoryV1Artifact.bytecode
- )
+ const DharmaSmartWalletFactoryV1Deployer = new web3.eth.Contract(
+ DharmaSmartWalletFactoryV1Artifact.abi
+ );
+ DharmaSmartWalletFactoryV1Deployer.options.data =
+ DharmaSmartWalletFactoryV1Artifact.bytecode;
- const DharmaKeyRingFactoryV2Deployer = new web3.eth.Contract(
- DharmaKeyRingFactoryV2Artifact.abi
- )
- DharmaKeyRingFactoryV2Deployer.options.data = (
- DharmaKeyRingFactoryV2Artifact.bytecode
- )
+ const DharmaKeyRingFactoryV2Deployer = new web3.eth.Contract(
+ DharmaKeyRingFactoryV2Artifact.abi
+ );
+ DharmaKeyRingFactoryV2Deployer.options.data =
+ DharmaKeyRingFactoryV2Artifact.bytecode;
- const AdharmaSmartWalletImplementationDeployer = new web3.eth.Contract(
- AdharmaSmartWalletImplementationArtifact.abi
- )
- AdharmaSmartWalletImplementationDeployer.options.data = (
- swapMetadataHash(
- AdharmaSmartWalletImplementationArtifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
-
- const AdharmaKeyRingImplementationDeployer = new web3.eth.Contract(
- AdharmaKeyRingImplementationArtifact.abi
- )
- AdharmaKeyRingImplementationDeployer.options.data = (
- swapMetadataHash(
- AdharmaKeyRingImplementationArtifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const AdharmaSmartWalletImplementationDeployer = newContractAndSwapMetadataHash(
+ AdharmaSmartWalletImplementationArtifact
+ );
- const DharmaAccountRecoveryManagerV2Deployer = new web3.eth.Contract(
- DharmaAccountRecoveryManagerV2Artifact.abi
- )
- DharmaAccountRecoveryManagerV2Deployer.options.data = (
- swapMetadataHash(
- DharmaAccountRecoveryManagerV2Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const AdharmaKeyRingImplementationDeployer = newContractAndSwapMetadataHash(
+ AdharmaKeyRingImplementationArtifact
+ );
- const DharmaSmartWalletImplementationV0Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV0Artifact.abi
- )
- DharmaSmartWalletImplementationV0Deployer.options.data = (
- swapMetadataHash(
- DharmaSmartWalletImplementationV0Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const DharmaAccountRecoveryManagerV2Deployer = newContractAndSwapMetadataHash(
+ DharmaAccountRecoveryManagerV2Artifact
+ );
- const DharmaSmartWalletImplementationV1Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV1Artifact.abi
- )
- DharmaSmartWalletImplementationV1Deployer.options.data = (
- swapMetadataHash(
- DharmaSmartWalletImplementationV1Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ /*
+ const DharmaSmartWalletImplementationV0Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV0Artifact
+ );
- const DharmaSmartWalletImplementationV2Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV2Artifact.abi
- )
- DharmaSmartWalletImplementationV2Deployer.options.data = (
- swapMetadataHash(
- DharmaSmartWalletImplementationV2Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const DharmaSmartWalletImplementationV1Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV1Artifact
+ );
+
+ const DharmaSmartWalletImplementationV2Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV2Artifact
+ );
- /*
const DharmaSmartWalletImplementationV3Deployer = new web3.eth.Contract(
DharmaSmartWalletImplementationV3Artifact.abi
)
@@ -404,19 +383,45 @@ module.exports = {test: async function (provider, testingContext) {
['0000000000000000000000000000000000000000000000000000000000000000']
)
)
+
+ const DharmaSmartWalletImplementationV5Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV5Artifact
+ );
*/
- const DharmaSmartWalletImplementationV5Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV5Artifact.abi
- )
- DharmaSmartWalletImplementationV5Deployer.options.data = (
- swapMetadataHash(
- DharmaSmartWalletImplementationV5Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const DharmaSmartWalletImplementationV6Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV6Artifact
+ );
+
+ const DharmaSmartWalletImplementationV7Deployer = newContractAndSwapMetadataHash(
+ DharmaSmartWalletImplementationV7Artifact
+ );
+
+ const DharmaDaiInitializerDeployer = new web3.eth.Contract(
+ DharmaDaiInitializerArtifact.abi
+ );
+ DharmaDaiInitializerDeployer.options.data =
+ DharmaDaiInitializerArtifact.bytecode;
+
+ const DharmaDaiImplementationV1Deployer = new web3.eth.Contract(
+ DharmaDaiImplementationV1Artifact.abi
+ );
+ DharmaDaiImplementationV1Deployer.options.data =
+ DharmaDaiImplementationV1Artifact.bytecode;
+
+ const DharmaUSDCInitializerDeployer = new web3.eth.Contract(
+ DharmaUSDCInitializerArtifact.abi
+ );
+ DharmaUSDCInitializerDeployer.options.data =
+ DharmaUSDCInitializerArtifact.bytecode;
- /*
+ const DharmaUSDCImplementationV1Deployer = new web3.eth.Contract(
+ DharmaUSDCImplementationV1Artifact.abi
+ );
+ DharmaUSDCImplementationV1Deployer.options.data =
+ DharmaUSDCImplementationV1Artifact.bytecode;
+
+ /*
const DharmaKeyRingImplementationV0Deployer = new web3.eth.Contract(
DharmaKeyRingImplementationV0Artifact.abi
)
@@ -428,17 +433,11 @@ module.exports = {test: async function (provider, testingContext) {
)
*/
- const DharmaKeyRingImplementationV1Deployer = new web3.eth.Contract(
- DharmaKeyRingImplementationV1Artifact.abi
- )
- DharmaKeyRingImplementationV1Deployer.options.data = (
- swapMetadataHash(
- DharmaKeyRingImplementationV1Artifact.bytecode,
- ['0000000000000000000000000000000000000000000000000000000000000000']
- )
- )
+ const DharmaKeyRingImplementationV1Deployer = newContractAndSwapMetadataHash(
+ DharmaKeyRingImplementationV1Artifact
+ );
- /*
+ /*
const DharmaKeyRingImplementationV2Deployer = new web3.eth.Contract(
DharmaKeyRingImplementationV2Artifact.abi
)
@@ -450,1254 +449,459 @@ module.exports = {test: async function (provider, testingContext) {
)
*/
- const UpgradeBeaconImplementationCheckDeployer = new web3.eth.Contract(
- UpgradeBeaconImplementationCheckArtifact.abi
- )
- UpgradeBeaconImplementationCheckDeployer.options.data = (
- UpgradeBeaconImplementationCheckArtifact.bytecode
- )
-
- const InefficientImmutableCreate2Factory = new web3.eth.Contract(
- ImmutableCreate2FactoryArtifact.abi,
- constants.INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS
- )
-
- const ImmutableCreate2Factory = new web3.eth.Contract(
- ImmutableCreate2FactoryArtifact.abi,
- constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS
- )
-
- const MockCodeCheckDeployer = new web3.eth.Contract(
- MockCodeCheckArtifact.abi
- )
- MockCodeCheckDeployer.options.data = MockCodeCheckArtifact.bytecode
-
- // construct the payload passed to create2 in order to verify correct behavior
- const testCreate2payload = (
- '0xff' +
- constants.KEYLESS_CREATE2_ADDRESS.slice(2) +
- '0000000000000000000000000000000000000000000000000000000000000000' +
- web3.utils.keccak256(
- MockCodeCheckArtifact.bytecode,
- {encoding: 'hex'}
- ).slice(2)
- )
-
- // determine the target address using the payload
- const targetCodeCheckAddress = web3.utils.toChecksumAddress(
- '0x' + web3.utils.keccak256(
- testCreate2payload,
- {encoding: "hex"}
- ).slice(12).substring(14)
- )
-
- const MockCodeCheckTwo = new web3.eth.Contract(
- MockCodeCheckArtifact.abi,
- targetCodeCheckAddress
- )
+ const UpgradeBeaconImplementationCheckDeployer = new web3.eth.Contract(
+ UpgradeBeaconImplementationCheckArtifact.abi
+ );
+ UpgradeBeaconImplementationCheckDeployer.options.data =
+ UpgradeBeaconImplementationCheckArtifact.bytecode;
- // get available addresses and assign them to various roles
- const addresses = await web3.eth.getAccounts()
- if (addresses.length < 1) {
- console.log('cannot find enough addresses to run tests!')
- process.exit(1)
- }
+ const InefficientImmutableCreate2Factory = new web3.eth.Contract(
+ ImmutableCreate2FactoryArtifact.abi,
+ constants.INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS
+ );
- let latestBlock = await web3.eth.getBlock('latest')
+ const ImmutableCreate2Factory = new web3.eth.Contract(
+ ImmutableCreate2FactoryArtifact.abi,
+ constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS
+ );
- const originalAddress = addresses[0]
+ // construct the payload passed to create2 in order to verify correct behavior
+ const testCreate2payload =
+ "0xff" +
+ constants.KEYLESS_CREATE2_ADDRESS.slice(2) +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ web3.utils
+ .keccak256(MockCodeCheckArtifact.bytecode, { encoding: "hex" })
+ .slice(2);
+
+ // determine the target address using the payload
+ const targetCodeCheckAddress = web3.utils.toChecksumAddress(
+ "0x" +
+ web3.utils
+ .keccak256(testCreate2payload, { encoding: "hex" })
+ .slice(12)
+ .substring(14)
+ );
- let address = await setupNewDefaultAddress(
- '0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed'
- )
+ const tester = new Tester(testingContext);
+ await tester.init();
- let addressTwo = await setupNewDefaultAddress(
- '0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d'
- )
+ console.log("funding initial create2 contract deployer address...");
+ await web3.eth.sendTransaction({
+ from: tester.originalAddress,
+ to: constants.KEYLESS_CREATE2_DEPLOYER_ADDRESS,
+ value: web3.utils.toWei("0.01", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
- const ownerOne = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[0]
- )
- const ownerTwo = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[1]
- )
- const ownerThree = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[2]
- )
- const ownerFour = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[3]
- )
- const ownerFive = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[4]
- )
+ console.log("running tests...");
+
+ let currentKeylessCreate2Runtime;
+ await tester.runTest(
+ "Current runtime code at address of initial create2 factory can be retrieved",
+ tester.MockCodeCheck,
+ "code",
+ "call",
+ [constants.KEYLESS_CREATE2_ADDRESS],
+ true,
+ value => {
+ currentKeylessCreate2Runtime = value;
+ }
+ );
- const gasLimit = latestBlock.gasLimit
-
- console.log('funding initial create2 contract deployer address...')
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: constants.KEYLESS_CREATE2_DEPLOYER_ADDRESS,
- value: web3.utils.toWei('0.01', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
-
- console.log('running tests...')
-
- // ************************** helper functions **************************** //
- async function send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- const receipt = await instance.methods[method](...args).send({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
+ // submit the initial create2 deployment transaction if needed
+ if (
+ currentKeylessCreate2Runtime !== constants.KEYLESS_CREATE2_RUNTIME_HASH
+ ) {
+ console.log(
+ " ✓ submitting initial create2 contract deployment transaction..."
+ );
+ await web3.eth.sendSignedTransaction(
+ constants.KEYLESS_CREATE2_DEPLOYMENT_TRANSACTION
+ );
+ tester.passed++;
+
+ // deploy a mock code check contract using the initial create2 deployer
+ console.log(" ✓ deploying test contract via create2 contract...");
+ const DeploymentTx = await web3.eth.sendTransaction({
+ from: tester.originalAddress,
+ to: constants.KEYLESS_CREATE2_ADDRESS,
+ value: 0,
+ gas: testingContext !== "coverage" ? 1500051 : tester.gasLimit - 1,
+ gasPrice: 1,
+ data: MockCodeCheckArtifact.bytecode
+ });
+ tester.passed++;
+ } else {
+ console.log(
+ " ✓ initial create2 contract already deployed, skipping..."
+ );
}
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
+ let currentInefficientImmutableCreate2FactoryRuntimeHash;
+ await tester.runTest(
+ "Current runtime hash at address of inefficient immutable create2 factory can be retrieved",
+ tester.MockCodeCheck,
+ "hash",
+ "call",
+ [constants.INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS],
+ true,
+ value => {
+ currentInefficientImmutableCreate2FactoryRuntimeHash = value;
+ }
+ );
- return assertionsPassed
- }
-
- async function call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let succeeded = true
- returnValues = await instance.methods[method](...args).call({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- succeeded = false
- })
-
- if (succeeded !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
+ // submit the inefficient immutable create2 deployment transaction if needed
+ if (
+ currentInefficientImmutableCreate2FactoryRuntimeHash !==
+ constants.IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH
+ ) {
+ console.log(
+ " ✓ submitting inefficient immutable create2 factory deployment through" +
+ " initial create2 contract..."
+ );
+ await web3.eth.sendTransaction({
+ from: tester.originalAddress,
+ to: constants.KEYLESS_CREATE2_ADDRESS,
+ value: "0",
+ gas: testingContext !== "coverage" ? "608261" : tester.gasLimit - 1,
+ gasPrice: 1,
+ data: constants.IMMUTABLE_CREATE2_FACTORY_CREATION_CODE
+ });
+ tester.passed++;
+ } else {
+ console.log(
+ " ✓ inefficient immutable create2 factory contract already deployed, skipping..."
+ );
}
- let assertionsPassed
- try {
- assertionCallback(returnValues)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
+ let currentImmutableCreate2FactoryRuntimeHash;
+ await tester.runTest(
+ "Current runtime hash at address of immutable create2 factory can be retrieved",
+ tester.MockCodeCheck,
+ "hash",
+ "call",
+ [constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS],
+ true,
+ value => {
+ currentImmutableCreate2FactoryRuntimeHash = value;
+ }
+ );
- return assertionsPassed
- }
-
- async function deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let deployData = instance.deploy({arguments: args}).encodeABI()
- let deployGas = await web3.eth.estimateGas({
- from: from,
- data: deployData
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return gasLimit
- })
-
- if (deployGas > gasLimit) {
- console.error(` ✘ ${title}: deployment costs exceed block gas limit!`)
- process.exit(1)
+ // submit the immutable create2 deployment transaction if needed
+ if (
+ currentImmutableCreate2FactoryRuntimeHash !==
+ constants.IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH
+ ) {
+ await tester.runTest(
+ `submitting immutable create2 factory deployment through initial create2 contract...`,
+ InefficientImmutableCreate2Factory,
+ "safeCreate2",
+ "send",
+ [
+ constants.IMMUTABLE_CREATE2_FACTORY_SALT,
+ constants.IMMUTABLE_CREATE2_FACTORY_CREATION_CODE
+ ],
+ true
+ );
+ } else {
+ console.log(
+ " ✓ immutable create2 factory contract already deployed, skipping..."
+ );
}
- if (typeof(gas) === 'undefined') {
- gas = deployGas
- }
+ let currentIndestructibleRegistryRuntimeHash;
+ await tester.runTest(
+ "Current runtime hash at address of indestructible registry can be retrieved",
+ tester.MockCodeCheck,
+ "hash",
+ "call",
+ [constants.INDESTRUCTIBLE_REGISTRY_ADDRESS],
+ true,
+ value => {
+ currentIndestructibleRegistryRuntimeHash = value;
+ }
+ );
- if (deployGas > gas) {
- console.error(` ✘ ${title}: deployment costs exceed supplied gas.`)
- process.exit(1)
+ // submit the indestructible registry deployment transaction if needed
+ if (
+ currentIndestructibleRegistryRuntimeHash !==
+ constants.INDESTRUCTIBLE_REGISTRY_RUNTIME_HASH
+ ) {
+ console.log(
+ ` ✓ submitting indestructible registry deployment through immutable create2 contract...`
+ );
+ await web3.eth.sendTransaction({
+ from: tester.originalAddress,
+ to: constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS,
+ value: "0",
+ gas:
+ testingContext !== "coverage" ? "3000000" : tester.gasLimit - 1,
+ gasPrice: 1,
+ data: constants.INDESTRUCTIBLE_REGISTRY_CREATION_TX
+ });
+ tester.passed++;
+ } else {
+ console.log(
+ " ✓ indestructible registry contract already deployed, skipping..."
+ );
}
- let signed
- let deployHash
- let receipt
- const contract = await instance.deploy({arguments: args}).send({
- from: from,
- gas: gas,
- gasPrice: gasPrice
- }).on('transactionHash', hash => {
- deployHash = hash
- }).on('receipt', r => {
- receipt = r
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
-
- receipt = {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- if (contract) {
- return [false, contract, gas]
- }
- return [false, instance, gas]
- } else if (!shouldSucceed) {
- if (contract) {
- return [true, contract, gas]
- }
- return [true, instance, gas]
- }
+ // BEGIN ACTUAL DEPLOYMENT TESTS
- assert.ok(receipt.status)
+ await tester.runTest(
+ `DharmaUpgradeBeaconController contract deployment fails before other deployments`,
+ DharmaUpgradeBeaconControllerCoverageDeployer,
+ "",
+ "deploy",
+ [],
+ false
+ );
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- }
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contract deployment fails before other deployments`,
+ DharmaUpgradeBeaconControllerManagerCoverageDeployer,
+ "",
+ "deploy",
+ [],
+ false
+ );
- if (contract) {
- return [assertionsPassed, contract, gas]
- }
- return [assertionsPassed, instance, gas]
- }
-
- async function runTest(
- title,
- instance,
- method,
- callOrSend,
- args,
- shouldSucceed,
- assertionCallback,
- from,
- value,
- gas
- ) {
- if (typeof(callOrSend) === 'undefined') {
- callOrSend = 'send'
- }
- if (typeof(args) === 'undefined') {
- args = []
- }
- if (typeof(shouldSucceed) === 'undefined') {
- shouldSucceed = true
- }
- if (typeof(assertionCallback) === 'undefined') {
- assertionCallback = (value) => {}
- }
- if (typeof(from) === 'undefined') {
- from = address
- }
- if (typeof(value) === 'undefined') {
- value = 0
- }
- if (typeof(gas) === 'undefined' && callOrSend !== 'deploy') {
- gas = 6009006
- if (testingContext === 'coverage') {
- gas = gasLimit - 1
- }
- }
- let ok = false
- let contract
- let deployGas
- if (callOrSend === 'send') {
- ok = await send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'call') {
- ok = await call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'deploy') {
- const fields = await deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- ok = fields[0]
- contract = fields[1]
- deployGas = fields[2]
- } else {
- console.error('must use call, send, or deploy!')
- process.exit(1)
- }
+ // UpgradeBeaconEnvoy
+ await tester.checkAndDeploy(
+ "UpgradeBeaconEnvoy",
+ constants.UPGRADE_BEACON_ENVOY_ADDRESS,
+ constants.UPGRADE_BEACON_ENVOY_SALT,
+ constants.UPGRADE_BEACON_ENVOY_RUNTIME_CODE,
+ constants.UPGRADE_BEACON_ENVOY_CREATION_CODE,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (ok) {
- console.log(
- ` ✓ ${
- callOrSend === 'deploy' ? 'successful ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- passed++
- } else {
- console.log(
- ` ✘ ${
- callOrSend === 'deploy' ? 'failed ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- failed++
- }
+ // UpgradeBeaconController
+ const upgradeBeaconControllerRuntimeCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
+ constants.UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- if (contract) {
- return contract
- }
- }
+ const upgradeBeaconControllerCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.bytecode,
+ constants.UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- async function setupNewDefaultAddress(newPrivateKey) {
- const pubKey = await web3.eth.accounts.privateKeyToAccount(newPrivateKey)
- await web3.eth.accounts.wallet.add(pubKey)
+ await tester.checkAndDeploy(
+ "UpgradeBeaconController",
+ constants.UPGRADE_BEACON_CONTROLLER_ADDRESS,
+ constants.UPGRADE_BEACON_CONTROLLER_SALT,
+ upgradeBeaconControllerRuntimeCode,
+ upgradeBeaconControllerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: pubKey.address,
- value: 10 ** 18,
- gas: '0x5208',
- gasPrice: '0x4A817C800'
- })
-
- return pubKey.address
- }
-
- async function raiseGasLimit(necessaryGas) {
- iterations = 9999
- if (necessaryGas > 8000000) {
- console.error('the gas needed is too high!')
- process.exit(1)
- } else if (typeof necessaryGas === 'undefined') {
- iterations = 20
- necessaryGas = 8000000
- }
+ // KeyRingUpgradeBeaconController
+ const keyRingUpgradeBeaconControllerRuntimeCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- // bring up gas limit if necessary by doing additional transactions
- var block = await web3.eth.getBlock("latest")
- while (iterations > 0 && block.gasLimit < necessaryGas) {
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: originalAddress,
- value: '0x01',
- gas: '0x5208',
- gasPrice: '0x4A817C800'
- })
- var block = await web3.eth.getBlock("latest")
- iterations--
- }
+ const keyRingUpgradeBeaconControllerCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.bytecode,
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- console.log("raising gasLimit, currently at " + block.gasLimit)
- return block.gasLimit
- }
-
- async function getDeployGas(dataPayload) {
- await web3.eth.estimateGas({
- from: address,
- data: dataPayload
- }).catch(async error => {
- if (
- error.message === (
- 'Returned error: gas required exceeds allowance or always failing ' +
- 'transaction'
- )
- ) {
- await raiseGasLimit()
- await getDeployGas(dataPayload)
- }
- })
-
- deployGas = await web3.eth.estimateGas({
- from: address,
- data: dataPayload
- })
-
- return deployGas
- }
-
- function signHashedPrefixedHexString(hashedHexString, account) {
- const hashedPrefixedMessage = web3.utils.keccak256(
- // prefix => "\x19Ethereum Signed Message:\n32"
- "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
- hashedHexString.slice(2),
- {encoding: "hex"}
- )
+ await tester.checkAndDeploy(
+ "KeyRingUpgradeBeaconController",
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS,
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_SALT,
+ keyRingUpgradeBeaconControllerRuntimeCode,
+ keyRingUpgradeBeaconControllerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- const sig = util.ecsign(
- util.toBuffer(hashedPrefixedMessage),
- util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
- )
+ await tester.runTest(
+ `DharmaUpgradeBeaconController contract deployment`,
+ DharmaUpgradeBeaconControllerDeployer,
+ "",
+ "deploy"
+ );
- return (
- util.bufferToHex(sig.r) +
- util.bufferToHex(sig.s).slice(2) +
- web3.utils.toHex(sig.v).slice(2)
- )
- }
-
- function signHashedPrefixedHashedHexString(hexString, account) {
- const hashedPrefixedHashedMessage = web3.utils.keccak256(
- // prefix => "\x19Ethereum Signed Message:\n32"
- "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
- web3.utils.keccak256(hexString, {encoding: "hex"}).slice(2),
- {encoding: "hex"}
- )
+ await tester.runTest(
+ `failure when deploying UpgradeBeaconProxyV1 contract using an undeployed beacon`,
+ UpgradeBeaconProxyV1Deployer,
+ "",
+ "deploy",
+ ["0x"],
+ false
+ );
- const sig = util.ecsign(
- util.toBuffer(hashedPrefixedHashedMessage),
- util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
- )
+ // UpgradeBeacon
+ const upgradeBeaconRuntimeCode = swapMetadataHash(
+ DharmaUpgradeBeaconArtifact.deployedBytecode,
+ constants.UPGRADE_BEACON_METADATA
+ );
- return (
- util.bufferToHex(sig.r) +
- util.bufferToHex(sig.s).slice(2) +
- web3.utils.toHex(sig.v).slice(2)
- )
- }
+ const upgradeBeaconCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconArtifact.bytecode,
+ constants.UPGRADE_BEACON_METADATA
+ );
- // *************************** deploy contracts *************************** //
- let deployGas
- let selfAddress
-
- const MockCodeCheck = await runTest(
- `MockCodeCheck contract deployment`,
- MockCodeCheckDeployer,
- '',
- 'deploy'
- )
-
- await runTest(
- 'Deployed MockCodeCheck code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [MockCodeCheck.options.address],
- true,
- value => {
- assert.strictEqual(value, MockCodeCheckArtifact.deployedBytecode)
- }
- )
-
- await runTest(
- 'Deployed MockCodeCheck has correct extcodehash',
- MockCodeCheck,
- 'hash',
- 'call',
- [MockCodeCheck.options.address],
- true,
- value => {
- assert.strictEqual(
- value,
- web3.utils.keccak256(
- MockCodeCheckArtifact.deployedBytecode,
- {encoding: 'hex'}
- )
- )
- }
- )
-
- let currentKeylessCreate2Runtime;
- await runTest(
- 'Current runtime code at address of initial create2 factory can be retrieved',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEYLESS_CREATE2_ADDRESS],
- true,
- value => {
- currentKeylessCreate2Runtime = value
- }
- )
-
- // submit the initial create2 deployment transaction if needed
- if (currentKeylessCreate2Runtime !== constants.KEYLESS_CREATE2_RUNTIME_HASH) {
- console.log(' ✓ submitting initial create2 contract deployment transaction...')
- await web3.eth.sendSignedTransaction(
- constants.KEYLESS_CREATE2_DEPLOYMENT_TRANSACTION
- );
- passed++
-
- // deploy a mock code check contract using the initial create2 deployer
- console.log(' ✓ deploying test contract via create2 contract...')
- const DeploymentTx = await web3.eth.sendTransaction({
- from: originalAddress,
- to: constants.KEYLESS_CREATE2_ADDRESS,
- value: 0,
- gas: (testingContext !== 'coverage') ? 1500051 : gasLimit - 1,
- gasPrice: 1,
- data: MockCodeCheckArtifact.bytecode
- })
- passed++
- } else {
- console.log(' ✓ initial create2 contract already deployed, skipping...')
- }
-
- let currentInefficientImmutableCreate2FactoryRuntimeHash;
- await runTest(
- 'Current runtime hash at address of inefficient immutable create2 factory can be retrieved',
- MockCodeCheck,
- 'hash',
- 'call',
- [constants.INEFFICIENT_IMMUTABLE_CREATE2_FACTORY_ADDRESS],
- true,
- value => {
- currentInefficientImmutableCreate2FactoryRuntimeHash = value
- }
- )
-
- // submit the inefficient immutable create2 deployment transaction if needed
- if (currentInefficientImmutableCreate2FactoryRuntimeHash !== constants.IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH) {
- console.log(
- ' ✓ submitting inefficient immutable create2 factory deployment through' +
- ' initial create2 contract...'
- )
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: constants.KEYLESS_CREATE2_ADDRESS,
- value: '0',
- gas: (testingContext !== 'coverage') ? '608261' : gasLimit - 1,
- gasPrice: 1,
- data: constants.IMMUTABLE_CREATE2_FACTORY_CREATION_CODE
- });
- passed++
- } else {
- console.log(' ✓ inefficient immutable create2 factory contract already deployed, skipping...')
- }
-
- let currentImmutableCreate2FactoryRuntimeHash;
- await runTest(
- 'Current runtime hash at address of immutable create2 factory can be retrieved',
- MockCodeCheck,
- 'hash',
- 'call',
- [constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS],
- true,
- value => {
- currentImmutableCreate2FactoryRuntimeHash = value
- }
- )
-
- // submit the immutable create2 deployment transaction if needed
- if (currentImmutableCreate2FactoryRuntimeHash !== constants.IMMUTABLE_CREATE2_FACTORY_RUNTIME_HASH) {
- await runTest(
- `submitting immutable create2 factory deployment through initial create2 contract...`,
- InefficientImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.IMMUTABLE_CREATE2_FACTORY_SALT,
- constants.IMMUTABLE_CREATE2_FACTORY_CREATION_CODE
- ],
- true
- )
- } else {
- console.log(' ✓ immutable create2 factory contract already deployed, skipping...')
- }
-
- let currentIndestructibleRegistryRuntimeHash;
- await runTest(
- 'Current runtime hash at address of indestructible registry can be retrieved',
- MockCodeCheck,
- 'hash',
- 'call',
- [constants.INDESTRUCTIBLE_REGISTRY_ADDRESS],
- true,
- value => {
- currentIndestructibleRegistryRuntimeHash = value
- }
- )
-
- // submit the indestructible registry deployment transaction if needed
- if (currentIndestructibleRegistryRuntimeHash !== constants.INDESTRUCTIBLE_REGISTRY_RUNTIME_HASH) {
- console.log(` ✓ submitting indestructible registry deployment through immutable create2 contract...`)
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: constants.IMMUTABLE_CREATE2_FACTORY_ADDRESS,
- value: '0',
- gas: (testingContext !== 'coverage') ? '3000000' : gasLimit - 1,
- gasPrice: 1,
- data: constants.INDESTRUCTIBLE_REGISTRY_CREATION_TX
- });
- passed++
- } else {
- console.log(' ✓ indestructible registry contract already deployed, skipping...')
- }
-
- // BEGIN ACTUAL DEPLOYMENT TESTS
-
- await runTest(
- `DharmaUpgradeBeaconController contract deployment fails before other deployments`,
- DharmaUpgradeBeaconControllerCoverageDeployer,
- '',
- 'deploy',
- [],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract deployment fails before other deployments`,
- DharmaUpgradeBeaconControllerManagerCoverageDeployer,
- '',
- 'deploy',
- [],
- false
- )
-
- let currentUpgradeBeaconEnvoyCode;
- await runTest(
- 'Checking Upgrade Beacon Envoy runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_ENVOY_ADDRESS],
- true,
- value => {
- currentUpgradeBeaconEnvoyCode = value;
- }
- )
-
- if (
- currentUpgradeBeaconEnvoyCode !== constants.UPGRADE_BEACON_ENVOY_RUNTIME_CODE
- ) {
- await runTest(
- `UpgradeBeaconEnvoy contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.UPGRADE_BEACON_ENVOY_SALT,
- constants.UPGRADE_BEACON_ENVOY_CREATION_CODE
- ],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_ENVOY_ADDRESS)
- }
- )
-
- await runTest(
- `Upgrade Beacon Envoy contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.UPGRADE_BEACON_ENVOY_SALT,
- constants.UPGRADE_BEACON_ENVOY_CREATION_CODE
- ]
- )
- }
-
- await runTest(
- 'Deployed Upgrade Beacon Envoy code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_ENVOY_ADDRESS],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_ENVOY_RUNTIME_CODE)
- }
- )
-
- let currentUpgradeBeaconControllerCode;
- await runTest(
- 'Checking Upgrade Beacon Controller runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS],
- true,
- value => {
- currentUpgradeBeaconControllerCode = value;
- }
- )
-
- if (
- currentUpgradeBeaconControllerCode !== swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
- constants.UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ) {
- await runTest(
- `DharmaUpgradeBeaconController contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.UPGRADE_BEACON_CONTROLLER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.bytecode,
- constants.UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_CONTROLLER_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.UPGRADE_BEACON_CONTROLLER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.bytecode,
- constants.UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Upgrade Beacon Controller code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaUpgradeBeaconController.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
- constants.UPGRADE_BEACON_CONTROLLER_METADATA
- ))
- }
- )
-
- let currentKeyRingUpgradeBeaconControllerCode;
- await runTest(
- 'Checking Key Ring Upgrade Beacon Controller runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS],
- true,
- value => {
- currentKeyRingUpgradeBeaconControllerCode = value;
- }
- )
-
- if (
- currentKeyRingUpgradeBeaconControllerCode !== swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ) {
- await runTest(
- `DharmaKeyRingUpgradeBeaconController contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.bytecode,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaKeyRingUpgradeBeaconController contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.bytecode,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Key Ring Upgrade Beacon Controller code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaKeyRingUpgradeBeaconController.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_METADATA
- ))
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController contract deployment`,
- DharmaUpgradeBeaconControllerDeployer,
- '',
- 'deploy'
- )
-
- const FailedUpgradeBeaconProxy = await runTest(
- `failure when deploying UpgradeBeaconProxyV1 contract using an undeployed beacon`,
- UpgradeBeaconProxyV1Deployer,
- '',
- 'deploy',
- ["0x"],
- false
- )
-
- let currentUpgradeBeaconCode;
- await runTest(
- 'Checking Upgrade Beacon runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_ADDRESS],
- true,
- value => {
- currentUpgradeBeaconCode = value;
- }
- )
-
- if (
- currentUpgradeBeaconCode !== swapMetadataHash(
- DharmaUpgradeBeaconArtifact.deployedBytecode,
- constants.UPGRADE_BEACON_METADATA
- )
- ) {
- await runTest(
- `DharmaUpgradeBeacon contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.UPGRADE_BEACON_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconArtifact.bytecode,
- constants.UPGRADE_BEACON_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeacon contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
+ await tester.checkAndDeploy(
+ "UpgradeBeacon",
+ constants.UPGRADE_BEACON_ADDRESS,
constants.UPGRADE_BEACON_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconArtifact.bytecode,
- constants.UPGRADE_BEACON_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Upgrade Beacon code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- DharmaUpgradeBeaconArtifact.deployedBytecode,
- constants.UPGRADE_BEACON_METADATA
- ))
- }
- )
-
- await runTest(
- `DharmaUpgradeBeacon contract deployment`,
- DharmaUpgradeBeaconDeployer,
- '',
- 'deploy'
- )
-
- let currentKeyRingUpgradeBeaconCode;
- await runTest(
- 'Checking Upgrade Beacon runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEY_RING_UPGRADE_BEACON_ADDRESS],
- true,
- value => {
- currentKeyRingUpgradeBeaconCode = value;
- }
- )
+ upgradeBeaconRuntimeCode,
+ upgradeBeaconCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (
- currentKeyRingUpgradeBeaconCode !== swapMetadataHash(
- DharmaKeyRingUpgradeBeaconArtifact.deployedBytecode,
- constants.KEY_RING_UPGRADE_BEACON_METADATA
- )
- ) {
- await runTest(
- `DharmaKeyRingUpgradeBeacon contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.KEY_RING_UPGRADE_BEACON_SALT,
- swapMetadataHash(
- DharmaKeyRingUpgradeBeaconArtifact.bytecode,
- constants.KEY_RING_UPGRADE_BEACON_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_RING_UPGRADE_BEACON_ADDRESS)
- }
- )
+ await tester.runTest(
+ `DharmaUpgradeBeacon contract deployment`,
+ DharmaUpgradeBeaconDeployer,
+ "",
+ "deploy"
+ );
- await runTest(
- `DharmaUpgradeBeacon contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.KEY_RING_UPGRADE_BEACON_SALT,
- swapMetadataHash(
- DharmaKeyRingUpgradeBeaconArtifact.bytecode,
- constants.KEY_RING_UPGRADE_BEACON_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Key Ring Upgrade Beacon code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaKeyRingUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ // KeyRingUpgradeBeacon
+ const keyRingUpgradeBeaconRuntimeCode = swapMetadataHash(
DharmaKeyRingUpgradeBeaconArtifact.deployedBytecode,
constants.KEY_RING_UPGRADE_BEACON_METADATA
- ))
- }
- )
+ );
- await runTest(
- `DharmaKeyRingUpgradeBeacon contract deployment`,
- DharmaKeyRingUpgradeBeaconDeployer,
- '',
- 'deploy'
- )
+ const keyRingUpgradeBeaconCreationCode = swapMetadataHash(
+ DharmaKeyRingUpgradeBeaconArtifact.bytecode,
+ constants.KEY_RING_UPGRADE_BEACON_METADATA
+ );
- let currentKeyRegistryCode;
- await runTest(
- 'Checking Key Registry runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEY_REGISTRY_ADDRESS],
- true,
- value => {
- currentKeyRegistryCode = value;
- }
- )
+ await tester.checkAndDeploy(
+ "KeyRingUpgradeBeacon",
+ constants.KEY_RING_UPGRADE_BEACON_ADDRESS,
+ constants.KEY_RING_UPGRADE_BEACON_SALT,
+ keyRingUpgradeBeaconRuntimeCode,
+ keyRingUpgradeBeaconCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingUpgradeBeacon contract deployment`,
+ DharmaKeyRingUpgradeBeaconDeployer,
+ "",
+ "deploy"
+ );
- if (
- currentKeyRegistryCode !== swapMetadataHash(
+ // KeyRegistry
+ /*
+ const keyRegistryRuntimeCode = swapMetadataHash(
DharmaKeyRegistryV1Artifact.deployedBytecode,
constants.KEY_REGISTRY_METADATA
- )
- ) {
- await runTest(
- `DharmaKeyRegistryV1 Code contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.KEY_REGISTRY_SALT,
- swapMetadataHash(
- DharmaKeyRegistryV1Artifact.bytecode,
- constants.KEY_REGISTRY_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_REGISTRY_ADDRESS)
- }
- )
+ );
- await runTest(
- `DharmaKeyRegistryV1 contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.KEY_REGISTRY_SALT,
- swapMetadataHash(
- DharmaKeyRegistryV1Artifact.bytecode,
- constants.KEY_REGISTRY_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Key Registry code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaKeyRegistryV1.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- DharmaKeyRegistryV1Artifact.deployedBytecode,
- constants.KEY_REGISTRY_METADATA
- ))
- }
- )
+ const keyRegistryCreationCode = swapMetadataHash(
+ DharmaKeyRegistryV1Artifact.bytecode,
+ constants.KEY_REGISTRY_METADATA
+ );
+
+ await tester.checkAndDeploy(
+ "KeyRegistry",
+ constants.KEY_REGISTRY_ADDRESS,
+ constants.KEY_REGISTRY_SALT,
+ keyRegistryRuntimeCode,
+ keyRegistryCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
+ */
- let currentKeyRegistryV2Code;
- await runTest(
- 'Checking Key Registry V2 runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEY_REGISTRY_V2_ADDRESS],
- true,
- value => {
- currentKeyRegistryV2Code = value;
- }
- )
+ // KeyRegistryV2
+ const keyRegistryV2RuntimeCode = swapMetadataHash(
+ DharmaKeyRegistryV2Artifact.deployedBytecode,
+ constants.KEY_REGISTRY_V2_METADATA
+ );
- if (
- currentKeyRegistryV2Code !== swapMetadataHash(
- DharmaKeyRegistryV2Artifact.deployedBytecode,
- constants.KEY_REGISTRY_V2_METADATA
- )
- ) {
- await runTest(
- `DharmaKeyRegistryV2 Code contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.KEY_REGISTRY_V2_SALT,
- swapMetadataHash(
- DharmaKeyRegistryV2Artifact.bytecode,
- constants.KEY_REGISTRY_V2_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_REGISTRY_V2_ADDRESS)
- }
- )
+ const keyRegistryV2CreationCode = swapMetadataHash(
+ DharmaKeyRegistryV2Artifact.bytecode,
+ constants.KEY_REGISTRY_V2_METADATA
+ );
- await runTest(
- `DharmaKeyRegistryV2 contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
+ await tester.checkAndDeploy(
+ "KeyRegistryV2",
+ constants.KEY_REGISTRY_V2_ADDRESS,
constants.KEY_REGISTRY_V2_SALT,
- swapMetadataHash(
- DharmaKeyRegistryV2Artifact.bytecode,
- constants.KEY_REGISTRY_V2_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Key Registry code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaKeyRegistryV2.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- DharmaKeyRegistryV2Artifact.deployedBytecode,
- constants.KEY_REGISTRY_V2_METADATA
- ))
- }
- )
+ keyRegistryV2RuntimeCode,
+ keyRegistryV2CreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- let currentEscapeHatchRegistryCode;
- await runTest(
- 'Checking Escape Hatch Registry runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ESCAPE_HATCH_REGISTRY_ADDRESS],
- true,
- value => {
- currentEscapeHatchRegistryCode = value;
- }
- )
+ // RevertReasonHelper
+ const revertReasonHelperRuntimeCode = swapMetadataHash(
+ SmartWalletRevertReasonHelperV1Artifact.deployedBytecode,
+ constants.REVERT_REASON_HELPER_METADATA
+ );
- if (
- currentEscapeHatchRegistryCode !== swapMetadataHash(
- DharmaEscapeHatchRegistryArtifact.deployedBytecode,
- constants.ESCAPE_HATCH_REGISTRY_METADATA
- )
- ) {
- await runTest(
- `DharmaEscapeHatchRegistry Code contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.ESCAPE_HATCH_REGISTRY_SALT,
- swapMetadataHash(
- DharmaEscapeHatchRegistryArtifact.bytecode,
- constants.ESCAPE_HATCH_REGISTRY_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.ESCAPE_HATCH_REGISTRY_ADDRESS)
- }
- )
+ const revertReasonHelperCreationCode = swapMetadataHash(
+ SmartWalletRevertReasonHelperV1Artifact.bytecode,
+ constants.REVERT_REASON_HELPER_METADATA
+ );
- await runTest(
- `DharmaEscapeHatchRegistry contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.ESCAPE_HATCH_REGISTRY_SALT,
- swapMetadataHash(
- DharmaEscapeHatchRegistryArtifact.bytecode,
- constants.ESCAPE_HATCH_REGISTRY_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Escape Hatch Registry code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaEscapeHatchRegistry.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ await tester.checkAndDeploy(
+ "RevertReasonHelper",
+ constants.REVERT_REASON_HELPER_ADDRESS,
+ constants.NULL_BYTES_32,
+ revertReasonHelperRuntimeCode,
+ revertReasonHelperCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
+
+ // EscapeHatchRegistry
+ const escapeHatchRegistryRuntimeCode = swapMetadataHash(
DharmaEscapeHatchRegistryArtifact.deployedBytecode,
constants.ESCAPE_HATCH_REGISTRY_METADATA
- ))
- }
- )
+ );
+
+ const escapeHatchRegistryCreationCode = swapMetadataHash(
+ DharmaEscapeHatchRegistryArtifact.bytecode,
+ constants.ESCAPE_HATCH_REGISTRY_METADATA
+ );
+
+ await tester.checkAndDeploy(
+ "EscapeHatchRegistry",
+ constants.ESCAPE_HATCH_REGISTRY_ADDRESS,
+ constants.ESCAPE_HATCH_REGISTRY_SALT,
+ escapeHatchRegistryRuntimeCode,
+ escapeHatchRegistryCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- const DharmaSmartWalletImplementationV0 = await runTest(
+ // Dharma Smart Wallet Implementations
+ /*
+ const DharmaSmartWalletImplementationV0 = await tester.runTest(
`DharmaSmartWalletImplementationV0 contract deployment`,
DharmaSmartWalletImplementationV0Deployer,
'',
'deploy'
)
- const DharmaSmartWalletImplementationV1 = await runTest(
+ const DharmaSmartWalletImplementationV1 = await tester.runTest(
`DharmaSmartWalletImplementationV1 contract deployment`,
DharmaSmartWalletImplementationV1Deployer,
'',
'deploy'
)
- const DharmaSmartWalletImplementationV2 = await runTest(
+ const DharmaSmartWalletImplementationV2 = await tester.runTest(
`DharmaSmartWalletImplementationV2 contract deployment`,
DharmaSmartWalletImplementationV2Deployer,
'',
'deploy'
)
- /*
const DharmaSmartWalletImplementationV3 = await runTest(
`DharmaSmartWalletImplementationV3 contract deployment`,
DharmaSmartWalletImplementationV3Deployer,
@@ -1711,16 +915,30 @@ module.exports = {test: async function (provider, testingContext) {
'',
'deploy'
)
- */
- const DharmaSmartWalletImplementationV5 = await runTest(
+ const DharmaSmartWalletImplementationV5 = await tester.runTest(
`DharmaSmartWalletImplementationV5 contract deployment`,
DharmaSmartWalletImplementationV5Deployer,
'',
'deploy'
)
+ */
- /*
+ const DharmaSmartWalletImplementationV6 = await tester.runTest(
+ `DharmaSmartWalletImplementationV6 contract deployment`,
+ DharmaSmartWalletImplementationV6Deployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletImplementationV7 = await tester.runTest(
+ `DharmaSmartWalletImplementationV7 contract deployment`,
+ DharmaSmartWalletImplementationV7Deployer,
+ "",
+ "deploy"
+ );
+
+ /*
const DharmaKeyRingImplementationV0 = await runTest(
`DharmaKeyRingImplementationV0 contract deployment`,
DharmaKeyRingImplementationV0Deployer,
@@ -1729,14 +947,15 @@ module.exports = {test: async function (provider, testingContext) {
)
*/
- const DharmaKeyRingImplementationV1 = await runTest(
- `DharmaKeyRingImplementationV1 contract deployment`,
- DharmaKeyRingImplementationV1Deployer,
- '',
- 'deploy'
- )
+ // Dharma Key Ring Implementations
+ const DharmaKeyRingImplementationV1 = await tester.runTest(
+ `DharmaKeyRingImplementationV1 contract deployment`,
+ DharmaKeyRingImplementationV1Deployer,
+ "",
+ "deploy"
+ );
- /*
+ /*
const DharmaKeyRingImplementationV2 = await runTest(
`DharmaKeyRingImplementationV2 contract deployment`,
DharmaKeyRingImplementationV2Deployer,
@@ -1745,994 +964,547 @@ module.exports = {test: async function (provider, testingContext) {
)
*/
- let currentAccountRecoveryManagerCode;
- await runTest(
- 'Checking Account Recovery Manager runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS],
- true,
- value => {
- currentAccountRecoveryManagerCode = value;
- }
- )
-
- if (
- currentAccountRecoveryManagerCode !== swapMetadataHash(
- DharmaAccountRecoveryManagerV2Artifact.deployedBytecode,
- constants.ACCOUNT_RECOVERY_MANAGER_V2_METADATA
- )
- ) {
- await runTest(
- `DharmaAccountRecoveryManagerV2 contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.ACCOUNT_RECOVERY_MANAGER_V2_SALT,
- swapMetadataHash(
- DharmaAccountRecoveryManagerV2Artifact.bytecode,
- constants.ACCOUNT_RECOVERY_MANAGER_V2_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.ACCOUNT_RECOVERY_MANAGER_V2_SALT,
- swapMetadataHash(
- DharmaAccountRecoveryManagerV2Artifact.bytecode,
- constants.ACCOUNT_RECOVERY_MANAGER_V2_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed Account Recovery Manager code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaAccountRecoveryManagerV2.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ // AccountRecoveryManager
+ const accountRecoveryManagerRuntimeCode = swapMetadataHash(
DharmaAccountRecoveryManagerV2Artifact.deployedBytecode,
constants.ACCOUNT_RECOVERY_MANAGER_V2_METADATA
- ))
- }
- )
+ );
- await runTest(
- `DharmaAccountRecoveryManagerV2 contract deployment`,
- DharmaAccountRecoveryManagerV2Deployer,
- '',
- 'deploy'
- )
+ const accountRecoveryManagerCreationCode = swapMetadataHash(
+ DharmaAccountRecoveryManagerV2Artifact.bytecode,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_METADATA
+ );
- let currentFactoryCode;
- await runTest(
- 'Checking Factory runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.FACTORY_ADDRESS],
- true,
- value => {
- currentFactoryCode = value;
- }
- )
+ await tester.checkAndDeploy(
+ "AccountRecoveryManager",
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_SALT,
+ accountRecoveryManagerRuntimeCode,
+ accountRecoveryManagerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (
- currentFactoryCode !== swapMetadataHash(
- DharmaSmartWalletFactoryV1Artifact.deployedBytecode,
- constants.FACTORY_METADATA
- )
- ) {
- await runTest(
- `DharmaSmartWalletFactoryV1 Code contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.FACTORY_SALT,
- swapMetadataHash(
- DharmaSmartWalletFactoryV1Artifact.bytecode,
- constants.FACTORY_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.FACTORY_ADDRESS)
- }
- )
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 contract deployment`,
+ DharmaAccountRecoveryManagerV2Deployer,
+ "",
+ "deploy"
+ );
- await runTest(
- `DharmaSmartWalletFactoryV1 contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.FACTORY_SALT,
- swapMetadataHash(
- DharmaSmartWalletFactoryV1Artifact.bytecode,
- constants.FACTORY_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed FactoryV1 code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaSmartWalletFactoryV1.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ // DharmaSmartWalletFactory
+ const dharmaSmartWalletFactoryRuntimeCode = swapMetadataHash(
DharmaSmartWalletFactoryV1Artifact.deployedBytecode,
constants.FACTORY_METADATA
- ))
- }
- )
+ );
- await runTest(
- `DharmaSmartWalletFactoryV1 contract deployment`,
- DharmaSmartWalletFactoryV1Deployer,
- '',
- 'deploy',
- []
- )
+ const dharmaSmartWalletFactoryCreationCode = swapMetadataHash(
+ DharmaSmartWalletFactoryV1Artifact.bytecode,
+ constants.FACTORY_METADATA
+ );
- let currentKeyRingFactoryCode;
- await runTest(
- 'Checking Key Ring Factory runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.KEY_RING_FACTORY_V2_ADDRESS],
- true,
- value => {
- currentKeyRingFactoryCode = value;
- }
- )
+ await tester.checkAndDeploy(
+ "DharmaSmartWalletFactory",
+ constants.FACTORY_ADDRESS,
+ constants.FACTORY_SALT,
+ dharmaSmartWalletFactoryRuntimeCode,
+ dharmaSmartWalletFactoryCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (
- currentKeyRingFactoryCode !== swapMetadataHash(
- DharmaKeyRingFactoryV2Artifact.deployedBytecode,
- constants.KEY_RING_FACTORY_V2_METADATA
- )
- ) {
- await runTest(
- `DharmaKeyRingFactoryV2 Code contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.KEY_RING_FACTORY_V2_SALT,
- swapMetadataHash(
- DharmaKeyRingFactoryV2Artifact.bytecode,
- constants.KEY_RING_FACTORY_V2_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_RING_FACTORY_V2_ADDRESS)
- }
- )
+ await tester.runTest(
+ `DharmaSmartWalletFactoryV1 contract deployment`,
+ DharmaSmartWalletFactoryV1Deployer,
+ "",
+ "deploy",
+ []
+ );
- await runTest(
- `DharmaKeyRingFactoryV2 contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.KEY_RING_FACTORY_V2_SALT,
- swapMetadataHash(
- DharmaKeyRingFactoryV2Artifact.bytecode,
- constants.KEY_RING_FACTORY_V2_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed KeyRingFactoryV2 code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [DharmaKeyRingFactoryV2.options.address],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ // KeyRingFactory
+ const keyRingFactoryRuntimeCode = swapMetadataHash(
DharmaKeyRingFactoryV2Artifact.deployedBytecode,
constants.KEY_RING_FACTORY_V2_METADATA
- ))
- }
- )
+ );
- await runTest(
- `DharmaKeyRingFactoryV2 contract deployment`,
- DharmaKeyRingFactoryV2Deployer,
- '',
- 'deploy',
- []
- )
+ const keyRingFactoryCreationCode = swapMetadataHash(
+ DharmaKeyRingFactoryV2Artifact.bytecode,
+ constants.KEY_RING_FACTORY_V2_METADATA
+ );
- let currentAdharmaSmartWalletImplementationCode;
- await runTest(
- 'Checking Adharma smart wallet implementation runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS],
- true,
- value => {
- currentAdharmaSmartWalletImplementationCode = value;
- }
- )
+ await tester.checkAndDeploy(
+ "KeyRingFactory",
+ constants.KEY_RING_FACTORY_V2_ADDRESS,
+ constants.KEY_RING_FACTORY_V2_SALT,
+ keyRingFactoryRuntimeCode,
+ keyRingFactoryCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (
- currentAdharmaSmartWalletImplementationCode !== swapMetadataHash(
- AdharmaSmartWalletImplementationArtifact.deployedBytecode,
- constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA
- )
- ) {
- await runTest(
- `AdharmaSmartWalletImplementation contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_SALT,
- swapMetadataHash(
- AdharmaSmartWalletImplementationArtifact.bytecode,
- constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS)
- }
- )
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 contract deployment`,
+ DharmaKeyRingFactoryV2Deployer,
+ "",
+ "deploy",
+ []
+ );
- await runTest(
- `AdharmaSmartWalletImplementation contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_SALT,
- swapMetadataHash(
- AdharmaSmartWalletImplementationArtifact.bytecode,
- constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed AdharmaSmartWalletImplementation code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ // AdharmaSmartWalletImplementation
+ const adharmaSmartWalletImplementationRuntimeCode = swapMetadataHash(
AdharmaSmartWalletImplementationArtifact.deployedBytecode,
constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA
- ))
- }
- )
+ );
- await runTest(
- `AdharmaSmartWalletImplementation contract deployment`,
- AdharmaSmartWalletImplementationDeployer,
- '',
- 'deploy'
- )
+ const adharmaSmartWalletImplementationCreationCode = swapMetadataHash(
+ AdharmaSmartWalletImplementationArtifact.bytecode,
+ constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_METADATA
+ );
- let currentAdharmaKeyRingImplementationCode;
- await runTest(
- 'Checking Adharma key ring implementation runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS],
- true,
- value => {
- currentAdharmaKeyRingImplementationCode = value;
- }
- )
+ await tester.checkAndDeploy(
+ "AdharmaSmartWalletImplementation",
+ constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS,
+ constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_SALT,
+ adharmaSmartWalletImplementationRuntimeCode,
+ adharmaSmartWalletImplementationCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- if (
- currentAdharmaKeyRingImplementationCode !== swapMetadataHash(
- AdharmaKeyRingImplementationArtifact.deployedBytecode,
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
- )
- ) {
- await runTest(
- `AdharmaKeyRingImplementation contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_SALT,
- swapMetadataHash(
- AdharmaKeyRingImplementationArtifact.bytecode,
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS)
- }
- )
+ // DharmaDaiUpgrageBeaconController
+ const dharmaDaiUpgradeBeaconControllerRuntimeCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
+ constants.DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- await runTest(
- `AdharmaKeyRingImplementation contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_SALT,
- swapMetadataHash(
- AdharmaKeyRingImplementationArtifact.bytecode,
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed AdharmaSmartWalletImplementation code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
- AdharmaKeyRingImplementationArtifact.deployedBytecode,
- constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
- ))
- }
- )
+ const dharmaDaiUpgradeBeaconControllerCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.bytecode,
+ constants.DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- await runTest(
- `AdharmaKeyRingImplementation contract deployment`,
- AdharmaKeyRingImplementationDeployer,
- '',
- 'deploy'
- )
+ await tester.checkAndDeploy(
+ "DharmaDaiUpgrageBeaconController",
+ constants.DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_ADDRESS,
+ constants.DHARMA_DAI_UPGRADE_BEACON_CONTROLLER_SALT,
+ dharmaDaiUpgradeBeaconControllerRuntimeCode,
+ dharmaDaiUpgradeBeaconControllerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- `DharmaAccountRecoveryMultisig contract deployment fails if threshold is not met`,
- DharmaAccountRecoveryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ // DharmaUSDCUpgrageBeaconController
+ const dharmaUSDCUpgradeBeaconControllerRuntimeCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.deployedBytecode,
+ constants.DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- await runTest(
- `DharmaAccountRecoveryMultisig contract deployment fails if sigs are out of order`,
- DharmaAccountRecoveryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ const dharmaUSDCUpgradeBeaconControllerCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerArtifact.bytecode,
+ constants.DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_METADATA
+ );
- await runTest(
- `DharmaAccountRecoveryMultisig contract deployment fails with too many owners`,
- DharmaAccountRecoveryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000006',
- '0x0000000000000000000000000000000000000007',
- '0x0000000000000000000000000000000000000008',
- '0x0000000000000000000000000000000000000009',
- '0x000000000000000000000000000000000000000a',
- '0x000000000000000000000000000000000000000b'
- ]],
- false
- )
+ await tester.checkAndDeploy(
+ "DharmaUSDCUpgrageBeaconController",
+ constants.DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_ADDRESS,
+ constants.DHARMA_USDC_UPGRADE_BEACON_CONTROLLER_SALT,
+ dharmaUSDCUpgradeBeaconControllerRuntimeCode,
+ dharmaUSDCUpgradeBeaconControllerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig contract deployment fails if threshold is not met`,
- DharmaAccountRecoveryOperatorMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ // DharmaUSDCUpgrageBeacon
+ const dharmaDaiUpgradeBeaconRuntimeCode = swapMetadataHash(
+ DharmaDaiUpgradeBeaconArtifact.deployedBytecode,
+ constants.DHARMA_DAI_UPGRADE_BEACON_METADATA
+ );
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig contract deployment fails if sigs are out of order`,
- DharmaAccountRecoveryOperatorMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ const dharmaDaiUpgradeBeaconCreationCode = swapMetadataHash(
+ DharmaDaiUpgradeBeaconArtifact.bytecode,
+ constants.DHARMA_DAI_UPGRADE_BEACON_METADATA
+ );
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig contract deployment fails with too many owners`,
- DharmaAccountRecoveryOperatorMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000006',
- '0x0000000000000000000000000000000000000007',
- '0x0000000000000000000000000000000000000008',
- '0x0000000000000000000000000000000000000009',
- '0x000000000000000000000000000000000000000a',
- '0x000000000000000000000000000000000000000b'
- ]],
- false
- )
+ await tester.checkAndDeploy(
+ "DharmaDaiUpgrageBeacon",
+ constants.DHARMA_DAI_UPGRADE_BEACON_ADDRESS,
+ constants.DHARMA_DAI_UPGRADE_BEACON_SALT,
+ dharmaDaiUpgradeBeaconRuntimeCode,
+ dharmaDaiUpgradeBeaconCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- const DharmaAccountRecoveryMultisig = await runTest(
- `DharmaAccountRecoveryMultisig contract deployment`,
- DharmaAccountRecoveryMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour]]
- )
+ // DharmaUSDCUpgrageBeacon
+ const dharmaUSDCUpgradeBeaconRuntimeCode = swapMetadataHash(
+ DharmaUSDCUpgradeBeaconArtifact.deployedBytecode,
+ constants.DHARMA_USDC_UPGRADE_BEACON_METADATA
+ );
- await runTest(
- `DharmaKeyRegistryMultisig contract deployment fails if threshold is not met`,
- DharmaKeyRegistryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ const dharmaUSDCUpgradeBeaconCreationCode = swapMetadataHash(
+ DharmaUSDCUpgradeBeaconArtifact.bytecode,
+ constants.DHARMA_USDC_UPGRADE_BEACON_METADATA
+ );
- await runTest(
- `DharmaKeyRegistryMultisig contract deployment fails if sigs are out of order`,
- DharmaKeyRegistryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ await tester.checkAndDeploy(
+ "DharmaUSDCUpgrageBeacon",
+ constants.DHARMA_USDC_UPGRADE_BEACON_ADDRESS,
+ constants.DHARMA_USDC_UPGRADE_BEACON_SALT,
+ dharmaUSDCUpgradeBeaconRuntimeCode,
+ dharmaUSDCUpgradeBeaconCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- `DharmaKeyRegistryMultisig contract deployment fails with too many owners`,
- DharmaKeyRegistryMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000006',
- '0x0000000000000000000000000000000000000007',
- '0x0000000000000000000000000000000000000008',
- '0x0000000000000000000000000000000000000009',
- '0x000000000000000000000000000000000000000a',
- '0x000000000000000000000000000000000000000b'
- ]],
- false
- )
+ // DharmaDai
+ const dharmaDaiRuntimeCode = swapMetadataHash(
+ DharmaDaiArtifact.deployedBytecode,
+ constants.DHARMA_DAI_METADATA
+ );
- const DharmaKeyRegistryMultisig = await runTest(
- `DharmaKeyRegistryMultisig contract deployment`,
- DharmaKeyRegistryMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]]
- )
+ const dharmaDaiCreationCode = swapMetadataHash(
+ DharmaDaiArtifact.bytecode,
+ constants.DHARMA_DAI_METADATA
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract deployment fails before indestructible registration`,
- DharmaUpgradeBeaconControllerManagerCoverageDeployer,
- '',
- 'deploy',
- [],
- false
- )
+ await tester.checkAndDeploy(
+ "DharmaDai",
+ constants.DHARMA_DAI_ADDRESS,
+ constants.DHARMA_DAI_SALT,
+ dharmaDaiRuntimeCode,
+ dharmaDaiCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- const IndestructibleRegistry = await runTest(
- `IndestructibleRegistry contract deployment`,
- IndestructibleRegistryDeployer,
- '',
- 'deploy'
- )
+ // DharmaUSDC
+ const dharmaUSDCRuntimeCode = swapMetadataHash(
+ DharmaUSDCArtifact.deployedBytecode,
+ constants.DHARMA_USDC_METADATA
+ );
- await runTest(
- 'IndestructibleRegistry can register itself as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [IndestructibleRegistry.options.address]
- )
+ const dharmaUSDCCreationCode = swapMetadataHash(
+ DharmaUSDCArtifact.bytecode,
+ constants.DHARMA_USDC_METADATA
+ );
- await runTest(
- 'IndestructibleRegistry can register the upgrade beacon as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS]
- )
-
- await runTest(
- 'IndestructibleRegistry can register the upgrade beacon controller as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS]
- )
+ await tester.checkAndDeploy(
+ "DharmaDai",
+ constants.DHARMA_USDC_ADDRESS,
+ constants.DHARMA_USDC_SALT,
+ dharmaUSDCRuntimeCode,
+ dharmaUSDCCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- 'IndestructibleRegistry can register the key ring upgrade beacon as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_RING_UPGRADE_BEACON_ADDRESS]
- )
-
- await runTest(
- 'IndestructibleRegistry can register the key ring upgrade beacon controller as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS]
- )
+ const DharmaDaiInitializerImplementation = await tester.runTest(
+ `DharmaDaiInitializer contract deployment`,
+ DharmaDaiInitializerDeployer,
+ "",
+ "deploy"
+ );
- await runTest(
- 'IndestructibleRegistry can register the upgrade beacon envoy as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_ENVOY_ADDRESS]
- )
-
- await runTest(
- 'IndestructibleRegistry can register the account recovery manager as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS]
- )
+ const DharmaUSDCInitializerImplementation = await tester.runTest(
+ `DharmaUSDCInitializer contract deployment`,
+ DharmaUSDCInitializerDeployer,
+ "",
+ "deploy"
+ );
- await runTest(
- 'IndestructibleRegistry can register DharmaKeyRegistryV1 as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_REGISTRY_ADDRESS]
- )
+ const DharmaDaiImplementationV1 = await tester.runTest(
+ `DharmaDaiImplementationV1 contract deployment`,
+ DharmaDaiImplementationV1Deployer,
+ "",
+ "deploy"
+ );
- await runTest(
- 'IndestructibleRegistry can register DharmaKeyRegistryV2 as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_REGISTRY_V2_ADDRESS]
- )
+ const DharmaUSDCImplementationV1 = await tester.runTest(
+ `DharmaUSDCImplementationV1 contract deployment`,
+ DharmaUSDCImplementationV1Deployer,
+ "",
+ "deploy"
+ );
- await runTest(
- 'IndestructibleRegistry can register DharmaEscapeHatchRegistry as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ESCAPE_HATCH_REGISTRY_ADDRESS]
- )
+ await tester.runTest(
+ "DharmaDaiUpgradeBeaconController can set initializer implementation",
+ DharmaDaiUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ constants.DHARMA_DAI_UPGRADE_BEACON_ADDRESS,
+ DharmaDaiInitializerImplementation.options.address
+ ]
+ );
- await runTest(
- 'WARNING: IndestructibleRegistry CANNOT register the smart wallet factory as indestructible (even though it is in fact NOT destructible)',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.FACTORY_ADDRESS],
- false
- )
+ await tester.runTest(
+ "DharmaDai can be initialized",
+ DharmaDaiInitializer,
+ "initialize"
+ );
- await runTest(
- 'IndestructibleRegistry can register the Adharma smart wallet implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS]
- )
+ await tester.runTest(
+ "DharmaDaiUpgradeBeaconController can set implementation V1",
+ DharmaDaiUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ constants.DHARMA_DAI_UPGRADE_BEACON_ADDRESS,
+ DharmaDaiImplementationV1.options.address
+ ]
+ );
- await runTest(
- 'IndestructibleRegistry can register the Adharma key ring implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS]
- )
+ await tester.runTest(
+ "DharmaUSDCUpgradeBeaconController can set initializer implementation",
+ DharmaUSDCUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ constants.DHARMA_USDC_UPGRADE_BEACON_ADDRESS,
+ DharmaUSDCInitializerImplementation.options.address
+ ]
+ );
- await runTest(
- 'IndestructibleRegistry can register V0 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV0.options.address]
- )
+ await tester.runTest(
+ "DharmaUSDC can be initialized",
+ DharmaUSDCInitializer,
+ "initialize"
+ );
- /*
- await runTest(
- 'IndestructibleRegistry can register V0 key ring implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaKeyRingImplementationV0.options.address]
- )
- */
+ await tester.runTest(
+ "DharmaUSDCUpgradeBeaconController can set implementation V1",
+ DharmaUSDCUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ constants.DHARMA_USDC_UPGRADE_BEACON_ADDRESS,
+ DharmaUSDCImplementationV1.options.address
+ ]
+ );
- await runTest(
- 'IndestructibleRegistry can register V1 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV1.options.address]
- )
+ await tester.runTest(
+ `AdharmaSmartWalletImplementation contract deployment`,
+ AdharmaSmartWalletImplementationDeployer,
+ "",
+ "deploy"
+ );
- if (testingContext !== 'coverage') {
- await runTest(
- 'IndestructibleRegistry can register V2 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV2.options.address]
- )
+ // ADharmaKeyRingImplementation
+ const adharmaKeyRingImplementationRuntimeCode = swapMetadataHash(
+ AdharmaKeyRingImplementationArtifact.deployedBytecode,
+ constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
+ );
- /*
- await runTest(
- 'IndestructibleRegistry can register V3 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV3.options.address]
- )
+ const adharmaKeyRingImplementationCreationCode = swapMetadataHash(
+ AdharmaKeyRingImplementationArtifact.bytecode,
+ constants.ADHARMA_KEY_RING_IMPLEMENTATION_METADATA
+ );
- await runTest(
- 'IndestructibleRegistry can register V4 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV4.options.address]
- )
- */
+ await tester.checkAndDeploy(
+ "DharmaDai",
+ constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS,
+ constants.ADHARMA_KEY_RING_IMPLEMENTATION_SALT,
+ adharmaKeyRingImplementationRuntimeCode,
+ adharmaKeyRingImplementationCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- 'IndestructibleRegistry can register V5 implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaSmartWalletImplementationV5.options.address]
- )
+ await tester.runTest(
+ `AdharmaKeyRingImplementation contract deployment`,
+ AdharmaKeyRingImplementationDeployer,
+ "",
+ "deploy"
+ );
- await runTest(
- 'IndestructibleRegistry can register V1 key ring implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaKeyRingImplementationV1.options.address]
- )
- }
-
- /*
- await runTest(
- 'IndestructibleRegistry can register V2 key ring implementation as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [DharmaKeyRingImplementationV2.options.address]
- )
- */
+ await testDharmaAccountRecoveryMultisigDeployer(
+ tester,
+ DharmaAccountRecoveryMultisigDeployer
+ );
- await runTest(
- '"actual" IndestructibleRegistry can register the upgrade beacon as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS]
- )
-
- await runTest(
- '"actual" IndestructibleRegistry can register the upgrade beacon controller as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS]
- )
+ await testDharmaAccountRecoveryOperatorMultisigDeployer(
+ tester,
+ DharmaAccountRecoveryOperatorMultisigDeployer
+ );
- await runTest(
- '"actual" IndestructibleRegistry can register the key ring upgrade beacon as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_RING_UPGRADE_BEACON_ADDRESS]
- )
-
- await runTest(
- '"actual" IndestructibleRegistry can register the key ring upgrade beacon controller as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS]
- )
+ await testDharmaKeyRegistryMultisigDeployer(
+ tester,
+ DharmaKeyRegistryMultisigDeployer
+ );
- await runTest(
- '"actual" IndestructibleRegistry can register the Adharma smart wallet implementation as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS]
- )
+ //
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contract deployment fails before indestructible registration`,
+ DharmaUpgradeBeaconControllerManagerCoverageDeployer,
+ "",
+ "deploy",
+ [],
+ false
+ );
- await runTest(
- '"actual" IndestructibleRegistry can register the Adharma key ring implementation as indestructible',
- ActualIndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS]
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the upgrade beacon as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_ADDRESS]
+ );
- const CodeHashCache = await runTest(
- `CodeHashCache contract deployment`,
- CodeHashCacheDeployer,
- '',
- 'deploy'
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the upgrade beacon controller as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS]
+ );
- await runTest(
- 'IndestructibleRegistry can register codehashcache as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [CodeHashCache.options.address]
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the key ring upgrade beacon as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.KEY_RING_UPGRADE_BEACON_ADDRESS]
+ );
- await runTest(
- 'CodeHashCache can register the runtime code hash of the smart wallet factory',
- CodeHashCache,
- 'registerCodeHash',
- 'send',
- [constants.FACTORY_ADDRESS]
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the key ring upgrade beacon controller as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS]
+ );
- let currentUpgradeBeaconControllerManagerCode;
- await runTest(
- 'Checking Upgrade Beacon Controller Manager runtime code',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS],
- true,
- value => {
- currentUpgradeBeaconControllerManagerCode = value;
- }
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the Adharma smart wallet implementation as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ADHARMA_SMART_WALLET_IMPLEMENTATION_ADDRESS]
+ );
- if (
- currentUpgradeBeaconControllerManagerCode !== swapMetadataHash(
- DharmaUpgradeBeaconControllerManagerArtifact.deployedBytecode,
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA
- )
- ) {
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract address check through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'findCreate2Address',
- 'call',
- [
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerManagerArtifact.bytecode,
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA
- )
- ],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS)
- }
- )
+ await tester.runTest(
+ '"actual" IndestructibleRegistry can register the Adharma key ring implementation as indestructible',
+ ActualIndestructibleRegistry,
+ "registerAsIndestructible",
+ "send",
+ [constants.ADHARMA_KEY_RING_IMPLEMENTATION_ADDRESS]
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract deployment through immutable create2 factory`,
- ImmutableCreate2Factory,
- 'safeCreate2',
- 'send',
- [
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_SALT,
- swapMetadataHash(
- DharmaUpgradeBeaconControllerManagerArtifact.bytecode,
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA
- )
- ]
- )
- }
-
- await runTest(
- 'Deployed DharmaUpgradeBeaconControllerManager code is correct',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS],
- true,
- value => {
- assert.strictEqual(value, swapMetadataHash(
+ const CodeHashCache = await tester.runTest(
+ `CodeHashCache contract deployment`,
+ CodeHashCacheDeployer,
+ "",
+ "deploy"
+ );
+
+ await tester.runTest(
+ "CodeHashCache can register the runtime code hash of the smart wallet factory",
+ CodeHashCache,
+ "registerCodeHash",
+ "send",
+ [constants.FACTORY_ADDRESS]
+ );
+
+ // UpgradeBeaconControllerManager
+ const upgradeBeaconControllerManagerRuntimeCode = swapMetadataHash(
DharmaUpgradeBeaconControllerManagerArtifact.deployedBytecode,
constants.UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA
- ))
- }
- )
+ );
- await runTest(
- 'IndestructibleRegistry can register the upgrade beacon controller manager as indestructible',
- IndestructibleRegistry,
- 'registerAsIndestructible',
- 'send',
- [constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS]
- )
+ const upgradeBeaconControllerManagerCreationCode = swapMetadataHash(
+ DharmaUpgradeBeaconControllerManagerArtifact.bytecode,
+ constants.UPGRADE_BEACON_CONTROLLER_MANAGER_METADATA
+ );
- await runTest(
- `DharmaUpgradeMultisig contract deployment fails if threshold is not met`,
- DharmaUpgradeMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ await tester.checkAndDeploy(
+ "UpgradeBeaconControllerManager",
+ constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS,
+ constants.UPGRADE_BEACON_CONTROLLER_MANAGER_SALT,
+ upgradeBeaconControllerManagerRuntimeCode,
+ upgradeBeaconControllerManagerCreationCode,
+ tester.MockCodeCheck,
+ ImmutableCreate2Factory
+ );
- await runTest(
- `DharmaUpgradeMultisig contract deployment fails if sigs are out of order`,
- DharmaUpgradeMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000001'
- ]],
- false
- )
+ const testIndestructibleRegistryContracts = {
+ DharmaSmartWalletImplementationV6,
+ DharmaSmartWalletImplementationV7,
+ DharmaKeyRingImplementationV1
+ };
- await runTest(
- `DharmaUpgradeMultisig contract deployment fails with too many owners`,
- DharmaUpgradeMultisigDeployer,
- '',
- 'deploy',
- [[
- '0x0000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000002',
- '0x0000000000000000000000000000000000000003',
- '0x0000000000000000000000000000000000000004',
- '0x0000000000000000000000000000000000000005',
- '0x0000000000000000000000000000000000000006',
- '0x0000000000000000000000000000000000000007',
- '0x0000000000000000000000000000000000000008',
- '0x0000000000000000000000000000000000000009',
- '0x000000000000000000000000000000000000000a',
- '0x000000000000000000000000000000000000000b'
- ]],
- false
- )
+ await testIndestructibleRegistry(
+ tester,
+ testIndestructibleRegistryContracts
+ );
- const DharmaUpgradeMultisig = await runTest(
- `DharmaUpgradeMultisig contract deployment`,
- DharmaUpgradeMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]]
- )
+ await testDharmaUpgradeMultisigDeployer(
+ tester,
+ DharmaUpgradeMultisigDeployer
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract deployment`,
- DharmaUpgradeBeaconControllerManagerDeployer,
- '',
- 'deploy'
- )
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contract deployment`,
+ DharmaUpgradeBeaconControllerManagerDeployer,
+ "",
+ "deploy"
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contract coverage deployment`,
- DharmaUpgradeBeaconControllerManagerCoverageDeployer,
- '',
- 'deploy'
- )
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contract coverage deployment`,
+ DharmaUpgradeBeaconControllerManagerCoverageDeployer,
+ "",
+ "deploy"
+ );
- let currentSaiCode;
- await runTest(
- 'Checking for required external contracts...',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.SAI_MAINNET_ADDRESS],
- true,
- value => {
- currentSaiCode = value;
- }
- )
+ let currentSaiCode;
+ await tester.runTest(
+ "Checking for required external contracts...",
+ tester.MockCodeCheck,
+ "code",
+ "call",
+ [constants.SAI_MAINNET_ADDRESS],
+ true,
+ value => {
+ currentSaiCode = value;
+ }
+ );
- if (!currentSaiCode) {
- console.log(
- `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` +
- `with ${failed} failure${failed === 1 ? '' : 's'}.`
- )
+ if (!currentSaiCode) {
+ console.log(
+ `completed ${tester.passed + tester.failed} test${
+ tester.passed + tester.failed === 1 ? "" : "s"
+ } ` +
+ `with ${tester.failed} failure${
+ tester.failed === 1 ? "" : "s"
+ }.`
+ );
+
+ console.log(
+ "Note that the full test suite cannot be executed locally - instead, " +
+ "run against a fork of mainnet using `yarn forkStart` and `yarn test`."
+ );
+
+ if (tester.failed > 0) {
+ process.exit(1);
+ }
+
+ // exit.
+ return 0;
+ }
console.log(
- 'Note that the full test suite cannot be executed locally - instead, ' +
- 'run against a fork of mainnet using `yarn forkStart` and `yarn test`.'
- )
+ `completed ${tester.passed + tester.failed} test${
+ tester.passed + tester.failed === 1 ? "" : "s"
+ } ` + `with ${tester.failed} failure${tester.failed === 1 ? "" : "s"}.`
+ );
- if (failed > 0) {
- process.exit(1)
+ if (tester.failed > 0) {
+ process.exit(1);
}
// exit.
- return 0
- }
-
-
- console.log(
- `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` +
- `with ${failed} failure${failed === 1 ? '' : 's'}.`
- )
-
- if (failed > 0) {
- process.exit(1)
- }
-
- // exit.
- return 0
+ return 0;
+}
-}}
+module.exports = {
+ test
+};
diff --git a/scripts/test/deployMockExternal.js b/scripts/test/deployMockExternal.js
index ed02cba..35dd357 100644
--- a/scripts/test/deployMockExternal.js
+++ b/scripts/test/deployMockExternal.js
@@ -1,5267 +1,5185 @@
-var assert = require('assert')
-var fs = require('fs')
-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
- let passed = 0
- let failed = 0
- 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
- )
-
- 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(
- 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(
- [
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "pendingAdmin",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newPendingAdmin",
- "type": "address"
- }
- ],
- "name": "_setPendingAdmin",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "comptrollerImplementation",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
-
- ],
- "name": "_acceptImplementation",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "pendingComptrollerImplementation",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newPendingImplementation",
- "type": "address"
- }
- ],
- "name": "_setPendingImplementation",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
-
- ],
- "name": "_acceptAdmin",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "admin",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "constructor"
- },
- {
- "payable": true,
- "stateMutability": "payable",
- "type": "fallback"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldPendingImplementation",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newPendingImplementation",
- "type": "address"
- }
- ],
- "name": "NewPendingImplementation",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldImplementation",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newImplementation",
- "type": "address"
- }
- ],
- "name": "NewImplementation",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldPendingAdmin",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newPendingAdmin",
- "type": "address"
- }
- ],
- "name": "NewPendingAdmin",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldAdmin",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newAdmin",
- "type": "address"
- }
- ],
- "name": "NewAdmin",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "error",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "info",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "detail",
- "type": "uint256"
- }
- ],
- "name": "Failure",
- "type": "event"
- }
- ],
- constants.COMPTROLLER_MAINNET_ADDRESS
- )
-
- const FIAT_TOKEN = new web3.eth.Contract(
- [
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "name",
- "outputs": [
- {
- "name": "",
- "type": "string"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_spender",
- "type": "address"
- },
- {
- "name": "_value",
- "type": "uint256"
- }
- ],
- "name": "approve",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "totalSupply",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "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": "_from",
- "type": "address"
- },
- {
- "name": "_to",
- "type": "address"
- },
- {
- "name": "_value",
- "type": "uint256"
- }
- ],
- "name": "transferFrom",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "minter",
- "type": "address"
- }
- ],
- "name": "removeMinter",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "decimals",
- "outputs": [
- {
- "name": "",
- "type": "uint8"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_name",
- "type": "string"
- },
- {
- "name": "_symbol",
- "type": "string"
- },
- {
- "name": "_currency",
- "type": "string"
- },
- {
- "name": "_decimals",
- "type": "uint8"
- },
- {
- "name": "_masterMinter",
- "type": "address"
- },
- {
- "name": "_pauser",
- "type": "address"
- },
- {
- "name": "_blacklister",
- "type": "address"
- },
- {
- "name": "_owner",
- "type": "address"
- }
- ],
- "name": "initialize",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "masterMinter",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
-
- ],
- "name": "unpause",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_to",
- "type": "address"
- },
- {
- "name": "_amount",
- "type": "uint256"
- }
- ],
- "name": "mint",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_amount",
- "type": "uint256"
- }
- ],
- "name": "burn",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "minter",
- "type": "address"
- },
- {
- "name": "minterAllowedAmount",
- "type": "uint256"
- }
- ],
- "name": "configureMinter",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_newPauser",
- "type": "address"
- }
- ],
- "name": "updatePauser",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "paused",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "account",
- "type": "address"
- }
- ],
- "name": "balanceOf",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
-
- ],
- "name": "pause",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "minter",
- "type": "address"
- }
- ],
- "name": "minterAllowance",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "owner",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "symbol",
- "outputs": [
- {
- "name": "",
- "type": "string"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "pauser",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_to",
- "type": "address"
- },
- {
- "name": "_value",
- "type": "uint256"
- }
- ],
- "name": "transfer",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_newMasterMinter",
- "type": "address"
- }
- ],
- "name": "updateMasterMinter",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "account",
- "type": "address"
- }
- ],
- "name": "isMinter",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "_newBlacklister",
- "type": "address"
- }
- ],
- "name": "updateBlacklister",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "blacklister",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "owner",
- "type": "address"
- },
- {
- "name": "spender",
- "type": "address"
- }
- ],
- "name": "allowance",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "currency",
- "outputs": [
- {
- "name": "",
- "type": "string"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newOwner",
- "type": "address"
- }
- ],
- "name": "transferOwnership",
- "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"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "minter",
- "type": "address"
- },
- {
- "indexed": true,
- "name": "to",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "amount",
- "type": "uint256"
- }
- ],
- "name": "Mint",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "burner",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "amount",
- "type": "uint256"
- }
- ],
- "name": "Burn",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "minter",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "minterAllowedAmount",
- "type": "uint256"
- }
- ],
- "name": "MinterConfigured",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "oldMinter",
- "type": "address"
- }
- ],
- "name": "MinterRemoved",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "newMasterMinter",
- "type": "address"
- }
- ],
- "name": "MasterMinterChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "_account",
- "type": "address"
- }
- ],
- "name": "Blacklisted",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "_account",
- "type": "address"
- }
- ],
- "name": "UnBlacklisted",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "newBlacklister",
- "type": "address"
- }
- ],
- "name": "BlacklisterChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
-
- ],
- "name": "Pause",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
-
- ],
- "name": "Unpause",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "newAddress",
- "type": "address"
- }
- ],
- "name": "PauserChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "name": "spender",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "previousOwner",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newOwner",
- "type": "address"
- }
- ],
- "name": "OwnershipTransferred",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "name": "to",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- }
- ],
- constants.USDC_MAINNET_ADDRESS
- )
-
- const COMPTROLLER_ABI = [
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "isComptroller",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "payer",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "repayAmount",
- "type": "uint256"
- },
- {
- "name": "borrowerIndex",
- "type": "uint256"
- }
- ],
- "name": "repayBorrowVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "payer",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "repayAmount",
- "type": "uint256"
- }
- ],
- "name": "repayBorrowAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "pendingAdmin",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newCloseFactorMantissa",
- "type": "uint256"
- }
- ],
- "name": "_setCloseFactor",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "unitroller",
- "type": "address"
- },
- {
- "name": "_oracle",
- "type": "address"
- },
- {
- "name": "_closeFactorMantissa",
- "type": "uint256"
- },
- {
- "name": "_maxAssets",
- "type": "uint256"
- },
- {
- "name": "reinitializing",
- "type": "bool"
- }
- ],
- "name": "_become",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "minter",
- "type": "address"
- },
- {
- "name": "mintAmount",
- "type": "uint256"
- },
- {
- "name": "mintTokens",
- "type": "uint256"
- }
- ],
- "name": "mintVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokenBorrowed",
- "type": "address"
- },
- {
- "name": "cTokenCollateral",
- "type": "address"
- },
- {
- "name": "liquidator",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "repayAmount",
- "type": "uint256"
- },
- {
- "name": "seizeTokens",
- "type": "uint256"
- }
- ],
- "name": "liquidateBorrowVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "liquidationIncentiveMantissa",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "minter",
- "type": "address"
- },
- {
- "name": "mintAmount",
- "type": "uint256"
- }
- ],
- "name": "mintAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newLiquidationIncentiveMantissa",
- "type": "uint256"
- }
- ],
- "name": "_setLiquidationIncentive",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "redeemer",
- "type": "address"
- },
- {
- "name": "redeemAmount",
- "type": "uint256"
- },
- {
- "name": "redeemTokens",
- "type": "uint256"
- }
- ],
- "name": "redeemVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newOracle",
- "type": "address"
- }
- ],
- "name": "_setPriceOracle",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "borrowAmount",
- "type": "uint256"
- }
- ],
- "name": "borrowVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "account",
- "type": "address"
- }
- ],
- "name": "getAccountLiquidity",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- },
- {
- "name": "",
- "type": "uint256"
- },
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokenBorrowed",
- "type": "address"
- },
- {
- "name": "cTokenCollateral",
- "type": "address"
- },
- {
- "name": "liquidator",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "repayAmount",
- "type": "uint256"
- }
- ],
- "name": "liquidateBorrowAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "src",
- "type": "address"
- },
- {
- "name": "dst",
- "type": "address"
- },
- {
- "name": "transferTokens",
- "type": "uint256"
- }
- ],
- "name": "transferVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokenCollateral",
- "type": "address"
- },
- {
- "name": "cTokenBorrowed",
- "type": "address"
- },
- {
- "name": "liquidator",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "seizeTokens",
- "type": "uint256"
- }
- ],
- "name": "seizeVerify",
- "outputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "oracle",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "name": "markets",
- "outputs": [
- {
- "name": "isListed",
- "type": "bool"
- },
- {
- "name": "collateralFactorMantissa",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "account",
- "type": "address"
- },
- {
- "name": "cToken",
- "type": "address"
- }
- ],
- "name": "checkMembership",
- "outputs": [
- {
- "name": "",
- "type": "bool"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "maxAssets",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- }
- ],
- "name": "_supportMarket",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "account",
- "type": "address"
- }
- ],
- "name": "getAssetsIn",
- "outputs": [
- {
- "name": "",
- "type": "address[]"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "comptrollerImplementation",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "src",
- "type": "address"
- },
- {
- "name": "dst",
- "type": "address"
- },
- {
- "name": "transferTokens",
- "type": "uint256"
- }
- ],
- "name": "transferAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokens",
- "type": "address[]"
- }
- ],
- "name": "enterMarkets",
- "outputs": [
- {
- "name": "",
- "type": "uint256[]"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "cTokenBorrowed",
- "type": "address"
- },
- {
- "name": "cTokenCollateral",
- "type": "address"
- },
- {
- "name": "repayAmount",
- "type": "uint256"
- }
- ],
- "name": "liquidateCalculateSeizeTokens",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- },
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokenCollateral",
- "type": "address"
- },
- {
- "name": "cTokenBorrowed",
- "type": "address"
- },
- {
- "name": "liquidator",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "seizeTokens",
- "type": "uint256"
- }
- ],
- "name": "seizeAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newMaxAssets",
- "type": "uint256"
- }
- ],
- "name": "_setMaxAssets",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "borrower",
- "type": "address"
- },
- {
- "name": "borrowAmount",
- "type": "uint256"
- }
- ],
- "name": "borrowAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "",
- "type": "address"
- },
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "name": "accountAssets",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "pendingComptrollerImplementation",
- "outputs": [
- {
- "name": "",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "newCollateralFactorMantissa",
- "type": "uint256"
- }
- ],
- "name": "_setCollateralFactor",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "closeFactorMantissa",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
+var assert = require("assert");
+var fs = require("fs");
+var util = require("ethereumjs-util");
+const constants = require("./constants.js");
+
+const IERC20Artifact = require("../../build/contracts/IERC20.json");
+const MockSaiToDaiMigratorArtifact = require("../../build/contracts/MockSaiToDaiMigrator.json");
+
+const { web3 } = require("./web3");
+
+module.exports = {
+ test: async function(testingContext) {
+ let passed = 0;
+ let failed = 0;
+ 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
+ );
+
+ 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(
+ 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(
+ [
+ {
+ constant: true,
+ inputs: [],
+ name: "pendingAdmin",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newPendingAdmin",
+ type: "address"
+ }
+ ],
+ name: "_setPendingAdmin",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "comptrollerImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [],
+ name: "_acceptImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "pendingComptrollerImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newPendingImplementation",
+ type: "address"
+ }
+ ],
+ name: "_setPendingImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [],
+ name: "_acceptAdmin",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "admin",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ inputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "constructor"
+ },
+ {
+ payable: true,
+ stateMutability: "payable",
+ type: "fallback"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldPendingImplementation",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newPendingImplementation",
+ type: "address"
+ }
+ ],
+ name: "NewPendingImplementation",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldImplementation",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newImplementation",
+ type: "address"
+ }
+ ],
+ name: "NewImplementation",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldPendingAdmin",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newPendingAdmin",
+ type: "address"
+ }
+ ],
+ name: "NewPendingAdmin",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldAdmin",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newAdmin",
+ type: "address"
+ }
+ ],
+ name: "NewAdmin",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "error",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "info",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "detail",
+ type: "uint256"
+ }
+ ],
+ name: "Failure",
+ type: "event"
+ }
+ ],
+ constants.COMPTROLLER_MAINNET_ADDRESS
+ );
+
+ const FIAT_TOKEN = new web3.eth.Contract(
+ [
+ {
+ constant: true,
+ inputs: [],
+ name: "name",
+ outputs: [
+ {
+ name: "",
+ type: "string"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_spender",
+ type: "address"
+ },
+ {
+ name: "_value",
+ type: "uint256"
+ }
+ ],
+ name: "approve",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "totalSupply",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ 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: "_from",
+ type: "address"
+ },
+ {
+ name: "_to",
+ type: "address"
+ },
+ {
+ name: "_value",
+ type: "uint256"
+ }
+ ],
+ name: "transferFrom",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "minter",
+ type: "address"
+ }
+ ],
+ name: "removeMinter",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "decimals",
+ outputs: [
+ {
+ name: "",
+ type: "uint8"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_name",
+ type: "string"
+ },
+ {
+ name: "_symbol",
+ type: "string"
+ },
+ {
+ name: "_currency",
+ type: "string"
+ },
+ {
+ name: "_decimals",
+ type: "uint8"
+ },
+ {
+ name: "_masterMinter",
+ type: "address"
+ },
+ {
+ name: "_pauser",
+ type: "address"
+ },
+ {
+ name: "_blacklister",
+ type: "address"
+ },
+ {
+ name: "_owner",
+ type: "address"
+ }
+ ],
+ name: "initialize",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "masterMinter",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [],
+ name: "unpause",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_to",
+ type: "address"
+ },
+ {
+ name: "_amount",
+ type: "uint256"
+ }
+ ],
+ name: "mint",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_amount",
+ type: "uint256"
+ }
+ ],
+ name: "burn",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "minter",
+ type: "address"
+ },
+ {
+ name: "minterAllowedAmount",
+ type: "uint256"
+ }
+ ],
+ name: "configureMinter",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_newPauser",
+ type: "address"
+ }
+ ],
+ name: "updatePauser",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "paused",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "balanceOf",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [],
+ name: "pause",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "minter",
+ type: "address"
+ }
+ ],
+ name: "minterAllowance",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "owner",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "symbol",
+ outputs: [
+ {
+ name: "",
+ type: "string"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "pauser",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_to",
+ type: "address"
+ },
+ {
+ name: "_value",
+ type: "uint256"
+ }
+ ],
+ name: "transfer",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_newMasterMinter",
+ type: "address"
+ }
+ ],
+ name: "updateMasterMinter",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "isMinter",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "_newBlacklister",
+ type: "address"
+ }
+ ],
+ name: "updateBlacklister",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "blacklister",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "owner",
+ type: "address"
+ },
+ {
+ name: "spender",
+ type: "address"
+ }
+ ],
+ name: "allowance",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "currency",
+ outputs: [
+ {
+ name: "",
+ type: "string"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newOwner",
+ type: "address"
+ }
+ ],
+ name: "transferOwnership",
+ 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"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "minter",
+ type: "address"
+ },
+ {
+ indexed: true,
+ name: "to",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "amount",
+ type: "uint256"
+ }
+ ],
+ name: "Mint",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "burner",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "amount",
+ type: "uint256"
+ }
+ ],
+ name: "Burn",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "minter",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "minterAllowedAmount",
+ type: "uint256"
+ }
+ ],
+ name: "MinterConfigured",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "oldMinter",
+ type: "address"
+ }
+ ],
+ name: "MinterRemoved",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "newMasterMinter",
+ type: "address"
+ }
+ ],
+ name: "MasterMinterChanged",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "_account",
+ type: "address"
+ }
+ ],
+ name: "Blacklisted",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "_account",
+ type: "address"
+ }
+ ],
+ name: "UnBlacklisted",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "newBlacklister",
+ type: "address"
+ }
+ ],
+ name: "BlacklisterChanged",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [],
+ name: "Pause",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [],
+ name: "Unpause",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "newAddress",
+ type: "address"
+ }
+ ],
+ name: "PauserChanged",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "owner",
+ type: "address"
+ },
+ {
+ indexed: true,
+ name: "spender",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "value",
+ type: "uint256"
+ }
+ ],
+ name: "Approval",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "previousOwner",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newOwner",
+ type: "address"
+ }
+ ],
+ name: "OwnershipTransferred",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: "from",
+ type: "address"
+ },
+ {
+ indexed: true,
+ name: "to",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "value",
+ type: "uint256"
+ }
+ ],
+ name: "Transfer",
+ type: "event"
+ }
+ ],
+ constants.USDC_MAINNET_ADDRESS
+ );
+
+ const COMPTROLLER_ABI = [
+ {
+ constant: true,
+ inputs: [],
+ name: "isComptroller",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "payer",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "repayAmount",
+ type: "uint256"
+ },
+ {
+ name: "borrowerIndex",
+ type: "uint256"
+ }
+ ],
+ name: "repayBorrowVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "payer",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "repayAmount",
+ type: "uint256"
+ }
+ ],
+ name: "repayBorrowAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "pendingAdmin",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newCloseFactorMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "_setCloseFactor",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "unitroller",
+ type: "address"
+ },
+ {
+ name: "_oracle",
+ type: "address"
+ },
+ {
+ name: "_closeFactorMantissa",
+ type: "uint256"
+ },
+ {
+ name: "_maxAssets",
+ type: "uint256"
+ },
+ {
+ name: "reinitializing",
+ type: "bool"
+ }
+ ],
+ name: "_become",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "minter",
+ type: "address"
+ },
+ {
+ name: "mintAmount",
+ type: "uint256"
+ },
+ {
+ name: "mintTokens",
+ type: "uint256"
+ }
+ ],
+ name: "mintVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokenBorrowed",
+ type: "address"
+ },
+ {
+ name: "cTokenCollateral",
+ type: "address"
+ },
+ {
+ name: "liquidator",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "repayAmount",
+ type: "uint256"
+ },
+ {
+ name: "seizeTokens",
+ type: "uint256"
+ }
+ ],
+ name: "liquidateBorrowVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "liquidationIncentiveMantissa",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "minter",
+ type: "address"
+ },
+ {
+ name: "mintAmount",
+ type: "uint256"
+ }
+ ],
+ name: "mintAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newLiquidationIncentiveMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "_setLiquidationIncentive",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "redeemer",
+ type: "address"
+ },
+ {
+ name: "redeemAmount",
+ type: "uint256"
+ },
+ {
+ name: "redeemTokens",
+ type: "uint256"
+ }
+ ],
+ name: "redeemVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newOracle",
+ type: "address"
+ }
+ ],
+ name: "_setPriceOracle",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "borrowAmount",
+ type: "uint256"
+ }
+ ],
+ name: "borrowVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "getAccountLiquidity",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ },
+ {
+ name: "",
+ type: "uint256"
+ },
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokenBorrowed",
+ type: "address"
+ },
+ {
+ name: "cTokenCollateral",
+ type: "address"
+ },
+ {
+ name: "liquidator",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "repayAmount",
+ type: "uint256"
+ }
+ ],
+ name: "liquidateBorrowAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "src",
+ type: "address"
+ },
+ {
+ name: "dst",
+ type: "address"
+ },
+ {
+ name: "transferTokens",
+ type: "uint256"
+ }
+ ],
+ name: "transferVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokenCollateral",
+ type: "address"
+ },
+ {
+ name: "cTokenBorrowed",
+ type: "address"
+ },
+ {
+ name: "liquidator",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "seizeTokens",
+ type: "uint256"
+ }
+ ],
+ name: "seizeVerify",
+ outputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "oracle",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ name: "markets",
+ outputs: [
+ {
+ name: "isListed",
+ type: "bool"
+ },
+ {
+ name: "collateralFactorMantissa",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "account",
+ type: "address"
+ },
+ {
+ name: "cToken",
+ type: "address"
+ }
+ ],
+ name: "checkMembership",
+ outputs: [
+ {
+ name: "",
+ type: "bool"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "maxAssets",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ }
+ ],
+ name: "_supportMarket",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "getAssetsIn",
+ outputs: [
+ {
+ name: "",
+ type: "address[]"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "comptrollerImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "src",
+ type: "address"
+ },
+ {
+ name: "dst",
+ type: "address"
+ },
+ {
+ name: "transferTokens",
+ type: "uint256"
+ }
+ ],
+ name: "transferAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokens",
+ type: "address[]"
+ }
+ ],
+ name: "enterMarkets",
+ outputs: [
+ {
+ name: "",
+ type: "uint256[]"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "cTokenBorrowed",
+ type: "address"
+ },
+ {
+ name: "cTokenCollateral",
+ type: "address"
+ },
+ {
+ name: "repayAmount",
+ type: "uint256"
+ }
+ ],
+ name: "liquidateCalculateSeizeTokens",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ },
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokenCollateral",
+ type: "address"
+ },
+ {
+ name: "cTokenBorrowed",
+ type: "address"
+ },
+ {
+ name: "liquidator",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "seizeTokens",
+ type: "uint256"
+ }
+ ],
+ name: "seizeAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "newMaxAssets",
+ type: "uint256"
+ }
+ ],
+ name: "_setMaxAssets",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "borrower",
+ type: "address"
+ },
+ {
+ name: "borrowAmount",
+ type: "uint256"
+ }
+ ],
+ name: "borrowAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: "",
+ type: "address"
+ },
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ name: "accountAssets",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "pendingComptrollerImplementation",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "newCollateralFactorMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "_setCollateralFactor",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "closeFactorMantissa",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cToken",
+ type: "address"
+ },
+ {
+ name: "redeemer",
+ type: "address"
+ },
+ {
+ name: "redeemTokens",
+ type: "uint256"
+ }
+ ],
+ name: "redeemAllowed",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: "cTokenAddress",
+ type: "address"
+ }
+ ],
+ name: "exitMarket",
+ outputs: [
+ {
+ name: "",
+ type: "uint256"
+ }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: "admin",
+ outputs: [
+ {
+ name: "",
+ type: "address"
+ }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ },
+ {
+ inputs: [],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "constructor"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "cToken",
+ type: "address"
+ }
+ ],
+ name: "MarketListed",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "cToken",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "MarketEntered",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "cToken",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "account",
+ type: "address"
+ }
+ ],
+ name: "MarketExited",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldCloseFactorMantissa",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "newCloseFactorMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "NewCloseFactor",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "cToken",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "oldCollateralFactorMantissa",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "newCollateralFactorMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "NewCollateralFactor",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldLiquidationIncentiveMantissa",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "newLiquidationIncentiveMantissa",
+ type: "uint256"
+ }
+ ],
+ name: "NewLiquidationIncentive",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldMaxAssets",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "newMaxAssets",
+ type: "uint256"
+ }
+ ],
+ name: "NewMaxAssets",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "oldPriceOracle",
+ type: "address"
+ },
+ {
+ indexed: false,
+ name: "newPriceOracle",
+ type: "address"
+ }
+ ],
+ name: "NewPriceOracle",
+ type: "event"
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ name: "error",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "info",
+ type: "uint256"
+ },
+ {
+ indexed: false,
+ name: "detail",
+ type: "uint256"
+ }
+ ],
+ name: "Failure",
+ type: "event"
+ }
+ ];
+
+ // get available addresses and assign them to various roles
+ const addresses = await web3.eth.getAccounts();
+ if (addresses.length < 1) {
+ console.log("cannot find enough addresses to run tests!");
+ process.exit(1);
}
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cToken",
- "type": "address"
- },
- {
- "name": "redeemer",
- "type": "address"
- },
- {
- "name": "redeemTokens",
- "type": "uint256"
+
+ let latestBlock = await web3.eth.getBlock("latest");
+
+ const originalAddress = addresses[0];
+
+ let address = await setupNewDefaultAddress(
+ "0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed"
+ );
+
+ let addressTwo = await setupNewDefaultAddress(
+ "0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d"
+ );
+
+ const gasLimit = latestBlock.gasLimit;
+
+ // 0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14
+ // primary address, nonce: 0
+ const mockPriceOracleDeploymentData =
+ "0x608060405234801561001057600080fd5b5060cd8061001f6000396000f3fe60806040" +
+ "52348015600f57600080fd5b506004361060325760003560e01c806366331bba14603757" +
+ "8063fc57d4df146051575b600080fd5b603d6086565b6040805191151582525190819003" +
+ "60200190f35b607460048036036020811015606557600080fd5b50356001600160a01b03" +
+ "16608b565b60408051918252519081900360200190f35b600190565b50670de0b6b3a764" +
+ "00009056fea265627a7a72315820cf3b4d1c8f3041ebb02fbc6b404dd54636a41af89e8a" +
+ "04ea19bf35f04b48fae764736f6c634300050b0032";
+
+ // 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
+ // nonce: 4
+ const mockDaiDeploymentData =
+ "0x608060405234801561001057600080fd5b5060405160208061085d8339810180604052" +
+ "810190808051906020019092919050505080600160003373ffffffffffffffffffffffff" +
+ "ffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001" +
+ "9081526020016000208190555080600081905550506107cf8061008e6000396000f30060" +
+ "8060405260043610610078576000357c0100000000000000000000000000000000000000" +
+ "000000000000000000900463ffffffff168063095ea7b31461007d57806318160ddd1461" +
+ "00e257806323b872dd1461010d57806370a0823114610192578063a9059cbb146101e957" +
+ "8063dd62ed3e1461024e575b600080fd5b34801561008957600080fd5b506100c8600480" +
+ "360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092" +
+ "9190803590602001909291905050506102c5565b60405180821515151581526020019150" +
+ "5060405180910390f35b3480156100ee57600080fd5b506100f76103b7565b6040518082" +
+ "815260200191505060405180910390f35b34801561011957600080fd5b50610178600480" +
+ "360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092" +
+ "9190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035" +
+ "90602001909291905050506103c0565b6040518082151515158152602001915050604051" +
+ "80910390f35b34801561019e57600080fd5b506101d3600480360381019080803573ffff" +
+ "ffffffffffffffffffffffffffffffffffff169060200190929190505050610686565b60" +
+ "40518082815260200191505060405180910390f35b3480156101f557600080fd5b506102" +
+ "34600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060" +
+ "200190929190803590602001909291905050506106cf565b604051808215151515815260" +
+ "200191505060405180910390f35b34801561025a57600080fd5b506102af600480360381" +
+ "019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080" +
+ "3573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506106" +
+ "e4565b6040518082815260200191505060405180910390f35b600081600260003373ffff" +
+ "ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff" +
+ "ffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffff" +
+ "ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190" +
+ "8152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff1633" +
+ "73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d" +
+ "1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405180828152602001915050604051" +
+ "80910390a36001905092915050565b60008054905090565b60003373ffffffffffffffff" +
+ "ffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16" +
+ "1415156104fe5761047d600260008673ffffffffffffffffffffffffffffffffffffffff" +
+ "1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000" +
+ "2060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffff" +
+ "ffffffffffffffffffffff168152602001908152602001600020548361076b565b600260" +
+ "008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff" +
+ "ffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffff" +
+ "ffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681" +
+ "52602001908152602001600020819055505b610547600160008673ffffffffffffffffff" +
+ "ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152" +
+ "602001908152602001600020548361076b565b600160008673ffffffffffffffffffffff" +
+ "ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020" +
+ "01908152602001600020819055506105d3600160008573ffffffffffffffffffffffffff" +
+ "ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190" +
+ "81526020016000205483610787565b600160008573ffffffffffffffffffffffffffffff" +
+ "ffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152" +
+ "602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ff" +
+ "ffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378d" +
+ "aa952ba7f163c4a11628f55a4df523b3ef84604051808281526020019150506040518091" +
+ "0390a3600190509392505050565b6000600160008373ffffffffffffffffffffffffffff" +
+ "ffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081" +
+ "52602001600020549050919050565b60006106dc3384846103c0565b905092915050565b" +
+ "6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff" +
+ "ffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffff" +
+ "ffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffff" +
+ "ffffff16815260200190815260200160002054905092915050565b600082828403915081" +
+ "1115151561078157600080fd5b92915050565b6000828284019150811015151561079d57" +
+ "600080fd5b929150505600a165627a7a72305820b4ab3c13e840dd08d9787883bde3458d" +
+ "cbab9a56f185c55a59574286095eb6e80029f00000000000000000000000000000000000" +
+ "0000000000000000000000000000";
+
+ // 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
+ // nonce: 20
+ const mockUSDCDeploymentData =
+ "0x60806040526000600460146101000a81548160ff021916908315150217905550600060" +
+ "0e5561003c33610041640100000000026401000000009004565b610084565b8060008061" +
+ "01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff" +
+ "ffffffffffffffffffffffffffffffffff16021790555050565b6135c580620000946000" +
+ "396000f3006080604052600436106101a1576000357c0100000000000000000000000000" +
+ "000000000000000000000000000000900463ffffffff16806306fdde03146101a6578063" +
+ "095ea7b31461023657806318160ddd1461029b5780631a895266146102c657806323b872" +
+ "dd146103095780633092afd51461038e578063313ce567146103e95780633357162b1461" +
+ "041a57806335d99f351461059c57806339509351146105f35780633f4ba83a1461065857" +
+ "806340c10f191461066f57806342966c68146106d45780634e44d9561461070157806355" +
+ "4bab3c146107665780635c975abb146107a957806370a08231146107d85780638456cb59" +
+ "1461082f5780638a6db9c3146108465780638da5cb5b1461089d57806395d89b41146108" +
+ "f45780639fd0506d14610984578063a457c2d7146109db578063a9059cbb14610a405780" +
+ "63aa20e1e414610aa5578063aa271e1a14610ae8578063ad38bf2214610b43578063bd10" +
+ "243014610b86578063dd62ed3e14610bdd578063e5a6b10f14610c54578063f2fde38b14" +
+ "610ce4578063f9f92be414610d27578063fe575a8714610d6a575b600080fd5b34801561" +
+ "01b257600080fd5b506101bb610dc5565b60405180806020018281038252838181518152" +
+ "60200191508051906020019080838360005b838110156101fb5780820151818401526020" +
+ "810190506101e0565b50505050905090810190601f168015610228578082038051600183" +
+ "6020036101000a031916815260200191505b509250505060405180910390f35b34801561" +
+ "024257600080fd5b50610281600480360381019080803573ffffffffffffffffffffffff" +
+ "ffffffffffffffff16906020019092919080359060200190929190505050610e63565b60" +
+ "4051808215151515815260200191505060405180910390f35b3480156102a757600080fd" +
+ "5b506102b0611033565b6040518082815260200191505060405180910390f35b34801561" +
+ "02d257600080fd5b50610307600480360381019080803573ffffffffffffffffffffffff" +
+ "ffffffffffffffff16906020019092919050505061103d565b005b348015610315576000" +
+ "80fd5b50610374600480360381019080803573ffffffffffffffffffffffffffffffffff" +
+ "ffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16" +
+ "906020019092919080359060200190929190505050611137565b60405180821515151581" +
+ "5260200191505060405180910390f35b34801561039a57600080fd5b506103cf60048036" +
+ "0381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291" +
+ "90505050611636565b604051808215151515815260200191505060405180910390f35b34" +
+ "80156103f557600080fd5b506103fe61177d565b604051808260ff1660ff168152602001" +
+ "91505060405180910390f35b34801561042657600080fd5b5061059a6004803603810190" +
+ "80803590602001908201803590602001908080601f016020809104026020016040519081" +
+ "016040528093929190818152602001838380828437820191505050505050919291929080" +
+ "3590602001908201803590602001908080601f0160208091040260200160405190810160" +
+ "405280939291908181526020018383808284378201915050505050509192919290803590" +
+ "602001908201803590602001908080601f01602080910402602001604051908101604052" +
+ "80939291908181526020018383808284378201915050505050509192919290803560ff16" +
+ "9060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001" +
+ "90929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190" +
+ "803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ff" +
+ "ffffffffffffffffffffffffffffffffffffff169060200190929190505050611790565b" +
+ "005b3480156105a857600080fd5b506105b16119ed565b604051808273ffffffffffffff" +
+ "ffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16" +
+ "815260200191505060405180910390f35b3480156105ff57600080fd5b5061063e600480" +
+ "360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092" +
+ "919080359060200190929190505050611a13565b60405180821515151581526020019150" +
+ "5060405180910390f35b34801561066457600080fd5b5061066d611ab8565b005b348015" +
+ "61067b57600080fd5b506106ba600480360381019080803573ffffffffffffffffffffff" +
+ "ffffffffffffffffff16906020019092919080359060200190929190505050611b5d565b" +
+ "604051808215151515815260200191505060405180910390f35b3480156106e057600080" +
+ "fd5b506106ff60048036038101908080359060200190929190505050611eff565b005b34" +
+ "801561070d57600080fd5b5061074c600480360381019080803573ffffffffffffffffff" +
+ "ffffffffffffffffffffff16906020019092919080359060200190929190505050612166" +
+ "565b604051808215151515815260200191505060405180910390f35b3480156107725760" +
+ "0080fd5b506107a7600480360381019080803573ffffffffffffffffffffffffffffffff" +
+ "ffffffff1690602001909291905050506122d4565b005b3480156107b557600080fd5b50" +
+ "6107be6123fa565b604051808215151515815260200191505060405180910390f35b3480" +
+ "156107e457600080fd5b50610819600480360381019080803573ffffffffffffffffffff" +
+ "ffffffffffffffffffff16906020019092919050505061240d565b604051808281526020" +
+ "0191505060405180910390f35b34801561083b57600080fd5b50610844612456565b005b" +
+ "34801561085257600080fd5b50610887600480360381019080803573ffffffffffffffff" +
+ "ffffffffffffffffffffffff1690602001909291905050506124fb565b60405180828152" +
+ "60200191505060405180910390f35b3480156108a957600080fd5b506108b2612544565b" +
+ "604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffff" +
+ "ffffffffffffffffffffffff16815260200191505060405180910390f35b348015610900" +
+ "57600080fd5b5061090961256d565b604051808060200182810382528381815181526020" +
+ "0191508051906020019080838360005b8381101561094957808201518184015260208101" +
+ "905061092e565b50505050905090810190601f1680156109765780820380516001836020" +
+ "036101000a031916815260200191505b509250505060405180910390f35b348015610990" +
+ "57600080fd5b5061099961260b565b604051808273ffffffffffffffffffffffffffffff" +
+ "ffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050" +
+ "60405180910390f35b3480156109e757600080fd5b50610a266004803603810190808035" +
+ "73ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001" +
+ "90929190505050612631565b604051808215151515815260200191505060405180910390" +
+ "f35b348015610a4c57600080fd5b50610a8b600480360381019080803573ffffffffffff" +
+ "ffffffffffffffffffffffffffff16906020019092919080359060200190929190505050" +
+ "612734565b604051808215151515815260200191505060405180910390f35b348015610a" +
+ "b157600080fd5b50610ae6600480360381019080803573ffffffffffffffffffffffffff" +
+ "ffffffffffffff169060200190929190505050612a37565b005b348015610af457600080" +
+ "fd5b50610b29600480360381019080803573ffffffffffffffffffffffffffffffffffff" +
+ "ffff169060200190929190505050612b5d565b6040518082151515158152602001915050" +
+ "60405180910390f35b348015610b4f57600080fd5b50610b846004803603810190808035" +
+ "73ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612bb3" +
+ "565b005b348015610b9257600080fd5b50610b9b612cd9565b604051808273ffffffffff" +
+ "ffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffff" +
+ "ff16815260200191505060405180910390f35b348015610be957600080fd5b50610c3e60" +
+ "0480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001" +
+ "90929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190" +
+ "505050612cff565b6040518082815260200191505060405180910390f35b348015610c60" +
+ "57600080fd5b50610c69612d86565b604051808060200182810382528381815181526020" +
+ "0191508051906020019080838360005b83811015610ca957808201518184015260208101" +
+ "9050610c8e565b50505050905090810190601f168015610cd65780820380516001836020" +
+ "036101000a031916815260200191505b509250505060405180910390f35b348015610cf0" +
+ "57600080fd5b50610d25600480360381019080803573ffffffffffffffffffffffffffff" +
+ "ffffffffffff169060200190929190505050612e24565b005b348015610d3357600080fd" +
+ "5b50610d68600480360381019080803573ffffffffffffffffffffffffffffffffffffff" +
+ "ff169060200190929190505050612f4b565b005b348015610d7657600080fd5b50610dab" +
+ "600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020" +
+ "0190929190505050613045565b6040518082151515158152602001915050604051809103" +
+ "90f35b60078054600181600116156101000203166002900480601f016020809104026020" +
+ "016040519081016040528092919081815260200182805460018160011615610100020316" +
+ "600290048015610e5b5780601f10610e3057610100808354040283529160200191610e5b" +
+ "565b820191906000526020600020905b815481529060010190602001808311610e3e5782" +
+ "9003601f168201915b505050505081565b6000600460149054906101000a900460ff1615" +
+ "1515610e8157600080fd5b3360001515600660008373ffffffffffffffffffffffffffff" +
+ "ffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081" +
+ "5260200160002060009054906101000a900460ff161515141515610ee157600080fd5b83" +
+ "60001515600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffff" +
+ "ffffffffffffffffffffffffffffffff1681526020019081526020016000206000905490" +
+ "6101000a900460ff161515141515610f4157600080fd5b83600d60003373ffffffffffff" +
+ "ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff" +
+ "16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffff" +
+ "ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020" +
+ "01600020819055508473ffffffffffffffffffffffffffffffffffffffff163373ffffff" +
+ "ffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd" +
+ "0314c0f7b2291e5b200ac8c7c3b925866040518082815260200191505060405180910390" +
+ "a360019250505092915050565b6000600e54905090565b600560009054906101000a9004" +
+ "73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff" +
+ "ffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156110" +
+ "9957600080fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff16" +
+ "73ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020" +
+ "60006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffff" +
+ "ffffffffffffffffff167f117e3210bb9aa7d9baff172026820255c6f6c30ba8999d1c2f" +
+ "d88e2848137c4e60405160405180910390a250565b6000600460149054906101000a9004" +
+ "60ff1615151561115557600080fd5b8260001515600660008373ffffffffffffffffffff" +
+ "ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260" +
+ "200190815260200160002060009054906101000a900460ff1615151415156111b5576000" +
+ "80fd5b3360001515600660008373ffffffffffffffffffffffffffffffffffffffff1673" +
+ "ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060" +
+ "009054906101000a900460ff16151514151561121557600080fd5b856000151560066000" +
+ "8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff" +
+ "ffffffffffffffff16815260200190815260200160002060009054906101000a900460ff" +
+ "16151514151561127557600080fd5b600073ffffffffffffffffffffffffffffffffffff" +
+ "ffff168673ffffffffffffffffffffffffffffffffffffffff16141515156112b1576000" +
+ "80fd5b600c60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffff" +
+ "ffffffffffffffffffffffffffffff168152602001908152602001600020548511151515" +
+ "6112ff57600080fd5b600d60008873ffffffffffffffffffffffffffffffffffffffff16" +
+ "73ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020" +
+ "60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffff" +
+ "ffffffffffffffffffff16815260200190815260200160002054851115151561138a5760" +
+ "0080fd5b6113dc85600c60008a73ffffffffffffffffffffffffffffffffffffffff1673" +
+ "ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054" +
+ "61309b90919063ffffffff16565b600c60008973ffffffffffffffffffffffffffffffff" +
+ "ffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260" +
+ "20016000208190555061147185600c60008973ffffffffffffffffffffffffffffffffff" +
+ "ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020" +
+ "01600020546130e590919063ffffffff16565b600c60008873ffffffffffffffffffffff" +
+ "ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020" +
+ "019081526020016000208190555061154385600d60008a73ffffffffffffffffffffffff" +
+ "ffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001" +
+ "90815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ff" +
+ "ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461" +
+ "309b90919063ffffffff16565b600d60008973ffffffffffffffffffffffffffffffffff" +
+ "ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020" +
+ "0160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff" +
+ "ffffffffffffffffffffffffffff168152602001908152602001600020819055508573ff" +
+ "ffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffff" +
+ "ffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4d" +
+ "f523b3ef876040518082815260200191505060405180910390a360019350505050939250" +
+ "5050565b6000600b60009054906101000a900473ffffffffffffffffffffffffffffffff" +
+ "ffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff" +
+ "ffffffffffffffffffffffffff1614151561169457600080fd5b6000600f60008473ffff" +
+ "ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff" +
+ "ffffffff16815260200190815260200160002060006101000a81548160ff021916908315" +
+ "1502179055506000601060008473ffffffffffffffffffffffffffffffffffffffff1673" +
+ "ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081" +
+ "9055508173ffffffffffffffffffffffffffffffffffffffff167fe94479a9f7e1952cc7" +
+ "8f2d6baab678adc1b772d936c6583def489e524cb6669260405160405180910390a26001" +
+ "9050919050565b600960009054906101000a900460ff1681565b600b6014905490610100" +
+ "0a900460ff161515156117ac57600080fd5b600073ffffffffffffffffffffffffffffff" +
+ "ffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156117e8" +
+ "57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffff" +
+ "ffffffffffffffffffffffffffffffff161415151561182457600080fd5b600073ffffff" +
+ "ffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffff" +
+ "ffffffff161415151561186057600080fd5b600073ffffffffffffffffffffffffffffff" +
+ "ffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561189c" +
+ "57600080fd5b87600790805190602001906118b29291906134f4565b5086600890805190" +
+ "602001906118c99291906134f4565b5085600a90805190602001906118e09291906134f4" +
+ "565b5084600960006101000a81548160ff021916908360ff16021790555083600b600061" +
+ "01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff" +
+ "ffffffffffffffffffffffffffffffffff16021790555082600460006101000a81548173" +
+ "ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffff" +
+ "ffffffffffffffffffff16021790555081600560006101000a81548173ffffffffffffff" +
+ "ffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffff" +
+ "ffffff1602179055506119c88161316f565b6001600b60146101000a81548160ff021916" +
+ "9083151502179055505050505050505050565b600b60009054906101000a900473ffffff" +
+ "ffffffffffffffffffffffffffffffffff1681565b6000611aae3384611aa98560026000" +
+ "3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff" +
+ "ffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffff" +
+ "ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152" +
+ "602001908152602001600020546130e590919063ffffffff16565b6131b2565b60019050" +
+ "92915050565b600460009054906101000a900473ffffffffffffffffffffffffffffffff" +
+ "ffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff" +
+ "ffffffffffffffffffffffffff16141515611b1457600080fd5b6000600460146101000a" +
+ "81548160ff0219169083151502179055507f7805862f689e2f13df9f062ff482ad3ad112" +
+ "aca9e0847911ed832e158c525b3360405160405180910390a1565b600080600460149054" +
+ "906101000a900460ff16151515611b7c57600080fd5b60011515600f60003373ffffffff" +
+ "ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff" +
+ "ffff16815260200190815260200160002060009054906101000a900460ff161515141515" +
+ "611bdb57600080fd5b3360001515600660008373ffffffffffffffffffffffffffffffff" +
+ "ffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260" +
+ "200160002060009054906101000a900460ff161515141515611c3b57600080fd5b846000" +
+ "1515600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff" +
+ "ffffffffffffffffffffffffffff16815260200190815260200160002060009054906101" +
+ "000a900460ff161515141515611c9b57600080fd5b600073ffffffffffffffffffffffff" +
+ "ffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614151515" +
+ "611cd757600080fd5b600085111515611ce657600080fd5b601060003373ffffffffffff" +
+ "ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff" +
+ "168152602001908152602001600020549250828511151515611d3757600080fd5b611d4c" +
+ "85600e546130e590919063ffffffff16565b600e81905550611da485600c60008973ffff" +
+ "ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff" +
+ "ffffffff168152602001908152602001600020546130e590919063ffffffff16565b600c" +
+ "60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffff" +
+ "ffffffffffffffffffff16815260200190815260200160002081905550611dfa85846130" +
+ "9b90919063ffffffff16565b601060003373ffffffffffffffffffffffffffffffffffff" +
+ "ffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001" +
+ "600020819055508573ffffffffffffffffffffffffffffffffffffffff163373ffffffff" +
+ "ffffffffffffffffffffffffffffffff167fab8530f87dc9b59234c4623bf917212bb253" +
+ "6d647574c8e7e5da92c2ede0c9f8876040518082815260200191505060405180910390a3" +
+ "8573ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2" +
+ "b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405180828152602001915050" +
+ "60405180910390a36001935050505092915050565b6000600460149054906101000a9004" +
+ "60ff16151515611f1d57600080fd5b60011515600f60003373ffffffffffffffffffffff" +
+ "ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020" +
+ "0190815260200160002060009054906101000a900460ff161515141515611f7c57600080" +
+ "fd5b3360001515600660008373ffffffffffffffffffffffffffffffffffffffff1673ff" +
+ "ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000" +
+ "9054906101000a900460ff161515141515611fdc57600080fd5b600c60003373ffffffff" +
+ "ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff" +
+ "ffff16815260200190815260200160002054915060008311151561202d57600080fd5b82" +
+ "821015151561203c57600080fd5b61205183600e5461309b90919063ffffffff16565b60" +
+ "0e8190555061206a838361309b90919063ffffffff16565b600c60003373ffffffffffff" +
+ "ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff" +
+ "168152602001908152602001600020819055503373ffffffffffffffffffffffffffffff" +
+ "ffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d" +
+ "397ca5846040518082815260200191505060405180910390a2600073ffffffffffffffff" +
+ "ffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16" +
+ "7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040" +
+ "518082815260200191505060405180910390a3505050565b600060046014905490610100" +
+ "0a900460ff1615151561218457600080fd5b600b60009054906101000a900473ffffffff" +
+ "ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff" +
+ "ffff163373ffffffffffffffffffffffffffffffffffffffff161415156121e057600080" +
+ "fd5b6001600f60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffff" +
+ "ffffffffffffffffffffffffffffffff1681526020019081526020016000206000610100" +
+ "0a81548160ff02191690831515021790555081601060008573ffffffffffffffffffffff" +
+ "ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020" +
+ "01908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff" +
+ "167f46980fca912ef9bcdbd36877427b6b90e860769f604e89c0e67720cece530d208360" +
+ "40518082815260200191505060405180910390a26001905092915050565b6122dc612544" +
+ "565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffff" +
+ "ffffffffffffffffffff1614151561231557600080fd5b600073ffffffffffffffffffff" +
+ "ffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415" +
+ "151561235157600080fd5b80600460006101000a81548173ffffffffffffffffffffffff" +
+ "ffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602" +
+ "17905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffff" +
+ "ffff1673ffffffffffffffffffffffffffffffffffffffff167fb80482a293ca2e013eda" +
+ "8683c9bd7fc8347cfdaeea5ede58cba46df502c2a60460405160405180910390a250565b" +
+ "600460149054906101000a900460ff1681565b6000600c60008373ffffffffffffffffff" +
+ "ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152" +
+ "602001908152602001600020549050919050565b600460009054906101000a900473ffff" +
+ "ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff" +
+ "ffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156124b25760" +
+ "0080fd5b6001600460146101000a81548160ff0219169083151502179055507f6985a022" +
+ "10a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff6256040516040518091" +
+ "0390a1565b6000601060008373ffffffffffffffffffffffffffffffffffffffff1673ff" +
+ "ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490" +
+ "50919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffff" +
+ "ffffffffff16905090565b60088054600181600116156101000203166002900480601f01" +
+ "602080910402602001604051908101604052809291908181526020018280546001816001" +
+ "16156101000203166002900480156126035780601f106125d85761010080835404028352" +
+ "9160200191612603565b820191906000526020600020905b815481529060010190602001" +
+ "8083116125e657829003601f168201915b505050505081565b600460009054906101000a" +
+ "900473ffffffffffffffffffffffffffffffffffffffff1681565b600061272a33846127" +
+ "2585606060405190810160405280602581526020017f45524332303a2064656372656173" +
+ "656420616c6c6f77616e63652062656c6f7781526020017f207a65726f00000000000000" +
+ "0000000000000000000000000000000000000000815250600260003373ffffffffffffff" +
+ "ffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16" +
+ "815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffff" +
+ "ffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001" +
+ "600020546134339092919063ffffffff16565b6131b2565b6001905092915050565b6000" +
+ "600460149054906101000a900460ff1615151561275257600080fd5b3360001515600660" +
+ "008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff" +
+ "ffffffffffffffffff16815260200190815260200160002060009054906101000a900460" +
+ "ff1615151415156127b257600080fd5b8360001515600660008373ffffffffffffffffff" +
+ "ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152" +
+ "60200190815260200160002060009054906101000a900460ff1615151415156128125760" +
+ "0080fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffff" +
+ "ffffffffffffffffffffffffffff161415151561284e57600080fd5b600c60003373ffff" +
+ "ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff" +
+ "ffffffff16815260200190815260200160002054841115151561289c57600080fd5b6128" +
+ "ee84600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff" +
+ "ffffffffffffffffffffffffffff1681526020019081526020016000205461309b909190" +
+ "63ffffffff16565b600c60003373ffffffffffffffffffffffffffffffffffffffff1673" +
+ "ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081" +
+ "90555061298384600c60008873ffffffffffffffffffffffffffffffffffffffff1673ff" +
+ "ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461" +
+ "30e590919063ffffffff16565b600c60008773ffffffffffffffffffffffffffffffffff" +
+ "ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020" +
+ "01600020819055508473ffffffffffffffffffffffffffffffffffffffff163373ffffff" +
+ "ffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa95" +
+ "2ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390" +
+ "a360019250505092915050565b612a3f612544565b73ffffffffffffffffffffffffffff" +
+ "ffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612a78" +
+ "57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffff" +
+ "ffffffffffffffffffffffffffffffff1614151515612ab457600080fd5b80600b600061" +
+ "01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff" +
+ "ffffffffffffffffffffffffffffffffff160217905550600b60009054906101000a9004" +
+ "73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff" +
+ "ffffffffffffff167fdb66dfa9c6b8f5226fe9aac7e51897ae8ee94ac31dc70bb6c9900b" +
+ "2574b707e660405160405180910390a250565b6000600f60008373ffffffffffffffffff" +
+ "ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152" +
+ "60200190815260200160002060009054906101000a900460ff169050919050565b612bbb" +
+ "612544565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff" +
+ "ffffffffffffffffffffffffff16141515612bf457600080fd5b600073ffffffffffffff" +
+ "ffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff" +
+ "1614151515612c3057600080fd5b80600560006101000a81548173ffffffffffffffffff" +
+ "ffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffff" +
+ "ff160217905550600560009054906101000a900473ffffffffffffffffffffffffffffff" +
+ "ffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fc67398012c111c" +
+ "e95ecb7429b933096c977380ee6c421175a71a4a4c6c88c06e60405160405180910390a2" +
+ "50565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffff" +
+ "ff1681565b6000600d60008473ffffffffffffffffffffffffffffffffffffffff1673ff" +
+ "ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000" +
+ "8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff" +
+ "ffffffffffffffff16815260200190815260200160002054905092915050565b600a8054" +
+ "600181600116156101000203166002900480601f01602080910402602001604051908101" +
+ "604052809291908181526020018280546001816001161561010002031660029004801561" +
+ "2e1c5780601f10612df157610100808354040283529160200191612e1c565b8201919060" +
+ "00526020600020905b815481529060010190602001808311612dff57829003601f168201" +
+ "915b505050505081565b612e2c612544565b73ffffffffffffffffffffffffffffffffff" +
+ "ffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612e65576000" +
+ "80fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffff" +
+ "ffffffffffffffffffffffffff1614151515612ea157600080fd5b7f8be0079c53165914" +
+ "1344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612eca612544565b82604051" +
+ "808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff" +
+ "ffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffff" +
+ "ff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050604051" +
+ "80910390a1612f488161316f565b50565b600560009054906101000a900473ffffffffff" +
+ "ffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffff" +
+ "ff163373ffffffffffffffffffffffffffffffffffffffff16141515612fa757600080fd" +
+ "5b6001600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffff" +
+ "ffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a" +
+ "81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffff" +
+ "ffffff167fffa4e6181777692565cf28528fc88fd1516ea86b56da075235fa575af6a4b8" +
+ "5560405160405180910390a250565b6000600660008373ffffffffffffffffffffffffff" +
+ "ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190" +
+ "815260200160002060009054906101000a900460ff169050919050565b60006130dd8383" +
+ "6040805190810160405280601e81526020017f536166654d6174683a2073756274726163" +
+ "74696f6e206f766572666c6f770000815250613433565b905092915050565b6000808284" +
+ "019050838110151515613165576040517f08c379a0000000000000000000000000000000" +
+ "00000000000000000000000000815260040180806020018281038252601b815260200180" +
+ "7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815250" +
+ "60200191505060405180910390fd5b8091505092915050565b806000806101000a815481" +
+ "73ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffff" +
+ "ffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffff" +
+ "ffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561" +
+ "327d576040517f08c379a000000000000000000000000000000000000000000000000000" +
+ "00000081526004018080602001828103825260248152602001807f45524332303a206170" +
+ "70726f76652066726f6d20746865207a65726f2061646481526020017f72657373000000" +
+ "000000000000000000000000000000000000000000000000008152506040019150506040" +
+ "5180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffff" +
+ "ffffffffffffffffffffffffffffffffff1614151515613348576040517f08c379a00000" +
+ "000000000000000000000000000000000000000000000000000081526004018080602001" +
+ "828103825260228152602001807f45524332303a20617070726f766520746f2074686520" +
+ "7a65726f20616464726581526020017f7373000000000000000000000000000000000000" +
+ "00000000000000000000000081525060400191505060405180910390fd5b806002600085" +
+ "73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff" +
+ "ffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffff" +
+ "ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260" +
+ "2001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffff" +
+ "ff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f" +
+ "71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405180828152602001915050" +
+ "60405180910390a3505050565b60008084841115839015156134e3576040517f08c379a0" +
+ "000000000000000000000000000000000000000000000000000000008152600401808060" +
+ "2001828103825283818151815260200191508051906020019080838360005b8381101561" +
+ "34a857808201518184015260208101905061348d565b50505050905090810190601f1680" +
+ "156134d55780820380516001836020036101000a031916815260200191505b5092505050" +
+ "60405180910390fd5b508385039050809150509392505050565b82805460018160011615" +
+ "6101000203166002900490600052602060002090601f016020900481019282601f106135" +
+ "3557805160ff1916838001178555613563565b8280016001018555821561356357918201" +
+ "5b82811115613562578251825591602001919060010190613547565b5b50905061357091" +
+ "90613574565b5090565b61359691905b8082111561359257600081600090555060010161" +
+ "357a565b5090565b905600a165627a7a72305820e15de5c992fd476a4778192f1e437474" +
+ "d0da61a53e449a2db2ec25213f4be8620029";
+
+ // 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B
+ // nonce: 0
+ const mockUnitrollerDeploymentData =
+ "0x608060405234801561001057600080fd5b50600080546001600160a01b031916331790" +
+ "556105db806100326000396000f3fe60806040526004361061007b5760003560e01c8063" +
+ "dcfbc0c71161004e578063dcfbc0c71461019e578063e992a041146101b3578063e9c714" +
+ "f2146101e6578063f851a440146101fb5761007b565b806326782247146100fe578063b7" +
+ "1d1a0c1461012f578063bb82aa5e14610174578063c1e8033414610189575b6002546040" +
+ "516000916001600160a01b03169082903690808383808284376040519201945060009350" +
+ "9091505080830381855af49150503d80600081146100de576040519150601f19603f3d01" +
+ "1682016040523d82523d6000602084013e6100e3565b606091505b505090506040513d60" +
+ "00823e8180156100fa573d82f35b3d82fd5b34801561010a57600080fd5b506101136102" +
+ "10565b604080516001600160a01b039092168252519081900360200190f35b3480156101" +
+ "3b57600080fd5b506101626004803603602081101561015257600080fd5b503560016001" +
+ "60a01b031661021f565b60408051918252519081900360200190f35b3480156101805760" +
+ "0080fd5b506101136102b0565b34801561019557600080fd5b506101626102bf565b3480" +
+ "156101aa57600080fd5b506101136103ba565b3480156101bf57600080fd5b5061016260" +
+ "0480360360208110156101d657600080fd5b50356001600160a01b03166103c9565b3480" +
+ "156101f257600080fd5b5061016261044d565b34801561020757600080fd5b5061011361" +
+ "0533565b6001546001600160a01b031681565b600080546001600160a01b031633146102" +
+ "455761023e6001600e610542565b90506102ab565b600180546001600160a01b03848116" +
+ "6001600160a01b0319831681179093556040805191909216808252602082019390935281" +
+ "517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99291" +
+ "81900390910190a160005b9150505b919050565b6002546001600160a01b031681565b60" +
+ "03546000906001600160a01b0316331415806102e557506003546001600160a01b031615" +
+ "5b156102fc576102f5600180610542565b90506103b7565b600280546003805460016001" +
+ "60a01b038082166001600160a01b03198086168217968790559092169092556040805193" +
+ "8316808552949092166020840152815190927fd604de94d45953f9138079ec1b82d533cb" +
+ "2160c906d1076d1f7ed54befbca97a92908290030190a1600354604080516001600160a0" +
+ "1b038085168252909216602083015280517fe945ccee5d701fc83f9b8aa8ca94ea4219ec" +
+ "1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160005b925050505b90565b6003" +
+ "546001600160a01b031681565b600080546001600160a01b031633146103e85761023e60" +
+ "01600f610542565b600380546001600160a01b038481166001600160a01b031983161792" +
+ "8390556040805192821680845293909116602083015280517fe945ccee5d701fc83f9b8a" +
+ "a8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160006102a756" +
+ "5b6001546000906001600160a01b031633141580610468575033155b15610479576102f5" +
+ "60016000610542565b60008054600180546001600160a01b038082166001600160a01b03" +
+ "198086168217968790559092169092556040805193831680855294909216602084015281" +
+ "5190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" +
+ "92908290030190a1600154604080516001600160a01b0380851682529092166020830152" +
+ "80517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a992" +
+ "81900390910190a160006103b2565b6000546001600160a01b031681565b60007f45b96f" +
+ "e442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561" +
+ "057157fe5b83601381111561057d57fe5b60408051928352602083019190915260008282" +
+ "0152519081900360600190a18260118111156105a857fe5b939250505056fea165627a7a" +
+ "72305820deb1fa7c9392a8cb5591582fb6e4b04575db52ce8ef799b0a7a5140ae6ff75d8" +
+ "0029";
+
+ // 0x178053c06006e67e09879C09Ff012fF9d263dF29
+ // nonce: 68
+ const mockCurrentComptrollerDeploymentData =
+ "0x608060405234801561001057600080fd5b50600080546001600160a01b031916331790" +
+ "55612d15806100326000396000f3fe608060405234801561001057600080fd5b50600436" +
+ "106102315760003560e01c80638e8f294b11610130578063d02f7351116100b8578063e4" +
+ "028eee1161007c578063e4028eee1461090e578063e87554461461093a578063eabe7d91" +
+ "14610942578063ede4edd014610978578063f851a4401461099e57610231565b8063d02f" +
+ "735114610841578063d9226ced14610887578063da3d454c146108a4578063dce1544914" +
+ "6108da578063dcfbc0c71461090657610231565b8063abfceffc116100ff578063abfcef" +
+ "fc14610695578063bb82aa5e1461070b578063bdcdc25814610713578063c29982381461" +
+ "074f578063c488847b146107f257610231565b80638e8f294b146105f8578063929fe9a1" +
+ "1461063957806394b2294b14610667578063a76b3fda1461066f57610231565b80634ef4" +
+ "c3e1116101be5780635ec88c79116101825780635ec88c79146104e45780635fc7e71e14" +
+ "6105285780636a56947e1461056e5780636d35bf91146105aa5780637dc0d1d0146105f0" +
+ "57610231565b80634ef4c3e1146103f95780634fd42e171461042f57806351dff9891461" +
+ "044c57806355ee1fe1146104885780635c778605146104ae57610231565b8063317b0b77" +
+ "11610205578063317b0b771461030857806332000e001461032557806341c728b9146103" +
+ "6957806347ef3b3b146103a55780634ada90af146103f157610231565b80627e3dd21461" +
+ "02365780631ededc911461025257806324008a621461029657806326782247146102e457" +
+ "5b600080fd5b61023e6109a6565b604080519115158252519081900360200190f35b6102" +
+ "94600480360360a081101561026857600080fd5b506001600160a01b0381358116916020" +
+ "81013582169160408201351690606081013590608001356109ab565b005b6102d2600480" +
+ "360360808110156102ac57600080fd5b506001600160a01b038135811691602081013582" +
+ "169160408201351690606001356109b2565b60408051918252519081900360200190f35b" +
+ "6102ec6109e8565b604080516001600160a01b039092168252519081900360200190f35b" +
+ "6102d26004803603602081101561031e57600080fd5b50356109f7565b61029460048036" +
+ "0360a081101561033b57600080fd5b506001600160a01b03813581169160208101359091" +
+ "1690604081013590606081013590608001351515610b05565b6102946004803603608081" +
+ "101561037f57600080fd5b506001600160a01b0381358116916020810135909116906040" +
+ "8101359060600135610fcd565b610294600480360360c08110156103bb57600080fd5b50" +
+ "6001600160a01b0381358116916020810135821691604082013581169160608101359091" +
+ "169060808101359060a00135610fd3565b6102d2610fd8565b6102d26004803603606081" +
+ "101561040f57600080fd5b506001600160a01b0381358116916020810135909116906040" +
+ "0135610fde565b6102d26004803603602081101561044557600080fd5b5035611015565b" +
+ "6102946004803603608081101561046257600080fd5b506001600160a01b038135811691" +
+ "60208101359091169060408101359060600135611104565b6102d2600480360360208110" +
+ "1561049e57600080fd5b50356001600160a01b0316611167565b61029460048036036060" +
+ "8110156104c457600080fd5b506001600160a01b03813581169160208101359091169060" +
+ "4001356111e9565b61050a600480360360208110156104fa57600080fd5b503560016001" +
+ "60a01b03166111ee565b6040805193845260208401929092528282015251908190036060" +
+ "0190f35b6102d2600480360360a081101561053e57600080fd5b506001600160a01b0381" +
+ "358116916020810135821691604082013581169160608101359091169060800135611223" +
+ "565b6102946004803603608081101561058457600080fd5b506001600160a01b03813581" +
+ "169160208101358216916040820135169060600135610fcd565b610294600480360360a0" +
+ "8110156105c057600080fd5b506001600160a01b03813581169160208101358216916040" +
+ "820135811691606081013590911690608001356109ab565b6102ec6113aa565b61061e60" +
+ "04803603602081101561060e57600080fd5b50356001600160a01b03166113b9565b6040" +
+ "8051921515835260208301919091528051918290030190f35b61023e6004803603604081" +
+ "101561064f57600080fd5b506001600160a01b03813581169160200135166113d8565b61" +
+ "02d261140c565b6102d26004803603602081101561068557600080fd5b50356001600160" +
+ "a01b0316611412565b6106bb600480360360208110156106ab57600080fd5b5035600160" +
+ "0160a01b0316611541565b60408051602080825283518183015283519192839290830191" +
+ "858101910280838360005b838110156106f75781810151838201526020016106df565b50" +
+ "5050509050019250505060405180910390f35b6102ec6115ca565b6102d2600480360360" +
+ "8081101561072957600080fd5b506001600160a01b038135811691602081013582169160" +
+ "408201351690606001356115d9565b6106bb6004803603602081101561076557600080fd" +
+ "5b81019060208101813564010000000081111561078057600080fd5b8201836020820111" +
+ "1561079257600080fd5b8035906020019184602083028401116401000000008311171561" +
+ "07b457600080fd5b91908080602002602001604051908101604052809392919081815260" +
+ "20018383602002808284376000920191909152509295506115e6945050505050565b6108" +
+ "286004803603606081101561080857600080fd5b506001600160a01b0381358116916020" +
+ "810135909116906040013561178a565b6040805192835260208301919091528051918290" +
+ "030190f35b6102d2600480360360a081101561085757600080fd5b506001600160a01b03" +
+ "81358116916020810135821691604082013581169160608101359091169060800135611a" +
+ "05565b6102d26004803603602081101561089d57600080fd5b5035611b4b565b6102d260" +
+ "0480360360608110156108ba57600080fd5b506001600160a01b03813581169160208101" +
+ "359091169060400135611baf565b6102ec600480360360408110156108f057600080fd5b" +
+ "506001600160a01b038135169060200135611ce6565b6102ec611d1b565b6102d2600480" +
+ "3603604081101561092457600080fd5b506001600160a01b038135169060200135611d2a" +
+ "565b6102d2611edd565b6102d26004803603606081101561095857600080fd5b50600160" +
+ "0160a01b03813581169160208101359091169060400135611ee3565b6102d26004803603" +
+ "602081101561098e57600080fd5b50356001600160a01b0316611ef0565b6102ec612206" +
+ "565b600181565b5050505050565b6001600160a01b038416600090815260096020526040" +
+ "81205460ff166109da575060096109e0565b60005b90505b949350505050565b60015460" +
+ "01600160a01b031681565b6000610a01612215565b610a1857610a116001600461226056" +
+ "5b9050610b00565b610a20612bde565b506040805160208101909152828152610a37612b" +
+ "de565b50604080516020810190915266b1a2bc2ec500008152610a5782826122c6565b15" +
+ "610a7057610a67600580612260565b92505050610b00565b610a78612bde565b50604080" +
+ "5160208101909152670c7d713b49da00008152610a9981846122ce565b15610ab357610a" +
+ "a9600580612260565b9350505050610b00565b6005805490869055604080518281526020" +
+ "810188905281517f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f3" +
+ "46110fd9929181900390910190a160005b9450505050505b919050565b846001600160a0" +
+ "1b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186" +
+ "803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d6000fd5b5050" +
+ "50506040513d6020811015610b6857600080fd5b50516001600160a01b03163314610bb3" +
+ "57604051600160e51b62461bcd0281526004018080602001828103825260278152602001" +
+ "80612cc36027913960400191505060405180910390fd5b6000856001600160a01b031663" +
+ "c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b" +
+ "158015610bf057600080fd5b505af1158015610c04573d6000803e3d6000fd5b50505050" +
+ "6040513d6020811015610c1a57600080fd5b505190508015610c745760408051600160e5" +
+ "1b62461bcd02815260206004820152601560248201527f6368616e6765206e6f74206175" +
+ "74686f72697a65640000000000000000000000604482015290519081900360640190fd5b" +
+ "81610fc55760008690506000816001600160a01b03166355ee1fe1886040518263ffffff" +
+ "ff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191" +
+ "5050602060405180830381600087803b158015610cd857600080fd5b505af1158015610c" +
+ "ec573d6000803e3d6000fd5b505050506040513d6020811015610d0257600080fd5b5051" +
+ "90508015610d5c5760408051600160e51b62461bcd028152602060048201526016602482" +
+ "01527f736574207072696365206f7261636c65206572726f720000000000000000000060" +
+ "4482015290519081900360640190fd5b816001600160a01b031663317b0b778760405182" +
+ "63ffffffff1660e01b815260040180828152602001915050602060405180830381600087" +
+ "803b158015610da257600080fd5b505af1158015610db6573d6000803e3d6000fd5b5050" +
+ "50506040513d6020811015610dcc57600080fd5b505190508015610e2657604080516001" +
+ "60e51b62461bcd02815260206004820152601660248201527f73657420636c6f73652066" +
+ "6163746f72206572726f7200000000000000000000604482015290519081900360640190" +
+ "fd5b816001600160a01b031663d9226ced866040518263ffffffff1660e01b8152600401" +
+ "80828152602001915050602060405180830381600087803b158015610e6c57600080fd5b" +
+ "505af1158015610e80573d6000803e3d6000fd5b505050506040513d6020811015610e96" +
+ "57600080fd5b505190508015610ef05760408051600160e51b62461bcd02815260206004" +
+ "820152601560248201527f736574206d61782061737373657473206572726f7200000000" +
+ "00000000000000604482015290519081900360640190fd5b816001600160a01b0316634f" +
+ "d42e17670de0b6b3a76400006040518263ffffffff1660e01b8152600401808281526020" +
+ "01915050602060405180830381600087803b158015610f3e57600080fd5b505af1158015" +
+ "610f52573d6000803e3d6000fd5b505050506040513d6020811015610f6857600080fd5b" +
+ "505190508015610fc25760408051600160e51b62461bcd02815260206004820152601f60" +
+ "248201527f736574206c69717569646174696f6e20696e63656e74697665206572726f72" +
+ "00604482015290519081900360640190fd5b50505b505050505050565b50505050565b61" +
+ "0fc5565b60065481565b6001600160a01b03831660009081526009602052604081205460" +
+ "ff166110085760095b905061100e565b60005b90505b9392505050565b600061101f6122" +
+ "15565b61102f57610a116001600b612260565b611037612bde565b506040805160208101" +
+ "90915282815261104e612bde565b506040805160208101909152670de0b6b3a764000081" +
+ "5261106f82826122ce565b1561108057610a676007600c612260565b611088612bde565b" +
+ "5060408051602081019091526714d1120d7b16000081526110a981846122ce565b156110" +
+ "ba57610aa96007600c612260565b60068054908690556040805182815260208101889052" +
+ "81517faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec131692" +
+ "9181900390910190a16000610af9565b801580156111125750600082115b15610fcd5760" +
+ "408051600160e51b62461bcd02815260206004820152601160248201527f72656465656d" +
+ "546f6b656e73207a65726f00000000000000000000000000000060448201529051908190" +
+ "0360640190fd5b6000611171612215565b61118157610a1160016010612260565b600480" +
+ "546001600160a01b038481166001600160a01b0319831681179093556040805191909216" +
+ "808252602082019390935281517fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d" +
+ "2d0ea78402d576d22e22929181900390910190a160009392505050565b505050565b6000" +
+ "806000806000806112058760008060006122d5565b925092509250826011811115611217" +
+ "57fe5b97919650945092505050565b6001600160a01b0385166000908152600960205260" +
+ "4081205460ff16158061126457506001600160a01b038516600090815260096020526040" +
+ "90205460ff16155b156112735760095b90506113a1565b60008061127f856126fd565b91" +
+ "93509091506000905082601181111561129557fe5b146112af578160118111156112a657" +
+ "fe5b925050506113a1565b806112bb5760036112a6565b6000886001600160a01b031663" +
+ "95dd9193876040518263ffffffff1660e01b815260040180826001600160a01b03166001" +
+ "600160a01b0316815260200191505060206040518083038186803b158015611313576000" +
+ "80fd5b505afa158015611327573d6000803e3d6000fd5b505050506040513d6020811015" +
+ "61133d57600080fd5b505160408051602081019091526005548152909150600090819061" +
+ "1361908461271d565b9092509050600082600381111561137457fe5b1461138857600b5b" +
+ "955050505050506113a1565b8087111561139757601161137c565b600095505050505050" +
+ "5b95945050505050565b6004546001600160a01b031681565b6009602052600090815260" +
+ "409020805460019091015460ff9091169082565b6001600160a01b038082166000908152" +
+ "600960209081526040808320938616835260029093019052205460ff165b92915050565b" +
+ "60075481565b600080546001600160a01b0316331461143157610a116001601261226056" +
+ "5b6001600160a01b03821660009081526009602052604090205460ff161561145e57610a" +
+ "11600a6011612260565b816001600160a01b031663fe9c44ae6040518163ffffffff1660" +
+ "e01b815260040160206040518083038186803b15801561149757600080fd5b505afa1580" +
+ "156114ab573d6000803e3d6000fd5b505050506040513d60208110156114c157600080fd" +
+ "5b50506040805180820182526001808252600060208084018281526001600160a01b0388" +
+ "1680845260098352928690209451855460ff191690151517855551939092019290925582" +
+ "5191825291517fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f2" +
+ "12321f929181900390910190a1600092915050565b60608060086000846001600160a01b" +
+ "03166001600160a01b031681526020019081526020016000208054806020026020016040" +
+ "519081016040528092919081815260200182805480156115bd5760200282019190600052" +
+ "6020600020905b81546001600160a01b0316815260019091019060200180831161159f57" +
+ "5b5093979650505050505050565b6002546001600160a01b031681565b60006109dd8585" +
+ "84612771565b606060008251905060608160405190808252806020026020018201604052" +
+ "801561161a578160200160208202803883390190505b50905060005b8281101561178257" +
+ "600085828151811061163657fe5b6020908102919091018101516001600160a01b038116" +
+ "60009081526009909252604090912080549192509060ff1661168a5760095b8484815181" +
+ "1061167757fe5b602002602001018181525050505061177a565b33600090815260028201" +
+ "602052604090205460ff161515600114156116b057600061166b565b6007543360009081" +
+ "5260086020526040902054106116cf57601061166b565b33600081815260028301602090" +
+ "81526040808320805460ff19166001908117909155600883528184208054918201815584" +
+ "529282902090920180546001600160a01b0387166001600160a01b031990911681179091" +
+ "5582519081529081019290925280517f3ab23ab0d51cccc0c3085aec51f99228625aa1a9" +
+ "22b3a8ca89a26b0f2027a1a59281900390910190a1600084848151811061176b57fe5b60" +
+ "200260200101818152505050505b600101611620565b509392505050565b600480546040" +
+ "8051600160e01b63fc57d4df0281526001600160a01b0387811694820194909452905160" +
+ "00938493849391169163fc57d4df91602480820192602092909190829003018186803b15" +
+ "80156117e357600080fd5b505afa1580156117f7573d6000803e3d6000fd5b5050505060" +
+ "40513d602081101561180d57600080fd5b50516004805460408051600160e01b63fc57d4" +
+ "df0281526001600160a01b038a8116948201949094529051939450600093929091169163" +
+ "fc57d4df91602480820192602092909190829003018186803b15801561186957600080fd" +
+ "5b505afa15801561187d573d6000803e3d6000fd5b505050506040513d60208110156118" +
+ "9357600080fd5b505190508115806118a2575080155b156118b757600d93506000925061" +
+ "19fd915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e0" +
+ "1b815260040160206040518083038186803b1580156118f257600080fd5b505afa158015" +
+ "611906573d6000803e3d6000fd5b505050506040513d602081101561191c57600080fd5b" +
+ "50519050600061192a612bde565b611932612bde565b61193a612bde565b600061194860" +
+ "0654896127e0565b94509050600081600381111561195a57fe5b1461197657600b5b9950" +
+ "600098506119fd975050505050505050565b61198087876127e0565b9350905060008160" +
+ "0381111561199257fe5b1461199e57600b611962565b6119a8848461281b565b92509050" +
+ "60008160038111156119ba57fe5b146119c657600b611962565b6119d0828c61271d565b" +
+ "9550905060008160038111156119e257fe5b146119ee57600b611962565b600099509397" +
+ "50505050505050505b935093915050565b6001600160a01b038516600090815260096020" +
+ "52604081205460ff161580611a4657506001600160a01b03851660009081526009602052" +
+ "604090205460ff16155b15611a5257600961126c565b846001600160a01b0316635fe3b5" +
+ "676040518163ffffffff1660e01b815260040160206040518083038186803b158015611a" +
+ "8b57600080fd5b505afa158015611a9f573d6000803e3d6000fd5b505050506040513d60" +
+ "20811015611ab557600080fd5b505160408051600160e01b635fe3b56702815290516001" +
+ "600160a01b0392831692891691635fe3b567916004808301926020929190829003018186" +
+ "803b158015611afe57600080fd5b505afa158015611b12573d6000803e3d6000fd5b5050" +
+ "50506040513d6020811015611b2857600080fd5b50516001600160a01b031614611b3f57" +
+ "600261126c565b60009695505050505050565b6000611b55612215565b611b6557610a11" +
+ "6001600d612260565b6007805490839055604080518281526020810185905281517f7093" +
+ "cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea929181900390" +
+ "910190a1600061100e565b6001600160a01b038316600090815260096020526040812054" +
+ "60ff16611bd6576009611001565b6001600160a01b038085166000908152600960209081" +
+ "526040808320938716835260029093019052205460ff16611c0e576008611001565b6004" +
+ "805460408051600160e01b63fc57d4df0281526001600160a01b03888116948201949094" +
+ "529051929091169163fc57d4df91602480820192602092909190829003018186803b1580" +
+ "15611c6257600080fd5b505afa158015611c76573d6000803e3d6000fd5b505050506040" +
+ "513d6020811015611c8c57600080fd5b5051611c9957600d611001565b600080611ca985" +
+ "876000876122d5565b91935090915060009050826011811115611cbf57fe5b14611cd957" +
+ "816011811115611cd057fe5b9250505061100e565b8015611b3f576004611cd0565b6008" +
+ "6020528160005260406000208181548110611cff57fe5b60009182526020909120015460" +
+ "01600160a01b03169150829050565b6003546001600160a01b031681565b600080546001" +
+ "600160a01b03163314611d5057611d4960016006612260565b9050611406565b60016001" +
+ "60a01b0383166000908152600960205260409020805460ff16611d8557611d7d60096007" +
+ "612260565b915050611406565b611d8d612bde565b506040805160208101909152838152" +
+ "611da4612bde565b506040805160208101909152670c7d713b49da00008152611dc58183" +
+ "6122ce565b15611de057611dd660066008612260565b9350505050611406565b84158015" +
+ "90611e6c57506004805460408051600160e01b63fc57d4df0281526001600160a01b038a" +
+ "8116948201949094529051929091169163fc57d4df916024808201926020929091908290" +
+ "03018186803b158015611e3e57600080fd5b505afa158015611e52573d6000803e3d6000" +
+ "fd5b505050506040513d6020811015611e6857600080fd5b5051155b15611e7d57611dd6" +
+ "600d6009612260565b60018301805490869055604080516001600160a01b038916815260" +
+ "20810183905280820188905290517f70483e6592cd5182d45ac970e05bc62cdcc90e9d8e" +
+ "f2c2dbe686cf383bcd7fc59181900360600190a16000979650505050505050565b600554" +
+ "81565b600061100b848484612771565b6000808290506000806000836001600160a01b03" +
+ "1663c37f68e2336040518263ffffffff1660e01b815260040180826001600160a01b0316" +
+ "6001600160a01b0316815260200191505060806040518083038186803b158015611f5157" +
+ "600080fd5b505afa158015611f65573d6000803e3d6000fd5b505050506040513d608081" +
+ "1015611f7b57600080fd5b50805160208201516040909201519094509092509050821561" +
+ "1fd157604051600160e51b62461bcd028152600401808060200182810382526025815260" +
+ "200180612c9e6025913960400191505060405180910390fd5b8015611fee57611fe3600c" +
+ "6002612260565b945050505050610b00565b6000611ffb873385612771565b9050801561" +
+ "201c57612010600e600383612833565b95505050505050610b00565b6001600160a01b03" +
+ "85166000908152600960209081526040808320338452600281019092529091205460ff16" +
+ "61205b5760009650505050505050610b00565b3360009081526002820160209081526040" +
+ "808320805460ff1916905560088252918290208054835181840281018401909452808452" +
+ "606093928301828280156120cd57602002820191906000526020600020905b8154600160" +
+ "0160a01b031681526001909101906020018083116120af575b5050835193945083925060" +
+ "009150505b8281101561212257896001600160a01b03168482815181106120fb57fe5b60" +
+ "200260200101516001600160a01b0316141561211a57809150612122565b6001016120dd" +
+ "565b5081811061212c57fe5b336000908152600860205260409020805481906000198101" +
+ "90811061214d57fe5b9060005260206000200160009054906101000a90046001600160a0" +
+ "1b031681838154811061217757fe5b600091825260209091200180546001600160a01b03" +
+ "19166001600160a01b039290921691909117905580546121b0826000198301612bf1565b" +
+ "50604080516001600160a01b038c16815233602082015281517fe699a64c18b07ac5b730" +
+ "1aa273f36a2287239eb9501d81950672794afba29a0d929181900390910190a160009c9b" +
+ "505050505050505050505050565b6000546001600160a01b031681565b60025460009081" +
+ "906001600160a01b03163314801561223e57506000546001600160a01b031632145b6000" +
+ "549091506001600160a01b0316331480806122585750815b925050505b90565b60007f45" +
+ "b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360118111" +
+ "1561228f57fe5b83601381111561229b57fe5b6040805192835260208301919091526000" +
+ "82820152519081900360600190a182601181111561100e57fe5b519051111590565b5190" +
+ "511090565b60008060006122e2612c15565b6001600160a01b0388166000908152600860" +
+ "209081526040808320805482518185028101850190935280835284936060939291908301" +
+ "8282801561234f57602002820191906000526020600020905b81546001600160a01b0316" +
+ "8152600190910190602001808311612331575b50939450600093505050505b8151811015" +
+ "6126ae57600082828151811061237257fe5b60200260200101519050806001600160a01b" +
+ "031663c37f68e28e6040518263ffffffff1660e01b815260040180826001600160a01b03" +
+ "166001600160a01b0316815260200191505060806040518083038186803b1580156123d2" +
+ "57600080fd5b505afa1580156123e6573d6000803e3d6000fd5b505050506040513d6080" +
+ "8110156123fc57600080fd5b508051602082015160408084015160609485015160808c01" +
+ "52938a019390935291880191909152945084156124425750600f97506000965086955061" +
+ "26f3945050505050565b60408051602080820183526001600160a01b0380851660008181" +
+ "526009845285902060010154845260c08b01939093528351808301855260808b01518152" +
+ "60e08b0152600480548551600160e01b63fc57d4df028152918201949094529351921692" +
+ "63fc57d4df9260248083019392829003018186803b1580156124c557600080fd5b505afa" +
+ "1580156124d9573d6000803e3d6000fd5b505050506040513d60208110156124ef576000" +
+ "80fd5b505160a087018190526125135750600d9750600096508695506126f39450505050" +
+ "50565b604080516020810190915260a08701518152610100870181905260c087015160e0" +
+ "88015161254092612899565b6101208801529350600084600381111561255657fe5b1461" +
+ "25725750600b9750600096508695506126f3945050505050565b61258a86610120015187" +
+ "6040015188600001516128f1565b87529350600084600381111561259c57fe5b146125b8" +
+ "5750600b9750600096508695506126f3945050505050565b6125d0866101000151876060" +
+ "015188602001516128f1565b6020880152935060008460038111156125e557fe5b146126" +
+ "015750600b9750600096508695506126f3945050505050565b8b6001600160a01b031681" +
+ "6001600160a01b031614156126a55761262f8661012001518c88602001516128f1565b60" +
+ "208801529350600084600381111561264457fe5b146126605750600b9750600096508695" +
+ "506126f3945050505050565b6126748661010001518b88602001516128f1565b60208801" +
+ "529350600084600381111561268957fe5b146126a55750600b9750600096508695506126" +
+ "f3945050505050565b5060010161235b565b506020840151845111156126d55750505060" +
+ "208101519051600094500391508290506126f3565b505081516020909201516000955085" +
+ "94509190910391506126f39050565b9450945094915050565b6000806000612710846000" +
+ "8060006122d5565b9250925092509193909250565b600080600061272a612bde565b6127" +
+ "34868661293e565b9092509050600082600381111561274757fe5b146127585750915060" +
+ "00905061276a565b6000612763826129a6565b9350935050505b9250929050565b600160" +
+ "0160a01b03831660009081526009602052604081205460ff16612798576009611001565b" +
+ "6001600160a01b0380851660009081526009602090815260408083209387168352600290" +
+ "93019052205460ff166127d0576000611001565b600080611ca985878660006122d5565b" +
+ "60006127ea612bde565b6128106040518060200160405280868152506040518060200160" +
+ "405280868152506129b5565b915091509250929050565b6000612825612bde565b835183" +
+ "516128109190612a9e565b60007f45b96fe442630264581b197e84bbada861235052c5a1" +
+ "aadfff9ea4e40a969aa084601181111561286257fe5b84601381111561286e57fe5b6040" +
+ "80519283526020830191909152818101859052519081900360600190a183601181111561" +
+ "100b57fe5b60006128a3612bde565b60006128ad612bde565b6128b787876129b5565b90" +
+ "9250905060008260038111156128ca57fe5b146128d95790925090506119fd565b6128e3" +
+ "81866129b5565b935093505050935093915050565b60008060006128fe612bde565b6129" +
+ "08878761293e565b9092509050600082600381111561291b57fe5b1461292c5750915060" +
+ "0090506119fd565b6128e3612938826129a6565b86612b4e565b6000612948612bde565b" +
+ "600080612959866000015186612b74565b9092509050600082600381111561296c57fe5b" +
+ "1461298b5750604080516020810190915260008152909250905061276a565b6040805160" +
+ "2081019091529081526000969095509350505050565b51670de0b6b3a764000090049056" +
+ "5b60006129bf612bde565b6000806129d486600001518660000151612b74565b90925090" +
+ "5060008260038111156129e757fe5b14612a065750604080516020810190915260008152" +
+ "909250905061276a565b600080612a1b6706f05b59d3b2000084612b4e565b9092509050" +
+ "6000826003811115612a2e57fe5b14612a50575060408051602081019091526000815290" +
+ "9450925061276a915050565b600080612a6583670de0b6b3a7640000612bb3565b909250" +
+ "90506000826003811115612a7857fe5b14612a7f57fe5b60408051602081019091529081" +
+ "5260009a909950975050505050505050565b6000612aa8612bde565b600080612abd8667" +
+ "0de0b6b3a7640000612b74565b90925090506000826003811115612ad057fe5b14612aef" +
+ "5750604080516020810190915260008152909250905061276a565b600080612afc838861" +
+ "2bb3565b90925090506000826003811115612b0f57fe5b14612b31575060408051602081" +
+ "0190915260008152909450925061276a915050565b604080516020810190915290815260" +
+ "009890975095505050505050565b600080838301848110612b665760009250905061276a" +
+ "565b50600291506000905061276a565b60008083612b875750600090508061276a565b83" +
+ "830283858281612b9457fe5b0414612ba85750600291506000905061276a565b60009250" +
+ "905061276a565b60008082612bc7575060019050600061276a565b6000838581612bd257" +
+ "fe5b04915091509250929050565b6040518060200160405280600081525090565b815481" +
+ "8355818111156111e9576000838152602090206111e9918101908301612c7f565b604051" +
+ "806101400160405280600081526020016000815260200160008152602001600081526020" +
+ "016000815260200160008152602001612c53612bde565b8152602001612c60612bde565b" +
+ "8152602001612c6d612bde565b8152602001612c7a612bde565b905290565b61225d9190" +
+ "5b80821115612c995760008155600101612c85565b509056fe657869744d61726b65743a" +
+ "206765744163636f756e74536e617073686f74206661696c65646f6e6c7920756e697472" +
+ "6f6c6c65722061646d696e2063616e206368616e676520627261696e73a165627a7a7230" +
+ "582075d92d0e96eb01957b794704a02af0b7e3c5efe630de7186f3688639d7128e900029";
+
+ // 0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a
+ // nonce: 7
+ const mockCDaiIRMDeploymentData =
+ "0x608060405234801561001057600080fd5b506040516040806106638339810180604052" +
+ "604081101561003057600080fd5b50805160209091015160019190915560005561061280" +
+ "6100516000396000f3fe608060405234801561001057600080fd5b506004361061005757" +
+ "60003560e01c806315f240531461005c5780631b3ed7221461009e5780631f68f20a1461" +
+ "00b85780632191f92a146100c0578063a385fb96146100dc575b600080fd5b6100856004" +
+ "803603606081101561007257600080fd5b50803590602081013590604001356100e4565b" +
+ "6040805192835260208301919091528051918290030190f35b6100a661017d565b604080" +
+ "51918252519081900360200190f35b6100a6610183565b6100c8610189565b6040805191" +
+ "15158252519081900360200190f35b6100a661018e565b60008060006100f16105d3565b" +
+ "6100f96105d3565b6101038888610195565b919450925090506000836004811115610118" +
+ "57fe5b146101385782600481111561012957fe5b94506000935061017592505050565b60" +
+ "006101426105d3565b61014f8362201480610312565b9092509050600082600381111561" +
+ "016257fe5b1461016957fe5b51600096509450505050505b935093915050565b60005481" +
+ "565b60015481565b600181565b6220148081565b600061019f6105d3565b6101a76105d3" +
+ "565b60006101b16105d3565b6101bb878761037c565b9092509050600082600481111561" +
+ "01ce57fe5b146101fc575060408051602080820183526000808352835191820190935291" +
+ "8252919450909250905061030b565b60006102066105d3565b6102128360005461043e56" +
+ "5b9092509050600082600381111561022557fe5b14610257575050604080516020808201" +
+ "835260008083528351918201909352918252600396509450925061030b915050565b6000" +
+ "6102616105d3565b61027383670de0b6b3a7640000610312565b90925090506000826003" +
+ "81111561028657fe5b1461028d57fe5b60006102976105d3565b6102b183604051806020" +
+ "0160405280600154815250610459565b909250905060008260038111156102c457fe5b14" +
+ "6102fa57505060408051602080820183526000808352835191820190935291825260049a" +
+ "509850965061030b95505050505050565b60009a509598509496505050505050505b9250" +
+ "925092565b600061031c6105d3565b60008061032d866000015186610493565b90925090" +
+ "50600082600381111561034057fe5b1461035f5750604080516020810190915260008152" +
+ "9092509050610375565b6040805160208101909152908152600093509150505b92509290" +
+ "50565b60006103866105d3565b826103a357505060408051602081019091526000808252" +
+ "90610375565b6000806103b086866104be565b909250905060008260038111156103c357" +
+ "fe5b146103e4575050604080516020810190915260008152600192509050610375565b60" +
+ "006103ee6105d3565b6103f887846104e4565b9092509050600082600381111561040b57" +
+ "fe5b1461042f575050604080516020810190915260008152600294509250610375915050" +
+ "565b60009890975095505050505050565b60006104486105d3565b60008061032d866000" +
+ "015186610594565b60006104636105d3565b600080610478866000015186600001516104" +
+ "be565b60408051602081019091529081529097909650945050505050565b600080826104" +
+ "a75750600190506000610375565b60008385816104b257fe5b0491509150925092905056" +
+ "5b6000808383018481106104d657600092509050610375565b5060029150600090506103" +
+ "75565b60006104ee6105d3565b60008061050386670de0b6b3a7640000610594565b9092" +
+ "509050600082600381111561051657fe5b14610535575060408051602081019091526000" +
+ "81529092509050610375565b6000806105428388610493565b9092509050600082600381" +
+ "111561055557fe5b14610577575060408051602081019091526000815290945092506103" +
+ "75915050565b604080516020810190915290815260009890975095505050505050565b60" +
+ "0080836105a757506000905080610375565b838302838582816105b457fe5b04146105c8" +
+ "57506002915060009050610375565b600092509050610375565b60405180602001604052" +
+ "8060008152509056fea165627a7a7230582021d1e96de1a54e5aaf17c19ae397dd393fa0" +
+ "cd21afedd016b0e6d1fb0e4c749600290000000000000000000000000000000000000000" +
+ "0000000000b1a2bc2ec50000000000000000000000000000000000000000000000000000" +
+ "01aa535d3d0c0000";
+
+ // 0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB
+ // nonce: 8
+ const mockCUSDCIRMDeploymentData =
+ "0x608060405234801561001057600080fd5b506040516040806106638339810180604052" +
+ "604081101561003057600080fd5b50805160209091015160019190915560005561061280" +
+ "6100516000396000f3fe608060405234801561001057600080fd5b506004361061005757" +
+ "60003560e01c806315f240531461005c5780631b3ed7221461009e5780631f68f20a1461" +
+ "00b85780632191f92a146100c0578063a385fb96146100dc575b600080fd5b6100856004" +
+ "803603606081101561007257600080fd5b50803590602081013590604001356100e4565b" +
+ "6040805192835260208301919091528051918290030190f35b6100a661017d565b604080" +
+ "51918252519081900360200190f35b6100a6610183565b6100c8610189565b6040805191" +
+ "15158252519081900360200190f35b6100a661018e565b60008060006100f16105d3565b" +
+ "6100f96105d3565b6101038888610195565b919450925090506000836004811115610118" +
+ "57fe5b146101385782600481111561012957fe5b94506000935061017592505050565b60" +
+ "006101426105d3565b61014f8362201480610312565b9092509050600082600381111561" +
+ "016257fe5b1461016957fe5b51600096509450505050505b935093915050565b60005481" +
+ "565b60015481565b600181565b6220148081565b600061019f6105d3565b6101a76105d3" +
+ "565b60006101b16105d3565b6101bb878761037c565b9092509050600082600481111561" +
+ "01ce57fe5b146101fc575060408051602080820183526000808352835191820190935291" +
+ "8252919450909250905061030b565b60006102066105d3565b6102128360005461043e56" +
+ "5b9092509050600082600381111561022557fe5b14610257575050604080516020808201" +
+ "835260008083528351918201909352918252600396509450925061030b915050565b6000" +
+ "6102616105d3565b61027383670de0b6b3a7640000610312565b90925090506000826003" +
+ "81111561028657fe5b1461028d57fe5b60006102976105d3565b6102b183604051806020" +
+ "0160405280600154815250610459565b909250905060008260038111156102c457fe5b14" +
+ "6102fa57505060408051602080820183526000808352835191820190935291825260049a" +
+ "509850965061030b95505050505050565b60009a509598509496505050505050505b9250" +
+ "925092565b600061031c6105d3565b60008061032d866000015186610493565b90925090" +
+ "50600082600381111561034057fe5b1461035f5750604080516020810190915260008152" +
+ "9092509050610375565b6040805160208101909152908152600093509150505b92509290" +
+ "50565b60006103866105d3565b826103a357505060408051602081019091526000808252" +
+ "90610375565b6000806103b086866104be565b909250905060008260038111156103c357" +
+ "fe5b146103e4575050604080516020810190915260008152600192509050610375565b60" +
+ "006103ee6105d3565b6103f887846104e4565b9092509050600082600381111561040b57" +
+ "fe5b1461042f575050604080516020810190915260008152600294509250610375915050" +
+ "565b60009890975095505050505050565b60006104486105d3565b60008061032d866000" +
+ "015186610594565b60006104636105d3565b600080610478866000015186600001516104" +
+ "be565b60408051602081019091529081529097909650945050505050565b600080826104" +
+ "a75750600190506000610375565b60008385816104b257fe5b0491509150925092905056" +
+ "5b6000808383018481106104d657600092509050610375565b5060029150600090506103" +
+ "75565b60006104ee6105d3565b60008061050386670de0b6b3a7640000610594565b9092" +
+ "509050600082600381111561051657fe5b14610535575060408051602081019091526000" +
+ "81529092509050610375565b6000806105428388610493565b9092509050600082600381" +
+ "111561055557fe5b14610577575060408051602081019091526000815290945092506103" +
+ "75915050565b604080516020810190915290815260009890975095505050505050565b60" +
+ "0080836105a757506000905080610375565b838302838582816105b457fe5b04146105c8" +
+ "57506002915060009050610375565b600092509050610375565b60405180602001604052" +
+ "8060008152509056fea165627a7a7230582021d1e96de1a54e5aaf17c19ae397dd393fa0" +
+ "cd21afedd016b0e6d1fb0e4c749600290000000000000000000000000000000000000000" +
+ "000000000000000000000000000000000000000000000000000000000000000000000000" +
+ "02c68af0bb140000";
+
+ // 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC
+ // nonce: 14
+ const mockCDaiDeploymentData =
+ "0x60806040523480156200001157600080fd5b506040516200523c3803806200523c8339" +
+ "81018060405260e08110156200003757600080fd5b815160208301516040840151606085" +
+ "0151608086018051949693959294919392830192916401000000008111156200006e5760" +
+ "0080fd5b820160208101848111156200008257600080fd5b815164010000000081118282" +
+ "01871017156200009d57600080fd5b505092919060200180516401000000008111156200" +
+ "00ba57600080fd5b82016020810184811115620000ce57600080fd5b8151640100000000" +
+ "811182820187101715620000e957600080fd5b5050602090910151600160005560048054" +
+ "6001600160a01b0319163317905560088690559092509050858585858585836200017057" +
+ "6040517f08c379a000000000000000000000000000000000000000000000000000000000" +
+ "81526004018080602001828103825260308152602001806200520c603091396040019150" +
+ "5060405180910390fd5b600062000183876200036460201b60201c565b90508015620001" +
+ "f357604080517f08c379a000000000000000000000000000000000000000000000000000" +
+ "000000815260206004820152601a60248201527f53657474696e6720636f6d7074726f6c" +
+ "6c6572206661696c6564000000000000604482015290519081900360640190fd5b620002" +
+ "03620004f760201b60201c565b600a55670de0b6b3a7640000600b556200022486620004" +
+ "fc602090811b901c565b905080156200027f576040517f08c379a0000000000000000000" +
+ "000000000000000000000000000000000000008152600401808060200182810382526022" +
+ "815260200180620051ea6022913960400191505060405180910390fd5b83516200029490" +
+ "60019060208701906200071e565b508251620002aa9060029060208601906200071e565b" +
+ "50506003555050601280546001600160a01b0319166001600160a01b038c811691909117" +
+ "91829055604080517f18160ddd0000000000000000000000000000000000000000000000" +
+ "0000000000815290519290911694506318160ddd93506004808201935060209291829003" +
+ "018186803b1580156200032857600080fd5b505afa1580156200033d573d6000803e3d60" +
+ "00fd5b505050506040513d60208110156200035457600080fd5b50620007c09750505050" +
+ "50505050565b6004546000906001600160a01b0316331462000396576200038e6001603f" +
+ "620006ae60201b60201c565b9050620004f2565b600654604080517e7e3dd20000000000" +
+ "0000000000000000000000000000000000000000000000815290516001600160a01b0392" +
+ "831692851691627e3dd2916004808301926020929190829003018186803b158015620003" +
+ "f557600080fd5b505afa1580156200040a573d6000803e3d6000fd5b505050506040513d" +
+ "60208110156200042157600080fd5b50516200048f57604080517f08c379a00000000000" +
+ "0000000000000000000000000000000000000000000000815260206004820152601c6024" +
+ "8201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000" +
+ "604482015290519081900360640190fd5b600680546001600160a01b0319166001600160" +
+ "a01b03858116918217909255604080519284168352602083019190915280517f7ac369db" +
+ "d14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190" +
+ "a160005b9150505b919050565b435b90565b60045460009081906001600160a01b031633" +
+ "1462000531576200052860016042620006ae60201b60201c565b915050620004f2565b62" +
+ "000541620004f760201b60201c565b600a54146200055e5762000528600a6041620006ae" +
+ "60201b60201c565b600760009054906101000a90046001600160a01b0316905082600160" +
+ "0160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083" +
+ "038186803b158015620005b057600080fd5b505afa158015620005c5573d6000803e3d60" +
+ "00fd5b505050506040513d6020811015620005dc57600080fd5b50516200064a57604080" +
+ "517f08c379a0000000000000000000000000000000000000000000000000000000008152" +
+ "60206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65" +
+ "642066616c736500000000604482015290519081900360640190fd5b6007805460016001" +
+ "60a01b0319166001600160a01b0385811691821790925560408051928416835260208301" +
+ "9190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d" +
+ "72f9269281900390910190a16000620004ee565b60007f45b96fe442630264581b197e84" +
+ "bbada861235052c5a1aadfff9ea4e40a969aa0836010811115620006de57fe5b83604d81" +
+ "1115620006eb57fe5b604080519283526020830191909152600082820152519081900360" +
+ "600190a18260108111156200071757fe5b9392505050565b828054600181600116156101" +
+ "000203166002900490600052602060002090601f016020900481019282601f1062000761" +
+ "57805160ff191683800117855562000791565b8280016001018555821562000791579182" +
+ "015b828111156200079157825182559160200191906001019062000774565b506200079f" +
+ "929150620007a3565b5090565b620004f991905b808211156200079f5760008155600101" +
+ "620007aa565b614a1a80620007d06000396000f3fe608060405234801561001057600080" +
+ "fd5b506004361061028a5760003560e01c80638f840ddd1161015c578063c37f68e21161" +
+ "00ce578063f3fdb15a11610087578063f3fdb15a14610708578063f5e3c4621461071057" +
+ "8063f851a44014610746578063f8f9da281461074e578063fca7820b14610756578063fe" +
+ "9c44ae146107735761028a565b8063c37f68e214610626578063c5ebeaec146106725780" +
+ "63db006a751461068f578063dd62ed3e146106ac578063e9c714f2146106da578063f2b3" +
+ "abbd146106e25761028a565b8063a9059cbb11610120578063a9059cbb14610586578063" +
+ "aa5af0fd146105b2578063ae9d70b0146105ba578063b2a02ff1146105c2578063b71d1a" +
+ "0c146105f8578063bd6d894d1461061e5761028a565b80638f840ddd1461052b57806395" +
+ "d89b411461053357806395dd91931461053b578063a0712d6814610561578063a6afed95" +
+ "1461057e5761028a565b80633af9e66911610200578063675d972c116101b9578063675d" +
+ "972c146104c85780636c540baf146104d05780636f307dc3146104d857806370a0823114" +
+ "6104e057806373acee9814610506578063852a12e31461050e5761028a565b80633af9e6" +
+ "69146104475780633b1d21a21461046d5780634576b5db1461047557806347bd37181461" +
+ "049b5780635fe3b567146104a3578063601a0bf1146104ab5761028a565b806318160ddd" +
+ "1161025257806318160ddd146103a9578063182df0f5146103b157806323b872dd146103" +
+ "b95780632608f818146103ef578063267822471461041b578063313ce5671461043f5761" +
+ "028a565b806306fdde031461028f578063095ea7b31461030c5780630e7527021461034c" +
+ "578063173b99041461037b57806317bfdfbc14610383575b600080fd5b61029761077b56" +
+ "5b6040805160208082528351818301528351919283929083019185019080838360005b83" +
+ "8110156102d15781810151838201526020016102b9565b50505050905090810190601f16" +
+ "80156102fe5780820380516001836020036101000a031916815260200191505b50925050" +
+ "5060405180910390f35b6103386004803603604081101561032257600080fd5b50600160" +
+ "0160a01b038135169060200135610808565b604080519115158252519081900360200190" +
+ "f35b6103696004803603602081101561036257600080fd5b5035610875565b6040805191" +
+ "8252519081900360200190f35b610369610888565b610369600480360360208110156103" +
+ "9957600080fd5b50356001600160a01b031661088e565b610369610951565b6103696109" +
+ "57565b610338600480360360608110156103cf57600080fd5b506001600160a01b038135" +
+ "811691602081013590911690604001356109bd565b610369600480360360408110156104" +
+ "0557600080fd5b506001600160a01b038135169060200135610a29565b610423610a3c56" +
+ "5b604080516001600160a01b039092168252519081900360200190f35b610369610a4b56" +
+ "5b6103696004803603602081101561045d57600080fd5b50356001600160a01b0316610a" +
+ "51565b610369610abf565b6103696004803603602081101561048b57600080fd5b503560" +
+ "01600160a01b0316610ace565b610369610c23565b610423610c29565b61036960048036" +
+ "0360208110156104c157600080fd5b5035610c38565b610369610cc6565b610369610ccc" +
+ "565b610423610cd2565b610369600480360360208110156104f657600080fd5b50356001" +
+ "600160a01b0316610ce1565b610369610cfc565b61036960048036036020811015610524" +
+ "57600080fd5b5035610db6565b610369610dc1565b610297610dc7565b61036960048036" +
+ "03602081101561055157600080fd5b50356001600160a01b0316610e1f565b6103696004" +
+ "803603602081101561057757600080fd5b5035610e7f565b610369610e8a565b61033860" +
+ "04803603604081101561059c57600080fd5b506001600160a01b03813516906020013561" +
+ "1286565b6103696112f1565b6103696112f7565b610369600480360360608110156105d8" +
+ "57600080fd5b506001600160a01b038135811691602081013590911690604001356115d1" +
+ "565b6103696004803603602081101561060e57600080fd5b50356001600160a01b031661" +
+ "188e565b610369611915565b61064c6004803603602081101561063c57600080fd5b5035" +
+ "6001600160a01b03166119d0565b60408051948552602085019390935283830191909152" +
+ "6060830152519081900360800190f35b6103696004803603602081101561068857600080" +
+ "fd5b5035611a65565b610369600480360360208110156106a557600080fd5b5035611a70" +
+ "565b610369600480360360408110156106c257600080fd5b506001600160a01b03813581" +
+ "16916020013516611a7b565b610369611aa6565b610369600480360360208110156106f8" +
+ "57600080fd5b50356001600160a01b0316611b95565b610423611bcf565b610369600480" +
+ "3603606081101561072657600080fd5b506001600160a01b038135811691602081013591" +
+ "60409091013516611bde565b610423611beb565b610369611bfa565b6103696004803603" +
+ "602081101561076c57600080fd5b5035611cd9565b610338611d13565b60018054604080" +
+ "516020600284861615610100026000190190941693909304601f81018490048402820184" +
+ "0190925281815292918301828280156108005780601f106107d557610100808354040283" +
+ "529160200191610800565b820191906000526020600020905b8154815290600101906020" +
+ "018083116107e357829003601f168201915b505050505081565b33600081815260106020" +
+ "90815260408083206001600160a01b038716808552908352818420869055815186815291" +
+ "51939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200a" +
+ "c8c7c3b925929081900390910190a360019150505b92915050565b600061088082611d18" +
+ "565b90505b919050565b60095481565b60008054600101808255816108a1610e8a565b14" +
+ "6108f65760408051600160e51b62461bcd02815260206004820152601660248201527f61" +
+ "636372756520696e746572657374206661696c6564000000000000000000006044820152" +
+ "90519081900360640190fd5b6108ff83610e1f565b91505b600054811461094b57604080" +
+ "51600160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b" +
+ "595b9d195c995902604482015290519081900360640190fd5b50919050565b600e548156" +
+ "5b6000806000610964611d54565b9092509050600082600381111561097757fe5b146109" +
+ "b657604051600160e51b62461bcd02815260040180806020018281038252603581526020" +
+ "01806149626035913960400191505060405180910390fd5b9150505b90565b6000805460" +
+ "0101808255816109d433878787611e02565b1491505b6000548114610a21576040805160" +
+ "0160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b595b" +
+ "9d195c995902604482015290519081900360640190fd5b509392505050565b6000610a35" +
+ "8383612116565b9392505050565b6005546001600160a01b031681565b60035481565b60" +
+ "00610a5b6146bb565b6040518060200160405280610a6e611915565b90526001600160a0" +
+ "1b0384166000908152600f6020526040812054919250908190610a9a9084906121a6565b" +
+ "90925090506000826003811115610aad57fe5b14610ab757600080fd5b94935050505056" +
+ "5b6000610ac96121fa565b905090565b6004546000906001600160a01b03163314610af6" +
+ "57610aef6001603f61227d565b9050610883565b60065460408051600160e11b623f1ee9" +
+ "02815290516001600160a01b0392831692851691627e3dd2916004808301926020929190" +
+ "829003018186803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d" +
+ "6000fd5b505050506040513d6020811015610b6857600080fd5b5051610bbe5760408051" +
+ "600160e51b62461bcd02815260206004820152601c60248201527f6d61726b6572206d65" +
+ "74686f642072657475726e65642066616c73650000000060448201529051908190036064" +
+ "0190fd5b600680546001600160a01b0319166001600160a01b0385811691821790925560" +
+ "4080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d59896" +
+ "4a77501540ba6751eb0b3decf5870d9281900390910190a160009392505050565b600c54" +
+ "81565b6006546001600160a01b031681565b6000805460010180825581610c4b610e8a56" +
+ "5b90508015610c7157610c69816010811115610c6257fe5b603061227d565b9250506109" +
+ "02565b610c7a846122e3565b925050600054811461094b5760408051600160e51b62461b" +
+ "cd02815260206004820152600a6024820152600160b21b691c994b595b9d195c99590260" +
+ "4482015290519081900360640190fd5b60085481565b600a5481565b6012546001600160" +
+ "a01b031681565b6001600160a01b03166000908152600f602052604090205490565b6000" +
+ "805460010180825581610d0f610e8a565b14610d645760408051600160e51b62461bcd02" +
+ "815260206004820152601660248201527f61636372756520696e74657265737420666169" +
+ "6c656400000000000000000000604482015290519081900360640190fd5b600c54915060" +
+ "00548114610db25760408051600160e51b62461bcd02815260206004820152600a602482" +
+ "0152600160b21b691c994b595b9d195c995902604482015290519081900360640190fd5b" +
+ "5090565b600061088082612467565b600d5481565b600280546040805160206001841615" +
+ "6101000260001901909316849004601f8101849004840282018401909252818152929183" +
+ "01828280156108005780601f106107d55761010080835404028352916020019161080056" +
+ "5b6000806000610e2d846124a4565b90925090506000826003811115610e4057fe5b1461" +
+ "0a3557604051600160e51b62461bcd028152600401808060200182810382526037815260" +
+ "2001806148366037913960400191505060405180910390fd5b600061088082612558565b" +
+ "6000610e946146ce565b6007546001600160a01b03166315f24053610ead6121fa565b60" +
+ "0c54600d546040518463ffffffff1660e01b815260040180848152602001838152602001" +
+ "8281526020019350505050604080518083038186803b158015610ef457600080fd5b505a" +
+ "fa158015610f08573d6000803e3d6000fd5b505050506040513d6040811015610f1e5760" +
+ "0080fd5b50805160209182015160408401819052918301526601c6bf526340001015610f" +
+ "905760408051600160e51b62461bcd02815260206004820152601c60248201527f626f72" +
+ "726f772072617465206973206162737572646c7920686967680000000060448201529051" +
+ "9081900360640190fd5b602081015115610fb357610fab60056002836020015161259356" +
+ "5b9150506109ba565b610fbb6125f9565b60608201819052600a54610fcf91906125fd56" +
+ "5b6080830181905282826003811115610fe357fe5b6003811115610fee57fe5b90525060" +
+ "0090508151600381111561100257fe5b1461100957fe5b61102960405180602001604052" +
+ "8083604001518152508260800151612620565b60a083018190528282600381111561103d" +
+ "57fe5b600381111561104857fe5b905250600090508151600381111561105c57fe5b1461" +
+ "107d57610fab600960068360000151600381111561107857fe5b612593565b61108d8160" +
+ "a00151600c546121a6565b60c08301819052828260038111156110a157fe5b6003811115" +
+ "6110ac57fe5b90525060009050815160038111156110c057fe5b146110dc57610fab6009" +
+ "60018360000151600381111561107857fe5b6110ec8160c00151600c54612688565b60e0" +
+ "83018190528282600381111561110057fe5b600381111561110b57fe5b90525060009050" +
+ "8151600381111561111f57fe5b1461113b57610fab600960048360000151600381111561" +
+ "107857fe5b61115c60405180602001604052806009548152508260c00151600d546126ae" +
+ "565b61010083018190528282600381111561117157fe5b600381111561117c57fe5b9052" +
+ "50600090508151600381111561119057fe5b146111ac57610fab60096005836000015160" +
+ "0381111561107857fe5b6111bf8160a00151600b54600b546126ae565b61012083018190" +
+ "52828260038111156111d457fe5b60038111156111df57fe5b9052506000905081516003" +
+ "8111156111f357fe5b1461120f57610fab600960038360000151600381111561107857fe" +
+ "5b606080820151600a55610120820151600b81905560e0830151600c8190556101008401" +
+ "51600d5560c08401516040805191825260208201939093528083019190915290517f8753" +
+ "52fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9929181900390" +
+ "910190a1600091505090565b600080546001018082558161129d33338787611e02565b14" +
+ "91505b60005481146112ea5760408051600160e51b62461bcd0281526020600482015260" +
+ "0a6024820152600160b21b691c994b595b9d195c99590260448201529051908190036064" +
+ "0190fd5b5092915050565b600b5481565b600080611302610957565b6007549091506000" +
+ "9081906001600160a01b03166315f240536113236121fa565b600c54600d546040518463" +
+ "ffffffff1660e01b81526004018084815260200183815260200182815260200193505050" +
+ "50604080518083038186803b15801561136a57600080fd5b505afa15801561137e573d60" +
+ "00803e3d6000fd5b505050506040513d604081101561139457600080fd5b508051602090" +
+ "910151909250905081156113e257604051600160e51b62461bcd02815260040180806020" +
+ "01828103825260318152602001806148d56031913960400191505060405180910390fd5b" +
+ "60006113ec6146bb565b611406604051806020016040528087815250600e54612620565b" +
+ "9092509050600082600381111561141957fe5b1461145857604051600160e51b62461bcd" +
+ "02815260040180806020018281038252603181526020018061486d603191396040019150" +
+ "5060405180910390fd5b60006114626146bb565b61146e600c548461270a565b90925090" +
+ "50600082600381111561148157fe5b146114c057604051600160e51b62461bcd02815260" +
+ "04018080602001828103825260318152602001806147b160319139604001915050604051" +
+ "80910390fd5b60006114ca6146bb565b6114fa6040518060200160405280670de0b6b3a7" +
+ "6400008152506040518060200160405280600954815250612769565b9092509050600082" +
+ "600381111561150d57fe5b1461154c57604051600160e51b62461bcd0281526004018080" +
+ "6020018281038252603c815260200180614926603c913960400191505060405180910390" +
+ "fd5b60006115566146bb565b61156f60405180602001604052808b81525084876127a356" +
+ "5b9092509050600082600381111561158257fe5b146115c157604051600160e51b62461b" +
+ "cd0281526004018080602001828103825260318152602001806148056031913960400191" +
+ "505060405180910390fd5b519a505050505050505050505090565b600080546001018082" +
+ "5560065460408051600160e01b63d02f7351028152306004820152336024820152600160" +
+ "0160a01b0388811660448301528781166064830152608482018790529151859392909216" +
+ "9163d02f73519160a48082019260209290919082900301818787803b15801561164a5760" +
+ "0080fd5b505af115801561165e573d6000803e3d6000fd5b505050506040513d60208110" +
+ "1561167457600080fd5b5051905080156116935761168b6003601b83612593565b925050" +
+ "6109d8565b856001600160a01b0316856001600160a01b031614156116b95761168b6006" +
+ "601c61227d565b6001600160a01b0385166000908152600f602052604081205481908190" +
+ "6116e090886125fd565b909350915060008360038111156116f357fe5b14611716576117" +
+ "0b6009601a85600381111561107857fe5b9550505050506109d8565b6001600160a01b03" +
+ "89166000908152600f60205260409020546117399088612688565b909350905060008360" +
+ "0381111561174c57fe5b146117645761170b6009601985600381111561107857fe5b6001" +
+ "600160a01b038089166000818152600f60209081526040808320879055938d1680835291" +
+ "84902085905583518b815293519193600080516020614906833981519152929081900390" +
+ "910190a360065460408051600160e01b636d35bf91028152306004820152336024820152" +
+ "6001600160a01b038c811660448301528b81166064830152608482018b90529151919092" +
+ "1691636d35bf919160a480830192600092919082900301818387803b15801561181e5760" +
+ "0080fd5b505af1158015611832573d6000803e3d6000fd5b506000925061183f91505056" +
+ "5b9550505050506000548114610a215760408051600160e51b62461bcd02815260206004" +
+ "820152600a6024820152600160b21b691c994b595b9d195c995902604482015290519081" +
+ "900360640190fd5b6004546000906001600160a01b031633146118af57610aef60016045" +
+ "61227d565b600580546001600160a01b038481166001600160a01b031983168117909355" +
+ "6040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94" +
+ "012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610a35565b60" +
+ "00805460010180825581611928610e8a565b1461197d5760408051600160e51b62461bcd" +
+ "02815260206004820152601660248201527f61636372756520696e746572657374206661" +
+ "696c656400000000000000000000604482015290519081900360640190fd5b6119856109" +
+ "57565b91506000548114610db25760408051600160e51b62461bcd028152602060048201" +
+ "52600a6024820152600160b21b691c994b595b9d195c9959026044820152905190819003" +
+ "60640190fd5b6001600160a01b0381166000908152600f60205260408120548190819081" +
+ "908180806119fb896124a4565b935090506000816003811115611a0d57fe5b14611a2b57" +
+ "60095b975060009650869550859450611a5e9350505050565b611a33611d54565b925090" +
+ "506000816003811115611a4557fe5b14611a51576009611a15565b506000965091945092" +
+ "5090505b9193509193565b6000610880826127ed565b600061088082612828565b600160" +
+ "0160a01b0391821660009081526010602090815260408083209390941682529190915220" +
+ "5490565b6005546000906001600160a01b031633141580611ac1575033155b15611ad957" +
+ "611ad26001600061227d565b90506109ba565b60048054600580546001600160a01b0380" +
+ "82166001600160a01b031980861682179687905590921690925560408051938316808552" +
+ "949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f" +
+ "21c4e8146d8519b417dc92908290030190a1600554604080516001600160a01b03808516" +
+ "8252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b0" +
+ "93e7720646a95b16a99281900390910190a160009250505090565b600080611ba0610e8a" +
+ "565b90508015611bc657611bbe816010811115611bb757fe5b604061227d565b91505061" +
+ "0883565b610a358361285e565b6007546001600160a01b031681565b6000610ab7848484" +
+ "6129d1565b6004546001600160a01b031681565b600754600090819081906001600160a0" +
+ "1b03166315f24053611c1a6121fa565b600c54600d546040518463ffffffff1660e01b81" +
+ "526004018084815260200183815260200182815260200193505050506040805180830381" +
+ "86803b158015611c6157600080fd5b505afa158015611c75573d6000803e3d6000fd5b50" +
+ "5050506040513d6040811015611c8b57600080fd5b508051602090910151909250905081" +
+ "156109b657604051600160e51b62461bcd02815260040180806020018281038252603781" +
+ "526020018061489e6037913960400191505060405180910390fd5b600080546001018082" +
+ "5581611cec610e8a565b90508015611d0a57610c69816010811115611d0357fe5b604661" +
+ "227d565b610c7a84612adf565b600181565b6000805460010180825581611d2b610e8a56" +
+ "5b90508015611d4957610c69816010811115611d4257fe5b603661227d565b610c7a3333" +
+ "86612b82565b600080600e5460001415611d6f575050600854600090611dfe565b600061" +
+ "1d796121fa565b90506000611d856146bb565b6000611d9684600c54600d54612fde565b" +
+ "935090506000816003811115611da857fe5b14611dbc57945060009350611dfe92505050" +
+ "565b611dc883600e5461301c565b925090506000816003811115611dda57fe5b14611dee" +
+ "57945060009350611dfe92505050565b5051600094509250611dfe915050565b9091565b" +
+ "60065460408051600160e31b6317b9b84b0281523060048201526001600160a01b038681" +
+ "16602483015285811660448301526064820185905291516000938493169163bdcdc25891" +
+ "608480830192602092919082900301818787803b158015611e6a57600080fd5b505af115" +
+ "8015611e7e573d6000803e3d6000fd5b505050506040513d6020811015611e9457600080" +
+ "fd5b505190508015611eb357611eab6003604a83612593565b915050610ab7565b836001" +
+ "600160a01b0316856001600160a01b03161415611ed957611eab6002604b61227d565b60" +
+ "006001600160a01b038781169087161415611ef85750600019611f20565b506001600160" +
+ "a01b038086166000908152601060209081526040808320938a16835292905220545b6000" +
+ "80600080611f3085896125fd565b90945092506000846003811115611f4357fe5b14611f" +
+ "6157611f546009604b61227d565b9650505050505050610ab7565b6001600160a01b038a" +
+ "166000908152600f6020526040902054611f8490896125fd565b90945091506000846003" +
+ "811115611f9757fe5b14611fa857611f546009604c61227d565b6001600160a01b038916" +
+ "6000908152600f6020526040902054611fcb9089612688565b9094509050600084600381" +
+ "1115611fde57fe5b14611fef57611f546009604d61227d565b6001600160a01b03808b16" +
+ "6000908152600f6020526040808220859055918b16815220819055600019851461204757" +
+ "6001600160a01b03808b166000908152601060209081526040808320938f168352929052" +
+ "208390555b886001600160a01b03168a6001600160a01b03166000805160206149068339" +
+ "815191528a6040518082815260200191505060405180910390a360065460408051600160" +
+ "e11b63352b4a3f0281523060048201526001600160a01b038d811660248301528c811660" +
+ "44830152606482018c905291519190921691636a56947e91608480830192600092919082" +
+ "900301818387803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d" +
+ "6000fd5b5060009250612107915050565b9b9a5050505050505050505050565b60008054" +
+ "60010180825581612129610e8a565b9050801561214f5761214781601081111561214057" +
+ "fe5b603561227d565b9250506112a1565b61215a338686612b82565b9250506000548114" +
+ "6112ea5760408051600160e51b62461bcd02815260206004820152600a60248201526001" +
+ "60b21b691c994b595b9d195c995902604482015290519081900360640190fd5b60008060" +
+ "006121b36146bb565b6121bd8686612620565b909250905060008260038111156121d057" +
+ "fe5b146121e157509150600090506121f3565b60006121ec826130cc565b935093505050" +
+ "5b9250929050565b60125460408051600160e01b6370a082310281523060048201529051" +
+ "6000926001600160a01b03169182916370a0823191602480820192602092909190829003" +
+ "018186803b15801561224b57600080fd5b505afa15801561225f573d6000803e3d6000fd" +
+ "5b505050506040513d602081101561227557600080fd5b505191505090565b60007f45b9" +
+ "6fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836010811115" +
+ "6122ac57fe5b83604d8111156122b857fe5b604080519283526020830191909152600082" +
+ "820152519081900360600190a1826010811115610a3557fe5b6004546000908190819060" +
+ "01600160a01b03163314612311576123086001603161227d565b92505050610883565b61" +
+ "23196125f9565b600a541461232d57612308600a603361227d565b836123366121fa565b" +
+ "101561234857612308600e603261227d565b600d5484111561235e576123086002603461" +
+ "227d565b50600d54838103908111156123a757604051600160e51b62461bcd0281526004" +
+ "018080602001828103825260248152602001806149cb6024913960400191505060405180" +
+ "910390fd5b600d8190556004546123c2906001600160a01b0316856130db565b91506000" +
+ "8260108111156123d257fe5b1461241157604051600160e51b62461bcd02815260040180" +
+ "80602001828103825260238152602001806147e260239139604001915050604051809103" +
+ "90fd5b600454604080516001600160a01b03909216825260208201869052818101839052" +
+ "517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e9181" +
+ "900360600190a16000949350505050565b600080546001018082558161247a610e8a565b" +
+ "9050801561249857610c6981601081111561249157fe5b602761227d565b610c7a336000" +
+ "8661319a565b6001600160a01b0381166000908152601160205260408120805482918291" +
+ "829182916124db57506000945084935061255392505050565b6124eb8160000154600b54" +
+ "6136af565b909450925060008460038111156124fe57fe5b146125135750919350600092" +
+ "50612553915050565b6125218382600101546136ee565b90945091506000846003811115" +
+ "61253457fe5b14612549575091935060009250612553915050565b506000945092505050" +
+ "5b915091565b600080546001018082558161256b610e8a565b9050801561258957610c69" +
+ "81601081111561258257fe5b601e61227d565b610c7a3385613719565b60007f45b96fe4" +
+ "42630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156125" +
+ "c257fe5b84604d8111156125ce57fe5b6040805192835260208301919091528181018590" +
+ "52519081900360600190a1836010811115610ab757fe5b4390565b600080838311612614" +
+ "5750600090508183036121f3565b506003905060006121f3565b600061262a6146bb565b" +
+ "60008061263b8660000151866136af565b9092509050600082600381111561264e57fe5b" +
+ "1461266d575060408051602081019091526000815290925090506121f3565b6040805160" +
+ "2081019091529081526000969095509350505050565b6000808383018481106126a05760" +
+ "00925090506121f3565b5060029150600090506121f3565b60008060006126bb6146bb56" +
+ "5b6126c58787612620565b909250905060008260038111156126d857fe5b146126e95750" +
+ "915060009050612702565b6126fb6126f5826130cc565b86612688565b9350935050505b" +
+ "935093915050565b60006127146146bb565b600080612729670de0b6b3a7640000876136" +
+ "af565b9092509050600082600381111561273c57fe5b1461275b57506040805160208101" +
+ "9091526000815290925090506121f3565b6121ec81866000015161301c565b6000612773" +
+ "6146bb565b600080612788866000015186600001516125fd565b60408051602081019091" +
+ "529081529097909650945050505050565b60006127ad6146bb565b60006127b76146bb56" +
+ "5b6127c18787613b67565b909250905060008260038111156127d457fe5b146127e35790" +
+ "92509050612702565b6126fb8186613b67565b6000805460010180825581612800610e8a" +
+ "565b9050801561281e57610c6981601081111561281757fe5b600861227d565b610c7a33" +
+ "85613c50565b600080546001018082558161283b610e8a565b9050801561285257610c69" +
+ "81601081111561249157fe5b610c7a3385600061319a565b600454600090819060016001" +
+ "60a01b0316331461288157611bbe6001604261227d565b6128896125f9565b600a541461" +
+ "289d57611bbe600a604161227d565b600760009054906101000a90046001600160a01b03" +
+ "169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401" +
+ "60206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d60" +
+ "00803e3d6000fd5b505050506040513d602081101561291857600080fd5b505161296e57" +
+ "60408051600160e51b62461bcd02815260206004820152601c60248201527f6d61726b65" +
+ "72206d6574686f642072657475726e65642066616c736500000000604482015290519081" +
+ "900360640190fd5b600780546001600160a01b0319166001600160a01b03858116918217" +
+ "909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c" +
+ "4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610a35565b60" +
+ "008054600101808255816129e4610e8a565b90508015612a025761168b81601081111561" +
+ "29fb57fe5b600f61227d565b836001600160a01b031663a6afed956040518163ffffffff" +
+ "1660e01b8152600401602060405180830381600087803b158015612a3d57600080fd5b50" +
+ "5af1158015612a51573d6000803e3d6000fd5b505050506040513d6020811015612a6757" +
+ "600080fd5b505190508015612a875761168b816010811115612a8057fe5b601061227d56" +
+ "5b612a9333878787613fbf565b9250506000548114610a215760408051600160e51b6246" +
+ "1bcd02815260206004820152600a6024820152600160b21b691c994b595b9d195c995902" +
+ "604482015290519081900360640190fd5b6004546000906001600160a01b03163314612b" +
+ "0057610aef6001604761227d565b612b086125f9565b600a5414612b1c57610aef600a60" +
+ "4861227d565b670de0b6b3a7640000821115612b3857610aef6002604961227d565b6009" +
+ "805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af50684" +
+ "10ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610a35565b" +
+ "60065460408051600160e11b63120045310281523060048201526001600160a01b038681" +
+ "1660248301528581166044830152606482018590529151600093849316916324008a6291" +
+ "608480830192602092919082900301818787803b158015612bea57600080fd5b505af115" +
+ "8015612bfe573d6000803e3d6000fd5b505050506040513d6020811015612c1457600080" +
+ "fd5b505190508015612c3357612c2b6003603883612593565b915050610a35565b612c3b" +
+ "6125f9565b600a5414612c4f57612c2b600a603961227d565b612c57614728565b600160" +
+ "0160a01b0385166000908152601160205260409020600101546060820152612c81856124" +
+ "a4565b6080830181905260208301826003811115612c9857fe5b6003811115612ca357fe" +
+ "5b9052506000905081602001516003811115612cba57fe5b14612cdf57612cd660096037" +
+ "8360200151600381111561107857fe5b92505050610a35565b600019841415612cf85760" +
+ "808101516040820152612d00565b604081018490525b612d0e8682604001516144b3565b" +
+ "81906010811115612d1b57fe5b90816010811115612d2857fe5b90525060008151601081" +
+ "1115612d3a57fe5b14612d4c578051612cd690603c61227d565b612d5e81608001518260" +
+ "4001516125fd565b60a0830181905260208301826003811115612d7557fe5b6003811115" +
+ "612d8057fe5b9052506000905081602001516003811115612d9757fe5b14612db357612c" +
+ "d66009603a8360200151600381111561107857fe5b612dc3600c5482604001516125fd56" +
+ "5b60c0830181905260208301826003811115612dda57fe5b6003811115612de557fe5b90" +
+ "52506000905081602001516003811115612dfc57fe5b14612e1857612cd66009603b8360" +
+ "200151600381111561107857fe5b612e268682604001516145ea565b8190601081111561" +
+ "2e3357fe5b90816010811115612e4057fe5b905250600081516010811115612e5257fe5b" +
+ "14612ea75760408051600160e51b62461bcd02815260206004820152601f60248201527f" +
+ "726570617920626f72726f77207472616e7366657220696e206661696c65640060448201" +
+ "5290519081900360640190fd5b60a080820180516001600160a01b038089166000818152" +
+ "60116020908152604091829020948555600b5460019095019490945560c0870151600c81" +
+ "90558188015195518251948e168552948401929092528281019490945260608201929092" +
+ "52608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0" +
+ "355478d6f5c362a1929181900390910190a1600654604080830151606084015182516001" +
+ "60e01b631ededc910281523060048201526001600160a01b038b811660248301528a8116" +
+ "6044830152606482019390935260848101919091529151921691631ededc919160a48082" +
+ "019260009290919082900301818387803b158015612fb357600080fd5b505af115801561" +
+ "2fc7573d6000803e3d6000fd5b5060009250612fd4915050565b9695505050505050565b" +
+ "600080600080612fee8787612688565b9092509050600082600381111561300157fe5b14" +
+ "6130125750915060009050612702565b6126fb81866125fd565b60006130266146bb565b" +
+ "60008061303b86670de0b6b3a76400006136af565b909250905060008260038111156130" +
+ "4e57fe5b1461306d575060408051602081019091526000815290925090506121f3565b60" +
+ "008061307a83886136ee565b9092509050600082600381111561308d57fe5b146130af57" +
+ "5060408051602081019091526000815290945092506121f3915050565b60408051602081" +
+ "0190915290815260009890975095505050505050565b51670de0b6b3a764000090049056" +
+ "5b60125460408051600160e01b63a9059cbb0281526001600160a01b0385811660048301" +
+ "5260248201859052915160009392909216918391839163a9059cbb916044808201928692" +
+ "90919082900301818387803b15801561313a57600080fd5b505af115801561314e573d60" +
+ "00803e3d6000fd5b505050503d60008114613168576020811461317257600080fd5b6000" +
+ "19915061317e565b60206000803e60005191505b508061318f5760109250505061086f56" +
+ "5b506000949350505050565b60008215806131a7575081155b6131e557604051600160e5" +
+ "1b62461bcd02815260040180806020018281038252603481526020018061499760349139" +
+ "60400191505060405180910390fd5b6131ed614728565b6131f5611d54565b6040830181" +
+ "90526020830182600381111561320c57fe5b600381111561321757fe5b90525060009050" +
+ "8160200151600381111561322e57fe5b1461324a57612c2b6009602b8360200151600381" +
+ "111561107857fe5b83156132cb5760608101849052604080516020810182529082015181" +
+ "5261327190856121a6565b608083018190526020830182600381111561328857fe5b6003" +
+ "81111561329357fe5b90525060009050816020015160038111156132aa57fe5b146132c6" +
+ "57612c2b600960298360200151600381111561107857fe5b613344565b6132e783604051" +
+ "806020016040528084604001518152506146a4565b606083018190526020830182600381" +
+ "11156132fe57fe5b600381111561330957fe5b9052506000905081602001516003811115" +
+ "61332057fe5b1461333c57612c2b6009602a8360200151600381111561107857fe5b6080" +
+ "81018390525b600654606082015160408051600160e01b63eabe7d910281523060048201" +
+ "526001600160a01b03898116602483015260448201939093529051600093929092169163" +
+ "eabe7d919160648082019260209290919082900301818787803b1580156133ac57600080" +
+ "fd5b505af11580156133c0573d6000803e3d6000fd5b505050506040513d602081101561" +
+ "33d657600080fd5b5051905080156133ed57612cd66003602883612593565b6133f56125" +
+ "f9565b600a541461340957612cd6600a602c61227d565b613419600e5483606001516125" +
+ "fd565b60a084018190526020840182600381111561343057fe5b600381111561343b57fe" +
+ "5b905250600090508260200151600381111561345257fe5b1461346e57612cd66009602e" +
+ "8460200151600381111561107857fe5b6001600160a01b0386166000908152600f602052" +
+ "6040902054606083015161349691906125fd565b60c08401819052602084018260038111" +
+ "156134ad57fe5b60038111156134b857fe5b905250600090508260200151600381111561" +
+ "34cf57fe5b146134eb57612cd66009602d8460200151600381111561107857fe5b816080" +
+ "01516134f86121fa565b101561350a57612cd6600e602f61227d565b6135188683608001" +
+ "516130db565b8290601081111561352557fe5b9081601081111561353257fe5b90525060" +
+ "008251601081111561354457fe5b146135995760408051600160e51b62461bcd02815260" +
+ "206004820152601a60248201527f72656465656d207472616e73666572206f7574206661" +
+ "696c6564000000000000604482015290519081900360640190fd5b60a0820151600e5560" +
+ "c08201516001600160a01b0387166000818152600f602090815260409182902093909355" +
+ "6060850151815190815290513093600080516020614906833981519152928290030190a3" +
+ "6080820151606080840151604080516001600160a01b038b168152602081019490945283" +
+ "810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4" +
+ "ec31a9299281900390910190a16006546080830151606084015160408051600160e01b63" +
+ "51dff9890281523060048201526001600160a01b038b8116602483015260448201949094" +
+ "5260648101929092525191909216916351dff98991608480830192600092919082900301" +
+ "818387803b158015612fb357600080fd5b600080836136c2575060009050806121f3565b" +
+ "838302838582816136cf57fe5b04146136e3575060029150600090506121f3565b600092" +
+ "5090506121f3565b6000808261370257506001905060006121f3565b600083858161370d" +
+ "57fe5b04915091509250929050565b60065460408051600160e01b634ef4c3e102815230" +
+ "60048201526001600160a01b038581166024830152604482018590529151600093849316" +
+ "91634ef4c3e191606480830192602092919082900301818787803b158015613779576000" +
+ "80fd5b505af115801561378d573d6000803e3d6000fd5b505050506040513d6020811015" +
+ "6137a357600080fd5b5051905080156137c2576137ba6003601f83612593565b91505061" +
+ "086f565b6137ca6125f9565b600a54146137de576137ba600a602261227d565b6137e661" +
+ "4766565b6137f085856144b3565b819060108111156137fd57fe5b908160108111156138" +
+ "0a57fe5b90525060008151601081111561381c57fe5b1461383757805161382e90602661" +
+ "227d565b9250505061086f565b61383f611d54565b604083018190526020830182600381" +
+ "111561385657fe5b600381111561386157fe5b9052506000905081602001516003811115" +
+ "61387857fe5b146138945761382e600960218360200151600381111561107857fe5b6138" +
+ "b084604051806020016040528084604001518152506146a4565b60608301819052602083" +
+ "018260038111156138c757fe5b60038111156138d257fe5b905250600090508160200151" +
+ "60038111156138e957fe5b146139055761382e6009602083602001516003811115611078" +
+ "57fe5b613915600e548260600151612688565b6080830181905260208301826003811115" +
+ "61392c57fe5b600381111561393757fe5b90525060009050816020015160038111156139" +
+ "4e57fe5b1461396a5761382e600960248360200151600381111561107857fe5b60016001" +
+ "60a01b0385166000908152600f602052604090205460608201516139929190612688565b" +
+ "60a08301819052602083018260038111156139a957fe5b60038111156139b457fe5b9052" +
+ "5060009050816020015160038111156139cb57fe5b146139e75761382e60096023836020" +
+ "0151600381111561107857fe5b6139f185856145ea565b819060108111156139fe57fe5b" +
+ "90816010811115613a0b57fe5b905250600081516010811115613a1d57fe5b14613a2f57" +
+ "805161382e90602561227d565b6080810151600e5560a08101516001600160a01b038616" +
+ "6000818152600f6020908152604091829020939093556060808501518251938452938301" +
+ "88905282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef" +
+ "26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160" +
+ "a01b0387169130916000805160206149068339815191529181900360200190a360065460" +
+ "6082015160408051600160e01b6341c728b90281523060048201526001600160a01b0389" +
+ "81166024830152604482018990526064820193909352905191909216916341c728b99160" +
+ "8480830192600092919082900301818387803b158015613b3d57600080fd5b505af11580" +
+ "15613b51573d6000803e3d6000fd5b5060009250613b5e915050565b9594505050505056" +
+ "5b6000613b716146bb565b600080613b86866000015186600001516136af565b90925090" +
+ "506000826003811115613b9957fe5b14613bb85750604080516020810190915260008152" +
+ "90925090506121f3565b600080613bcd6706f05b59d3b2000084612688565b9092509050" +
+ "6000826003811115613be057fe5b14613c02575060408051602081019091526000815290" +
+ "945092506121f3915050565b600080613c1783670de0b6b3a76400006136ee565b909250" +
+ "90506000826003811115613c2a57fe5b14613c3157fe5b60408051602081019091529081" +
+ "5260009a909950975050505050505050565b60065460408051600160e21b63368f515302" +
+ "81523060048201526001600160a01b038581166024830152604482018590529151600093" +
+ "8493169163da3d454c91606480830192602092919082900301818787803b158015613cb0" +
+ "57600080fd5b505af1158015613cc4573d6000803e3d6000fd5b505050506040513d6020" +
+ "811015613cda57600080fd5b505190508015613cf1576137ba6003600e83612593565b61" +
+ "3cf96125f9565b600a5414613d0c576137ba600a8061227d565b82613d156121fa565b10" +
+ "15613d27576137ba600e600961227d565b613d2f614780565b613d38856124a4565b6040" +
+ "830181905260208301826003811115613d4f57fe5b6003811115613d5a57fe5b90525060" +
+ "00905081602001516003811115613d7157fe5b14613d8d5761382e600960078360200151" +
+ "600381111561107857fe5b613d9b816040015185612688565b6060830181905260208301" +
+ "826003811115613db257fe5b6003811115613dbd57fe5b90525060009050816020015160" +
+ "03811115613dd457fe5b14613df05761382e6009600c8360200151600381111561107857" +
+ "fe5b613dfc600c5485612688565b6080830181905260208301826003811115613e1357fe" +
+ "5b6003811115613e1e57fe5b9052506000905081602001516003811115613e3557fe5b14" +
+ "613e515761382e6009600b8360200151600381111561107857fe5b613e5b85856130db56" +
+ "5b81906010811115613e6857fe5b90816010811115613e7557fe5b905250600081516010" +
+ "811115613e8757fe5b14613edc5760408051600160e51b62461bcd028152602060048201" +
+ "52601a60248201527f626f72726f77207472616e73666572206f7574206661696c656400" +
+ "0000000000604482015290519081900360640190fd5b606080820180516001600160a01b" +
+ "038816600081815260116020908152604091829020938455600b54600190940193909355" +
+ "608080870151600c819055945182519384529383018a9052828201939093529381019290" +
+ "925291517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab" +
+ "80929181900390910190a160065460408051600160e01b635c7786050281523060048201" +
+ "526001600160a01b0388811660248301526044820188905291519190921691635c778605" +
+ "91606480830192600092919082900301818387803b158015613b3d57600080fd5b600654" +
+ "60408051600160e11b632fe3f38f0281523060048201526001600160a01b038481166024" +
+ "830152878116604483015286811660648301526084820186905291516000938493169163" +
+ "5fc7e71e9160a480830192602092919082900301818787803b15801561402f57600080fd" +
+ "5b505af1158015614043573d6000803e3d6000fd5b505050506040513d60208110156140" +
+ "5957600080fd5b50519050801561407057611eab6003601283612593565b6140786125f9" +
+ "565b600a541461408c57611eab600a601661227d565b6140946125f9565b836001600160" +
+ "a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381" +
+ "86803b1580156140cd57600080fd5b505afa1580156140e1573d6000803e3d6000fd5b50" +
+ "5050506040513d60208110156140f757600080fd5b50511461410a57611eab600a601161" +
+ "227d565b856001600160a01b0316856001600160a01b0316141561413057611eab600660" +
+ "1761227d565b8361414157611eab6007601561227d565b60001984141561415757611eab" +
+ "6007601461227d565b60065460408051600160e01b63c488847b02815230600482015260" +
+ "01600160a01b038681166024830152604482018890528251600094859492169263c48884" +
+ "7b926064808301939192829003018186803b1580156141b457600080fd5b505afa158015" +
+ "6141c8573d6000803e3d6000fd5b505050506040513d60408110156141de57600080fd5b" +
+ "50805160209091015190925090508115614209576141ff6004601384612593565b935050" +
+ "5050610ab7565b846001600160a01b03166370a08231886040518263ffffffff1660e01b" +
+ "815260040180826001600160a01b03166001600160a01b03168152602001915050602060" +
+ "40518083038186803b15801561425f57600080fd5b505afa158015614273573d6000803e" +
+ "3d6000fd5b505050506040513d602081101561428957600080fd5b505181111561429e57" +
+ "6141ff600d601d61227d565b60006142ab898989612b82565b905080156142d4576142c9" +
+ "8160108111156142c257fe5b601861227d565b945050505050610ab7565b604080516001" +
+ "60e01b63b2a02ff10281526001600160a01b038b811660048301528a8116602483015260" +
+ "448201859052915160009289169163b2a02ff19160648083019260209291908290030181" +
+ "8787803b15801561433257600080fd5b505af1158015614346573d6000803e3d6000fd5b" +
+ "505050506040513d602081101561435c57600080fd5b5051905080156143b65760408051" +
+ "600160e51b62461bcd02815260206004820152601460248201527f746f6b656e20736569" +
+ "7a757265206661696c656400000000000000000000000060448201529051908190036064" +
+ "0190fd5b604080516001600160a01b03808d168252808c1660208301528183018b905289" +
+ "1660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a33" +
+ "5ab1e7d6215a4b2484d8bb529181900360a00190a160065460408051600160e01b6347ef" +
+ "3b3b0281523060048201526001600160a01b038a811660248301528d811660448301528c" +
+ "81166064830152608482018c905260a48201879052915191909216916347ef3b3b9160c4" +
+ "80830192600092919082900301818387803b15801561448457600080fd5b505af1158015" +
+ "614498573d6000803e3d6000fd5b50600092506144a5915050565b9a9950505050505050" +
+ "505050565b60125460408051600160e11b636eb1769f0281526001600160a01b03858116" +
+ "6004830152306024830152915160009392909216918491839163dd62ed3e916044808201" +
+ "92602092909190829003018186803b15801561451157600080fd5b505afa158015614525" +
+ "573d6000803e3d6000fd5b505050506040513d602081101561453b57600080fd5b505110" +
+ "1561454d57600c91505061086f565b82816001600160a01b03166370a082318660405182" +
+ "63ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152" +
+ "60200191505060206040518083038186803b1580156145a457600080fd5b505afa158015" +
+ "6145b8573d6000803e3d6000fd5b505050506040513d60208110156145ce57600080fd5b" +
+ "505110156145e057600d91505061086f565b5060009392505050565b6012546040805160" +
+ "0160e01b6323b872dd0281526001600160a01b0385811660048301523060248301526044" +
+ "820185905291516000939290921691839183916323b872dd916064808201928692909190" +
+ "82900301818387803b15801561464f57600080fd5b505af1158015614663573d6000803e" +
+ "3d6000fd5b505050503d6000811461467d576020811461468757600080fd5b6000199150" +
+ "614693565b60206000803e60005191505b508061318f57600f9250505061086f565b6000" +
+ "8060006146b16146bb565b6121bd868661270a565b604051806020016040528060008152" +
+ "5090565b6040805161014081019091528060008152602001600081526020016000815260" +
+ "200160008152602001600081526020016147066146bb565b815260200160008152602001" +
+ "6000815260200160008152602001600081525090565b6040805160e08101909152806000" +
+ "815260200160008152602001600081526020016000815260200160008152602001600081" +
+ "52602001600081525090565b6040805160c0810190915280600081526020016000614706" +
+ "565b6040805160a081019091528060008152602001600081526020016000815260200160" +
+ "00815260200160008152509056fe737570706c7952617465506572426c6f636b3a206361" +
+ "6c63756c6174696e6720626f72726f7773506572206661696c6564726564756365207265" +
+ "736572766573207472616e73666572206f7574206661696c6564737570706c7952617465" +
+ "506572426c6f636b3a2063616c63756c6174696e6720737570706c795261746520666169" +
+ "6c6564626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e63" +
+ "6553746f726564496e7465726e616c206661696c6564737570706c795261746550657242" +
+ "6c6f636b3a2063616c63756c6174696e6720756e6465726c79696e67206661696c656462" +
+ "6f72726f7752617465506572426c6f636b3a20696e746572657374526174654d6f64656c" +
+ "2e626f72726f7752617465206661696c6564737570706c7952617465506572426c6f636b" +
+ "3a2063616c63756c6174696e6720626f72726f7752617465206661696c6564ddf252ad1b" +
+ "e2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef737570706c79526174" +
+ "65506572426c6f636b3a2063616c63756c6174696e67206f6e654d696e75735265736572" +
+ "7665466163746f72206661696c656465786368616e67655261746553746f7265643a2065" +
+ "786368616e67655261746553746f726564496e7465726e616c206661696c65646f6e6520" +
+ "6f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e20" +
+ "6d757374206265207a65726f72656475636520726573657276657320756e657870656374" +
+ "656420756e646572666c6f77a165627a7a72305820ae92d0e3e70b657d01891c7457bc6c" +
+ "8a5ce2401a1a8857f346a2fa9af4627145002953657474696e6720696e74657265737420" +
+ "72617465206d6f64656c206661696c6564496e697469616c2065786368616e6765207261" +
+ "7465206d7573742062652067726561746572207468616e207a65726f2e" +
+ "00000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359" + // dai
+ "0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b" + // troll
+ "000000000000000000000000a1046abfc2598f48c44fb320d281d3f3c0733c9a" + // IRM
+ "000000000000000000000000000000000000000000a56fa5b99019a5c8000000" +
+ "00000000000000000000000000000000000000000000000000000000000000e0" +
+ "0000000000000000000000000000000000000000000000000000000000000120" +
+ "0000000000000000000000000000000000000000000000000000000000000008" +
+ "000000000000000000000000000000000000000000000000000000000000000c" +
+ "436f6d706f756e64204461690000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000004" +
+ "6344414900000000000000000000000000000000000000000000000000000000";
+
+ // 0x39AA39c021dfbaE8faC545936693aC917d5E7563
+ // nonce: 17
+ const mockCUSDCDeploymentData =
+ "0x60806040523480156200001157600080fd5b506040516200523c3803806200523c8339" +
+ "81018060405260e08110156200003757600080fd5b815160208301516040840151606085" +
+ "0151608086018051949693959294919392830192916401000000008111156200006e5760" +
+ "0080fd5b820160208101848111156200008257600080fd5b815164010000000081118282" +
+ "01871017156200009d57600080fd5b505092919060200180516401000000008111156200" +
+ "00ba57600080fd5b82016020810184811115620000ce57600080fd5b8151640100000000" +
+ "811182820187101715620000e957600080fd5b5050602090910151600160005560048054" +
+ "6001600160a01b0319163317905560088690559092509050858585858585836200017057" +
+ "6040517f08c379a000000000000000000000000000000000000000000000000000000000" +
+ "81526004018080602001828103825260308152602001806200520c603091396040019150" +
+ "5060405180910390fd5b600062000183876200036460201b60201c565b90508015620001" +
+ "f357604080517f08c379a000000000000000000000000000000000000000000000000000" +
+ "000000815260206004820152601a60248201527f53657474696e6720636f6d7074726f6c" +
+ "6c6572206661696c6564000000000000604482015290519081900360640190fd5b620002" +
+ "03620004f760201b60201c565b600a55670de0b6b3a7640000600b556200022486620004" +
+ "fc602090811b901c565b905080156200027f576040517f08c379a0000000000000000000" +
+ "000000000000000000000000000000000000008152600401808060200182810382526022" +
+ "815260200180620051ea6022913960400191505060405180910390fd5b83516200029490" +
+ "60019060208701906200071e565b508251620002aa9060029060208601906200071e565b" +
+ "50506003555050601280546001600160a01b0319166001600160a01b038c811691909117" +
+ "91829055604080517f18160ddd0000000000000000000000000000000000000000000000" +
+ "0000000000815290519290911694506318160ddd93506004808201935060209291829003" +
+ "018186803b1580156200032857600080fd5b505afa1580156200033d573d6000803e3d60" +
+ "00fd5b505050506040513d60208110156200035457600080fd5b50620007c09750505050" +
+ "50505050565b6004546000906001600160a01b0316331462000396576200038e6001603f" +
+ "620006ae60201b60201c565b9050620004f2565b600654604080517e7e3dd20000000000" +
+ "0000000000000000000000000000000000000000000000815290516001600160a01b0392" +
+ "831692851691627e3dd2916004808301926020929190829003018186803b158015620003" +
+ "f557600080fd5b505afa1580156200040a573d6000803e3d6000fd5b505050506040513d" +
+ "60208110156200042157600080fd5b50516200048f57604080517f08c379a00000000000" +
+ "0000000000000000000000000000000000000000000000815260206004820152601c6024" +
+ "8201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000" +
+ "604482015290519081900360640190fd5b600680546001600160a01b0319166001600160" +
+ "a01b03858116918217909255604080519284168352602083019190915280517f7ac369db" +
+ "d14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190" +
+ "a160005b9150505b919050565b435b90565b60045460009081906001600160a01b031633" +
+ "1462000531576200052860016042620006ae60201b60201c565b915050620004f2565b62" +
+ "000541620004f760201b60201c565b600a54146200055e5762000528600a6041620006ae" +
+ "60201b60201c565b600760009054906101000a90046001600160a01b0316905082600160" +
+ "0160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083" +
+ "038186803b158015620005b057600080fd5b505afa158015620005c5573d6000803e3d60" +
+ "00fd5b505050506040513d6020811015620005dc57600080fd5b50516200064a57604080" +
+ "517f08c379a0000000000000000000000000000000000000000000000000000000008152" +
+ "60206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65" +
+ "642066616c736500000000604482015290519081900360640190fd5b6007805460016001" +
+ "60a01b0319166001600160a01b0385811691821790925560408051928416835260208301" +
+ "9190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d" +
+ "72f9269281900390910190a16000620004ee565b60007f45b96fe442630264581b197e84" +
+ "bbada861235052c5a1aadfff9ea4e40a969aa0836010811115620006de57fe5b83604d81" +
+ "1115620006eb57fe5b604080519283526020830191909152600082820152519081900360" +
+ "600190a18260108111156200071757fe5b9392505050565b828054600181600116156101" +
+ "000203166002900490600052602060002090601f016020900481019282601f1062000761" +
+ "57805160ff191683800117855562000791565b8280016001018555821562000791579182" +
+ "015b828111156200079157825182559160200191906001019062000774565b506200079f" +
+ "929150620007a3565b5090565b620004f991905b808211156200079f5760008155600101" +
+ "620007aa565b614a1a80620007d06000396000f3fe608060405234801561001057600080" +
+ "fd5b506004361061028a5760003560e01c80638f840ddd1161015c578063c37f68e21161" +
+ "00ce578063f3fdb15a11610087578063f3fdb15a14610708578063f5e3c4621461071057" +
+ "8063f851a44014610746578063f8f9da281461074e578063fca7820b14610756578063fe" +
+ "9c44ae146107735761028a565b8063c37f68e214610626578063c5ebeaec146106725780" +
+ "63db006a751461068f578063dd62ed3e146106ac578063e9c714f2146106da578063f2b3" +
+ "abbd146106e25761028a565b8063a9059cbb11610120578063a9059cbb14610586578063" +
+ "aa5af0fd146105b2578063ae9d70b0146105ba578063b2a02ff1146105c2578063b71d1a" +
+ "0c146105f8578063bd6d894d1461061e5761028a565b80638f840ddd1461052b57806395" +
+ "d89b411461053357806395dd91931461053b578063a0712d6814610561578063a6afed95" +
+ "1461057e5761028a565b80633af9e66911610200578063675d972c116101b9578063675d" +
+ "972c146104c85780636c540baf146104d05780636f307dc3146104d857806370a0823114" +
+ "6104e057806373acee9814610506578063852a12e31461050e5761028a565b80633af9e6" +
+ "69146104475780633b1d21a21461046d5780634576b5db1461047557806347bd37181461" +
+ "049b5780635fe3b567146104a3578063601a0bf1146104ab5761028a565b806318160ddd" +
+ "1161025257806318160ddd146103a9578063182df0f5146103b157806323b872dd146103" +
+ "b95780632608f818146103ef578063267822471461041b578063313ce5671461043f5761" +
+ "028a565b806306fdde031461028f578063095ea7b31461030c5780630e7527021461034c" +
+ "578063173b99041461037b57806317bfdfbc14610383575b600080fd5b61029761077b56" +
+ "5b6040805160208082528351818301528351919283929083019185019080838360005b83" +
+ "8110156102d15781810151838201526020016102b9565b50505050905090810190601f16" +
+ "80156102fe5780820380516001836020036101000a031916815260200191505b50925050" +
+ "5060405180910390f35b6103386004803603604081101561032257600080fd5b50600160" +
+ "0160a01b038135169060200135610808565b604080519115158252519081900360200190" +
+ "f35b6103696004803603602081101561036257600080fd5b5035610875565b6040805191" +
+ "8252519081900360200190f35b610369610888565b610369600480360360208110156103" +
+ "9957600080fd5b50356001600160a01b031661088e565b610369610951565b6103696109" +
+ "57565b610338600480360360608110156103cf57600080fd5b506001600160a01b038135" +
+ "811691602081013590911690604001356109bd565b610369600480360360408110156104" +
+ "0557600080fd5b506001600160a01b038135169060200135610a29565b610423610a3c56" +
+ "5b604080516001600160a01b039092168252519081900360200190f35b610369610a4b56" +
+ "5b6103696004803603602081101561045d57600080fd5b50356001600160a01b0316610a" +
+ "51565b610369610abf565b6103696004803603602081101561048b57600080fd5b503560" +
+ "01600160a01b0316610ace565b610369610c23565b610423610c29565b61036960048036" +
+ "0360208110156104c157600080fd5b5035610c38565b610369610cc6565b610369610ccc" +
+ "565b610423610cd2565b610369600480360360208110156104f657600080fd5b50356001" +
+ "600160a01b0316610ce1565b610369610cfc565b61036960048036036020811015610524" +
+ "57600080fd5b5035610db6565b610369610dc1565b610297610dc7565b61036960048036" +
+ "03602081101561055157600080fd5b50356001600160a01b0316610e1f565b6103696004" +
+ "803603602081101561057757600080fd5b5035610e7f565b610369610e8a565b61033860" +
+ "04803603604081101561059c57600080fd5b506001600160a01b03813516906020013561" +
+ "1286565b6103696112f1565b6103696112f7565b610369600480360360608110156105d8" +
+ "57600080fd5b506001600160a01b038135811691602081013590911690604001356115d1" +
+ "565b6103696004803603602081101561060e57600080fd5b50356001600160a01b031661" +
+ "188e565b610369611915565b61064c6004803603602081101561063c57600080fd5b5035" +
+ "6001600160a01b03166119d0565b60408051948552602085019390935283830191909152" +
+ "6060830152519081900360800190f35b6103696004803603602081101561068857600080" +
+ "fd5b5035611a65565b610369600480360360208110156106a557600080fd5b5035611a70" +
+ "565b610369600480360360408110156106c257600080fd5b506001600160a01b03813581" +
+ "16916020013516611a7b565b610369611aa6565b610369600480360360208110156106f8" +
+ "57600080fd5b50356001600160a01b0316611b95565b610423611bcf565b610369600480" +
+ "3603606081101561072657600080fd5b506001600160a01b038135811691602081013591" +
+ "60409091013516611bde565b610423611beb565b610369611bfa565b6103696004803603" +
+ "602081101561076c57600080fd5b5035611cd9565b610338611d13565b60018054604080" +
+ "516020600284861615610100026000190190941693909304601f81018490048402820184" +
+ "0190925281815292918301828280156108005780601f106107d557610100808354040283" +
+ "529160200191610800565b820191906000526020600020905b8154815290600101906020" +
+ "018083116107e357829003601f168201915b505050505081565b33600081815260106020" +
+ "90815260408083206001600160a01b038716808552908352818420869055815186815291" +
+ "51939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200a" +
+ "c8c7c3b925929081900390910190a360019150505b92915050565b600061088082611d18" +
+ "565b90505b919050565b60095481565b60008054600101808255816108a1610e8a565b14" +
+ "6108f65760408051600160e51b62461bcd02815260206004820152601660248201527f61" +
+ "636372756520696e746572657374206661696c6564000000000000000000006044820152" +
+ "90519081900360640190fd5b6108ff83610e1f565b91505b600054811461094b57604080" +
+ "51600160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b" +
+ "595b9d195c995902604482015290519081900360640190fd5b50919050565b600e548156" +
+ "5b6000806000610964611d54565b9092509050600082600381111561097757fe5b146109" +
+ "b657604051600160e51b62461bcd02815260040180806020018281038252603581526020" +
+ "01806149626035913960400191505060405180910390fd5b9150505b90565b6000805460" +
+ "0101808255816109d433878787611e02565b1491505b6000548114610a21576040805160" +
+ "0160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b595b" +
+ "9d195c995902604482015290519081900360640190fd5b509392505050565b6000610a35" +
+ "8383612116565b9392505050565b6005546001600160a01b031681565b60035481565b60" +
+ "00610a5b6146bb565b6040518060200160405280610a6e611915565b90526001600160a0" +
+ "1b0384166000908152600f6020526040812054919250908190610a9a9084906121a6565b" +
+ "90925090506000826003811115610aad57fe5b14610ab757600080fd5b94935050505056" +
+ "5b6000610ac96121fa565b905090565b6004546000906001600160a01b03163314610af6" +
+ "57610aef6001603f61227d565b9050610883565b60065460408051600160e11b623f1ee9" +
+ "02815290516001600160a01b0392831692851691627e3dd2916004808301926020929190" +
+ "829003018186803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d" +
+ "6000fd5b505050506040513d6020811015610b6857600080fd5b5051610bbe5760408051" +
+ "600160e51b62461bcd02815260206004820152601c60248201527f6d61726b6572206d65" +
+ "74686f642072657475726e65642066616c73650000000060448201529051908190036064" +
+ "0190fd5b600680546001600160a01b0319166001600160a01b0385811691821790925560" +
+ "4080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d59896" +
+ "4a77501540ba6751eb0b3decf5870d9281900390910190a160009392505050565b600c54" +
+ "81565b6006546001600160a01b031681565b6000805460010180825581610c4b610e8a56" +
+ "5b90508015610c7157610c69816010811115610c6257fe5b603061227d565b9250506109" +
+ "02565b610c7a846122e3565b925050600054811461094b5760408051600160e51b62461b" +
+ "cd02815260206004820152600a6024820152600160b21b691c994b595b9d195c99590260" +
+ "4482015290519081900360640190fd5b60085481565b600a5481565b6012546001600160" +
+ "a01b031681565b6001600160a01b03166000908152600f602052604090205490565b6000" +
+ "805460010180825581610d0f610e8a565b14610d645760408051600160e51b62461bcd02" +
+ "815260206004820152601660248201527f61636372756520696e74657265737420666169" +
+ "6c656400000000000000000000604482015290519081900360640190fd5b600c54915060" +
+ "00548114610db25760408051600160e51b62461bcd02815260206004820152600a602482" +
+ "0152600160b21b691c994b595b9d195c995902604482015290519081900360640190fd5b" +
+ "5090565b600061088082612467565b600d5481565b600280546040805160206001841615" +
+ "6101000260001901909316849004601f8101849004840282018401909252818152929183" +
+ "01828280156108005780601f106107d55761010080835404028352916020019161080056" +
+ "5b6000806000610e2d846124a4565b90925090506000826003811115610e4057fe5b1461" +
+ "0a3557604051600160e51b62461bcd028152600401808060200182810382526037815260" +
+ "2001806148366037913960400191505060405180910390fd5b600061088082612558565b" +
+ "6000610e946146ce565b6007546001600160a01b03166315f24053610ead6121fa565b60" +
+ "0c54600d546040518463ffffffff1660e01b815260040180848152602001838152602001" +
+ "8281526020019350505050604080518083038186803b158015610ef457600080fd5b505a" +
+ "fa158015610f08573d6000803e3d6000fd5b505050506040513d6040811015610f1e5760" +
+ "0080fd5b50805160209182015160408401819052918301526601c6bf526340001015610f" +
+ "905760408051600160e51b62461bcd02815260206004820152601c60248201527f626f72" +
+ "726f772072617465206973206162737572646c7920686967680000000060448201529051" +
+ "9081900360640190fd5b602081015115610fb357610fab60056002836020015161259356" +
+ "5b9150506109ba565b610fbb6125f9565b60608201819052600a54610fcf91906125fd56" +
+ "5b6080830181905282826003811115610fe357fe5b6003811115610fee57fe5b90525060" +
+ "0090508151600381111561100257fe5b1461100957fe5b61102960405180602001604052" +
+ "8083604001518152508260800151612620565b60a083018190528282600381111561103d" +
+ "57fe5b600381111561104857fe5b905250600090508151600381111561105c57fe5b1461" +
+ "107d57610fab600960068360000151600381111561107857fe5b612593565b61108d8160" +
+ "a00151600c546121a6565b60c08301819052828260038111156110a157fe5b6003811115" +
+ "6110ac57fe5b90525060009050815160038111156110c057fe5b146110dc57610fab6009" +
+ "60018360000151600381111561107857fe5b6110ec8160c00151600c54612688565b60e0" +
+ "83018190528282600381111561110057fe5b600381111561110b57fe5b90525060009050" +
+ "8151600381111561111f57fe5b1461113b57610fab600960048360000151600381111561" +
+ "107857fe5b61115c60405180602001604052806009548152508260c00151600d546126ae" +
+ "565b61010083018190528282600381111561117157fe5b600381111561117c57fe5b9052" +
+ "50600090508151600381111561119057fe5b146111ac57610fab60096005836000015160" +
+ "0381111561107857fe5b6111bf8160a00151600b54600b546126ae565b61012083018190" +
+ "52828260038111156111d457fe5b60038111156111df57fe5b9052506000905081516003" +
+ "8111156111f357fe5b1461120f57610fab600960038360000151600381111561107857fe" +
+ "5b606080820151600a55610120820151600b81905560e0830151600c8190556101008401" +
+ "51600d5560c08401516040805191825260208201939093528083019190915290517f8753" +
+ "52fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9929181900390" +
+ "910190a1600091505090565b600080546001018082558161129d33338787611e02565b14" +
+ "91505b60005481146112ea5760408051600160e51b62461bcd0281526020600482015260" +
+ "0a6024820152600160b21b691c994b595b9d195c99590260448201529051908190036064" +
+ "0190fd5b5092915050565b600b5481565b600080611302610957565b6007549091506000" +
+ "9081906001600160a01b03166315f240536113236121fa565b600c54600d546040518463" +
+ "ffffffff1660e01b81526004018084815260200183815260200182815260200193505050" +
+ "50604080518083038186803b15801561136a57600080fd5b505afa15801561137e573d60" +
+ "00803e3d6000fd5b505050506040513d604081101561139457600080fd5b508051602090" +
+ "910151909250905081156113e257604051600160e51b62461bcd02815260040180806020" +
+ "01828103825260318152602001806148d56031913960400191505060405180910390fd5b" +
+ "60006113ec6146bb565b611406604051806020016040528087815250600e54612620565b" +
+ "9092509050600082600381111561141957fe5b1461145857604051600160e51b62461bcd" +
+ "02815260040180806020018281038252603181526020018061486d603191396040019150" +
+ "5060405180910390fd5b60006114626146bb565b61146e600c548461270a565b90925090" +
+ "50600082600381111561148157fe5b146114c057604051600160e51b62461bcd02815260" +
+ "04018080602001828103825260318152602001806147b160319139604001915050604051" +
+ "80910390fd5b60006114ca6146bb565b6114fa6040518060200160405280670de0b6b3a7" +
+ "6400008152506040518060200160405280600954815250612769565b9092509050600082" +
+ "600381111561150d57fe5b1461154c57604051600160e51b62461bcd0281526004018080" +
+ "6020018281038252603c815260200180614926603c913960400191505060405180910390" +
+ "fd5b60006115566146bb565b61156f60405180602001604052808b81525084876127a356" +
+ "5b9092509050600082600381111561158257fe5b146115c157604051600160e51b62461b" +
+ "cd0281526004018080602001828103825260318152602001806148056031913960400191" +
+ "505060405180910390fd5b519a505050505050505050505090565b600080546001018082" +
+ "5560065460408051600160e01b63d02f7351028152306004820152336024820152600160" +
+ "0160a01b0388811660448301528781166064830152608482018790529151859392909216" +
+ "9163d02f73519160a48082019260209290919082900301818787803b15801561164a5760" +
+ "0080fd5b505af115801561165e573d6000803e3d6000fd5b505050506040513d60208110" +
+ "1561167457600080fd5b5051905080156116935761168b6003601b83612593565b925050" +
+ "6109d8565b856001600160a01b0316856001600160a01b031614156116b95761168b6006" +
+ "601c61227d565b6001600160a01b0385166000908152600f602052604081205481908190" +
+ "6116e090886125fd565b909350915060008360038111156116f357fe5b14611716576117" +
+ "0b6009601a85600381111561107857fe5b9550505050506109d8565b6001600160a01b03" +
+ "89166000908152600f60205260409020546117399088612688565b909350905060008360" +
+ "0381111561174c57fe5b146117645761170b6009601985600381111561107857fe5b6001" +
+ "600160a01b038089166000818152600f60209081526040808320879055938d1680835291" +
+ "84902085905583518b815293519193600080516020614906833981519152929081900390" +
+ "910190a360065460408051600160e01b636d35bf91028152306004820152336024820152" +
+ "6001600160a01b038c811660448301528b81166064830152608482018b90529151919092" +
+ "1691636d35bf919160a480830192600092919082900301818387803b15801561181e5760" +
+ "0080fd5b505af1158015611832573d6000803e3d6000fd5b506000925061183f91505056" +
+ "5b9550505050506000548114610a215760408051600160e51b62461bcd02815260206004" +
+ "820152600a6024820152600160b21b691c994b595b9d195c995902604482015290519081" +
+ "900360640190fd5b6004546000906001600160a01b031633146118af57610aef60016045" +
+ "61227d565b600580546001600160a01b038481166001600160a01b031983168117909355" +
+ "6040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94" +
+ "012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610a35565b60" +
+ "00805460010180825581611928610e8a565b1461197d5760408051600160e51b62461bcd" +
+ "02815260206004820152601660248201527f61636372756520696e746572657374206661" +
+ "696c656400000000000000000000604482015290519081900360640190fd5b6119856109" +
+ "57565b91506000548114610db25760408051600160e51b62461bcd028152602060048201" +
+ "52600a6024820152600160b21b691c994b595b9d195c9959026044820152905190819003" +
+ "60640190fd5b6001600160a01b0381166000908152600f60205260408120548190819081" +
+ "908180806119fb896124a4565b935090506000816003811115611a0d57fe5b14611a2b57" +
+ "60095b975060009650869550859450611a5e9350505050565b611a33611d54565b925090" +
+ "506000816003811115611a4557fe5b14611a51576009611a15565b506000965091945092" +
+ "5090505b9193509193565b6000610880826127ed565b600061088082612828565b600160" +
+ "0160a01b0391821660009081526010602090815260408083209390941682529190915220" +
+ "5490565b6005546000906001600160a01b031633141580611ac1575033155b15611ad957" +
+ "611ad26001600061227d565b90506109ba565b60048054600580546001600160a01b0380" +
+ "82166001600160a01b031980861682179687905590921690925560408051938316808552" +
+ "949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f" +
+ "21c4e8146d8519b417dc92908290030190a1600554604080516001600160a01b03808516" +
+ "8252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b0" +
+ "93e7720646a95b16a99281900390910190a160009250505090565b600080611ba0610e8a" +
+ "565b90508015611bc657611bbe816010811115611bb757fe5b604061227d565b91505061" +
+ "0883565b610a358361285e565b6007546001600160a01b031681565b6000610ab7848484" +
+ "6129d1565b6004546001600160a01b031681565b600754600090819081906001600160a0" +
+ "1b03166315f24053611c1a6121fa565b600c54600d546040518463ffffffff1660e01b81" +
+ "526004018084815260200183815260200182815260200193505050506040805180830381" +
+ "86803b158015611c6157600080fd5b505afa158015611c75573d6000803e3d6000fd5b50" +
+ "5050506040513d6040811015611c8b57600080fd5b508051602090910151909250905081" +
+ "156109b657604051600160e51b62461bcd02815260040180806020018281038252603781" +
+ "526020018061489e6037913960400191505060405180910390fd5b600080546001018082" +
+ "5581611cec610e8a565b90508015611d0a57610c69816010811115611d0357fe5b604661" +
+ "227d565b610c7a84612adf565b600181565b6000805460010180825581611d2b610e8a56" +
+ "5b90508015611d4957610c69816010811115611d4257fe5b603661227d565b610c7a3333" +
+ "86612b82565b600080600e5460001415611d6f575050600854600090611dfe565b600061" +
+ "1d796121fa565b90506000611d856146bb565b6000611d9684600c54600d54612fde565b" +
+ "935090506000816003811115611da857fe5b14611dbc57945060009350611dfe92505050" +
+ "565b611dc883600e5461301c565b925090506000816003811115611dda57fe5b14611dee" +
+ "57945060009350611dfe92505050565b5051600094509250611dfe915050565b9091565b" +
+ "60065460408051600160e31b6317b9b84b0281523060048201526001600160a01b038681" +
+ "16602483015285811660448301526064820185905291516000938493169163bdcdc25891" +
+ "608480830192602092919082900301818787803b158015611e6a57600080fd5b505af115" +
+ "8015611e7e573d6000803e3d6000fd5b505050506040513d6020811015611e9457600080" +
+ "fd5b505190508015611eb357611eab6003604a83612593565b915050610ab7565b836001" +
+ "600160a01b0316856001600160a01b03161415611ed957611eab6002604b61227d565b60" +
+ "006001600160a01b038781169087161415611ef85750600019611f20565b506001600160" +
+ "a01b038086166000908152601060209081526040808320938a16835292905220545b6000" +
+ "80600080611f3085896125fd565b90945092506000846003811115611f4357fe5b14611f" +
+ "6157611f546009604b61227d565b9650505050505050610ab7565b6001600160a01b038a" +
+ "166000908152600f6020526040902054611f8490896125fd565b90945091506000846003" +
+ "811115611f9757fe5b14611fa857611f546009604c61227d565b6001600160a01b038916" +
+ "6000908152600f6020526040902054611fcb9089612688565b9094509050600084600381" +
+ "1115611fde57fe5b14611fef57611f546009604d61227d565b6001600160a01b03808b16" +
+ "6000908152600f6020526040808220859055918b16815220819055600019851461204757" +
+ "6001600160a01b03808b166000908152601060209081526040808320938f168352929052" +
+ "208390555b886001600160a01b03168a6001600160a01b03166000805160206149068339" +
+ "815191528a6040518082815260200191505060405180910390a360065460408051600160" +
+ "e11b63352b4a3f0281523060048201526001600160a01b038d811660248301528c811660" +
+ "44830152606482018c905291519190921691636a56947e91608480830192600092919082" +
+ "900301818387803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d" +
+ "6000fd5b5060009250612107915050565b9b9a5050505050505050505050565b60008054" +
+ "60010180825581612129610e8a565b9050801561214f5761214781601081111561214057" +
+ "fe5b603561227d565b9250506112a1565b61215a338686612b82565b9250506000548114" +
+ "6112ea5760408051600160e51b62461bcd02815260206004820152600a60248201526001" +
+ "60b21b691c994b595b9d195c995902604482015290519081900360640190fd5b60008060" +
+ "006121b36146bb565b6121bd8686612620565b909250905060008260038111156121d057" +
+ "fe5b146121e157509150600090506121f3565b60006121ec826130cc565b935093505050" +
+ "5b9250929050565b60125460408051600160e01b6370a082310281523060048201529051" +
+ "6000926001600160a01b03169182916370a0823191602480820192602092909190829003" +
+ "018186803b15801561224b57600080fd5b505afa15801561225f573d6000803e3d6000fd" +
+ "5b505050506040513d602081101561227557600080fd5b505191505090565b60007f45b9" +
+ "6fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836010811115" +
+ "6122ac57fe5b83604d8111156122b857fe5b604080519283526020830191909152600082" +
+ "820152519081900360600190a1826010811115610a3557fe5b6004546000908190819060" +
+ "01600160a01b03163314612311576123086001603161227d565b92505050610883565b61" +
+ "23196125f9565b600a541461232d57612308600a603361227d565b836123366121fa565b" +
+ "101561234857612308600e603261227d565b600d5484111561235e576123086002603461" +
+ "227d565b50600d54838103908111156123a757604051600160e51b62461bcd0281526004" +
+ "018080602001828103825260248152602001806149cb6024913960400191505060405180" +
+ "910390fd5b600d8190556004546123c2906001600160a01b0316856130db565b91506000" +
+ "8260108111156123d257fe5b1461241157604051600160e51b62461bcd02815260040180" +
+ "80602001828103825260238152602001806147e260239139604001915050604051809103" +
+ "90fd5b600454604080516001600160a01b03909216825260208201869052818101839052" +
+ "517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e9181" +
+ "900360600190a16000949350505050565b600080546001018082558161247a610e8a565b" +
+ "9050801561249857610c6981601081111561249157fe5b602761227d565b610c7a336000" +
+ "8661319a565b6001600160a01b0381166000908152601160205260408120805482918291" +
+ "829182916124db57506000945084935061255392505050565b6124eb8160000154600b54" +
+ "6136af565b909450925060008460038111156124fe57fe5b146125135750919350600092" +
+ "50612553915050565b6125218382600101546136ee565b90945091506000846003811115" +
+ "61253457fe5b14612549575091935060009250612553915050565b506000945092505050" +
+ "5b915091565b600080546001018082558161256b610e8a565b9050801561258957610c69" +
+ "81601081111561258257fe5b601e61227d565b610c7a3385613719565b60007f45b96fe4" +
+ "42630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156125" +
+ "c257fe5b84604d8111156125ce57fe5b6040805192835260208301919091528181018590" +
+ "52519081900360600190a1836010811115610ab757fe5b4390565b600080838311612614" +
+ "5750600090508183036121f3565b506003905060006121f3565b600061262a6146bb565b" +
+ "60008061263b8660000151866136af565b9092509050600082600381111561264e57fe5b" +
+ "1461266d575060408051602081019091526000815290925090506121f3565b6040805160" +
+ "2081019091529081526000969095509350505050565b6000808383018481106126a05760" +
+ "00925090506121f3565b5060029150600090506121f3565b60008060006126bb6146bb56" +
+ "5b6126c58787612620565b909250905060008260038111156126d857fe5b146126e95750" +
+ "915060009050612702565b6126fb6126f5826130cc565b86612688565b9350935050505b" +
+ "935093915050565b60006127146146bb565b600080612729670de0b6b3a7640000876136" +
+ "af565b9092509050600082600381111561273c57fe5b1461275b57506040805160208101" +
+ "9091526000815290925090506121f3565b6121ec81866000015161301c565b6000612773" +
+ "6146bb565b600080612788866000015186600001516125fd565b60408051602081019091" +
+ "529081529097909650945050505050565b60006127ad6146bb565b60006127b76146bb56" +
+ "5b6127c18787613b67565b909250905060008260038111156127d457fe5b146127e35790" +
+ "92509050612702565b6126fb8186613b67565b6000805460010180825581612800610e8a" +
+ "565b9050801561281e57610c6981601081111561281757fe5b600861227d565b610c7a33" +
+ "85613c50565b600080546001018082558161283b610e8a565b9050801561285257610c69" +
+ "81601081111561249157fe5b610c7a3385600061319a565b600454600090819060016001" +
+ "60a01b0316331461288157611bbe6001604261227d565b6128896125f9565b600a541461" +
+ "289d57611bbe600a604161227d565b600760009054906101000a90046001600160a01b03" +
+ "169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401" +
+ "60206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d60" +
+ "00803e3d6000fd5b505050506040513d602081101561291857600080fd5b505161296e57" +
+ "60408051600160e51b62461bcd02815260206004820152601c60248201527f6d61726b65" +
+ "72206d6574686f642072657475726e65642066616c736500000000604482015290519081" +
+ "900360640190fd5b600780546001600160a01b0319166001600160a01b03858116918217" +
+ "909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c" +
+ "4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610a35565b60" +
+ "008054600101808255816129e4610e8a565b90508015612a025761168b81601081111561" +
+ "29fb57fe5b600f61227d565b836001600160a01b031663a6afed956040518163ffffffff" +
+ "1660e01b8152600401602060405180830381600087803b158015612a3d57600080fd5b50" +
+ "5af1158015612a51573d6000803e3d6000fd5b505050506040513d6020811015612a6757" +
+ "600080fd5b505190508015612a875761168b816010811115612a8057fe5b601061227d56" +
+ "5b612a9333878787613fbf565b9250506000548114610a215760408051600160e51b6246" +
+ "1bcd02815260206004820152600a6024820152600160b21b691c994b595b9d195c995902" +
+ "604482015290519081900360640190fd5b6004546000906001600160a01b03163314612b" +
+ "0057610aef6001604761227d565b612b086125f9565b600a5414612b1c57610aef600a60" +
+ "4861227d565b670de0b6b3a7640000821115612b3857610aef6002604961227d565b6009" +
+ "805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af50684" +
+ "10ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610a35565b" +
+ "60065460408051600160e11b63120045310281523060048201526001600160a01b038681" +
+ "1660248301528581166044830152606482018590529151600093849316916324008a6291" +
+ "608480830192602092919082900301818787803b158015612bea57600080fd5b505af115" +
+ "8015612bfe573d6000803e3d6000fd5b505050506040513d6020811015612c1457600080" +
+ "fd5b505190508015612c3357612c2b6003603883612593565b915050610a35565b612c3b" +
+ "6125f9565b600a5414612c4f57612c2b600a603961227d565b612c57614728565b600160" +
+ "0160a01b0385166000908152601160205260409020600101546060820152612c81856124" +
+ "a4565b6080830181905260208301826003811115612c9857fe5b6003811115612ca357fe" +
+ "5b9052506000905081602001516003811115612cba57fe5b14612cdf57612cd660096037" +
+ "8360200151600381111561107857fe5b92505050610a35565b600019841415612cf85760" +
+ "808101516040820152612d00565b604081018490525b612d0e8682604001516144b3565b" +
+ "81906010811115612d1b57fe5b90816010811115612d2857fe5b90525060008151601081" +
+ "1115612d3a57fe5b14612d4c578051612cd690603c61227d565b612d5e81608001518260" +
+ "4001516125fd565b60a0830181905260208301826003811115612d7557fe5b6003811115" +
+ "612d8057fe5b9052506000905081602001516003811115612d9757fe5b14612db357612c" +
+ "d66009603a8360200151600381111561107857fe5b612dc3600c5482604001516125fd56" +
+ "5b60c0830181905260208301826003811115612dda57fe5b6003811115612de557fe5b90" +
+ "52506000905081602001516003811115612dfc57fe5b14612e1857612cd66009603b8360" +
+ "200151600381111561107857fe5b612e268682604001516145ea565b8190601081111561" +
+ "2e3357fe5b90816010811115612e4057fe5b905250600081516010811115612e5257fe5b" +
+ "14612ea75760408051600160e51b62461bcd02815260206004820152601f60248201527f" +
+ "726570617920626f72726f77207472616e7366657220696e206661696c65640060448201" +
+ "5290519081900360640190fd5b60a080820180516001600160a01b038089166000818152" +
+ "60116020908152604091829020948555600b5460019095019490945560c0870151600c81" +
+ "90558188015195518251948e168552948401929092528281019490945260608201929092" +
+ "52608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0" +
+ "355478d6f5c362a1929181900390910190a1600654604080830151606084015182516001" +
+ "60e01b631ededc910281523060048201526001600160a01b038b811660248301528a8116" +
+ "6044830152606482019390935260848101919091529151921691631ededc919160a48082" +
+ "019260009290919082900301818387803b158015612fb357600080fd5b505af115801561" +
+ "2fc7573d6000803e3d6000fd5b5060009250612fd4915050565b9695505050505050565b" +
+ "600080600080612fee8787612688565b9092509050600082600381111561300157fe5b14" +
+ "6130125750915060009050612702565b6126fb81866125fd565b60006130266146bb565b" +
+ "60008061303b86670de0b6b3a76400006136af565b909250905060008260038111156130" +
+ "4e57fe5b1461306d575060408051602081019091526000815290925090506121f3565b60" +
+ "008061307a83886136ee565b9092509050600082600381111561308d57fe5b146130af57" +
+ "5060408051602081019091526000815290945092506121f3915050565b60408051602081" +
+ "0190915290815260009890975095505050505050565b51670de0b6b3a764000090049056" +
+ "5b60125460408051600160e01b63a9059cbb0281526001600160a01b0385811660048301" +
+ "5260248201859052915160009392909216918391839163a9059cbb916044808201928692" +
+ "90919082900301818387803b15801561313a57600080fd5b505af115801561314e573d60" +
+ "00803e3d6000fd5b505050503d60008114613168576020811461317257600080fd5b6000" +
+ "19915061317e565b60206000803e60005191505b508061318f5760109250505061086f56" +
+ "5b506000949350505050565b60008215806131a7575081155b6131e557604051600160e5" +
+ "1b62461bcd02815260040180806020018281038252603481526020018061499760349139" +
+ "60400191505060405180910390fd5b6131ed614728565b6131f5611d54565b6040830181" +
+ "90526020830182600381111561320c57fe5b600381111561321757fe5b90525060009050" +
+ "8160200151600381111561322e57fe5b1461324a57612c2b6009602b8360200151600381" +
+ "111561107857fe5b83156132cb5760608101849052604080516020810182529082015181" +
+ "5261327190856121a6565b608083018190526020830182600381111561328857fe5b6003" +
+ "81111561329357fe5b90525060009050816020015160038111156132aa57fe5b146132c6" +
+ "57612c2b600960298360200151600381111561107857fe5b613344565b6132e783604051" +
+ "806020016040528084604001518152506146a4565b606083018190526020830182600381" +
+ "11156132fe57fe5b600381111561330957fe5b9052506000905081602001516003811115" +
+ "61332057fe5b1461333c57612c2b6009602a8360200151600381111561107857fe5b6080" +
+ "81018390525b600654606082015160408051600160e01b63eabe7d910281523060048201" +
+ "526001600160a01b03898116602483015260448201939093529051600093929092169163" +
+ "eabe7d919160648082019260209290919082900301818787803b1580156133ac57600080" +
+ "fd5b505af11580156133c0573d6000803e3d6000fd5b505050506040513d602081101561" +
+ "33d657600080fd5b5051905080156133ed57612cd66003602883612593565b6133f56125" +
+ "f9565b600a541461340957612cd6600a602c61227d565b613419600e5483606001516125" +
+ "fd565b60a084018190526020840182600381111561343057fe5b600381111561343b57fe" +
+ "5b905250600090508260200151600381111561345257fe5b1461346e57612cd66009602e" +
+ "8460200151600381111561107857fe5b6001600160a01b0386166000908152600f602052" +
+ "6040902054606083015161349691906125fd565b60c08401819052602084018260038111" +
+ "156134ad57fe5b60038111156134b857fe5b905250600090508260200151600381111561" +
+ "34cf57fe5b146134eb57612cd66009602d8460200151600381111561107857fe5b816080" +
+ "01516134f86121fa565b101561350a57612cd6600e602f61227d565b6135188683608001" +
+ "516130db565b8290601081111561352557fe5b9081601081111561353257fe5b90525060" +
+ "008251601081111561354457fe5b146135995760408051600160e51b62461bcd02815260" +
+ "206004820152601a60248201527f72656465656d207472616e73666572206f7574206661" +
+ "696c6564000000000000604482015290519081900360640190fd5b60a0820151600e5560" +
+ "c08201516001600160a01b0387166000818152600f602090815260409182902093909355" +
+ "6060850151815190815290513093600080516020614906833981519152928290030190a3" +
+ "6080820151606080840151604080516001600160a01b038b168152602081019490945283" +
+ "810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4" +
+ "ec31a9299281900390910190a16006546080830151606084015160408051600160e01b63" +
+ "51dff9890281523060048201526001600160a01b038b8116602483015260448201949094" +
+ "5260648101929092525191909216916351dff98991608480830192600092919082900301" +
+ "818387803b158015612fb357600080fd5b600080836136c2575060009050806121f3565b" +
+ "838302838582816136cf57fe5b04146136e3575060029150600090506121f3565b600092" +
+ "5090506121f3565b6000808261370257506001905060006121f3565b600083858161370d" +
+ "57fe5b04915091509250929050565b60065460408051600160e01b634ef4c3e102815230" +
+ "60048201526001600160a01b038581166024830152604482018590529151600093849316" +
+ "91634ef4c3e191606480830192602092919082900301818787803b158015613779576000" +
+ "80fd5b505af115801561378d573d6000803e3d6000fd5b505050506040513d6020811015" +
+ "6137a357600080fd5b5051905080156137c2576137ba6003601f83612593565b91505061" +
+ "086f565b6137ca6125f9565b600a54146137de576137ba600a602261227d565b6137e661" +
+ "4766565b6137f085856144b3565b819060108111156137fd57fe5b908160108111156138" +
+ "0a57fe5b90525060008151601081111561381c57fe5b1461383757805161382e90602661" +
+ "227d565b9250505061086f565b61383f611d54565b604083018190526020830182600381" +
+ "111561385657fe5b600381111561386157fe5b9052506000905081602001516003811115" +
+ "61387857fe5b146138945761382e600960218360200151600381111561107857fe5b6138" +
+ "b084604051806020016040528084604001518152506146a4565b60608301819052602083" +
+ "018260038111156138c757fe5b60038111156138d257fe5b905250600090508160200151" +
+ "60038111156138e957fe5b146139055761382e6009602083602001516003811115611078" +
+ "57fe5b613915600e548260600151612688565b6080830181905260208301826003811115" +
+ "61392c57fe5b600381111561393757fe5b90525060009050816020015160038111156139" +
+ "4e57fe5b1461396a5761382e600960248360200151600381111561107857fe5b60016001" +
+ "60a01b0385166000908152600f602052604090205460608201516139929190612688565b" +
+ "60a08301819052602083018260038111156139a957fe5b60038111156139b457fe5b9052" +
+ "5060009050816020015160038111156139cb57fe5b146139e75761382e60096023836020" +
+ "0151600381111561107857fe5b6139f185856145ea565b819060108111156139fe57fe5b" +
+ "90816010811115613a0b57fe5b905250600081516010811115613a1d57fe5b14613a2f57" +
+ "805161382e90602561227d565b6080810151600e5560a08101516001600160a01b038616" +
+ "6000818152600f6020908152604091829020939093556060808501518251938452938301" +
+ "88905282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef" +
+ "26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160" +
+ "a01b0387169130916000805160206149068339815191529181900360200190a360065460" +
+ "6082015160408051600160e01b6341c728b90281523060048201526001600160a01b0389" +
+ "81166024830152604482018990526064820193909352905191909216916341c728b99160" +
+ "8480830192600092919082900301818387803b158015613b3d57600080fd5b505af11580" +
+ "15613b51573d6000803e3d6000fd5b5060009250613b5e915050565b9594505050505056" +
+ "5b6000613b716146bb565b600080613b86866000015186600001516136af565b90925090" +
+ "506000826003811115613b9957fe5b14613bb85750604080516020810190915260008152" +
+ "90925090506121f3565b600080613bcd6706f05b59d3b2000084612688565b9092509050" +
+ "6000826003811115613be057fe5b14613c02575060408051602081019091526000815290" +
+ "945092506121f3915050565b600080613c1783670de0b6b3a76400006136ee565b909250" +
+ "90506000826003811115613c2a57fe5b14613c3157fe5b60408051602081019091529081" +
+ "5260009a909950975050505050505050565b60065460408051600160e21b63368f515302" +
+ "81523060048201526001600160a01b038581166024830152604482018590529151600093" +
+ "8493169163da3d454c91606480830192602092919082900301818787803b158015613cb0" +
+ "57600080fd5b505af1158015613cc4573d6000803e3d6000fd5b505050506040513d6020" +
+ "811015613cda57600080fd5b505190508015613cf1576137ba6003600e83612593565b61" +
+ "3cf96125f9565b600a5414613d0c576137ba600a8061227d565b82613d156121fa565b10" +
+ "15613d27576137ba600e600961227d565b613d2f614780565b613d38856124a4565b6040" +
+ "830181905260208301826003811115613d4f57fe5b6003811115613d5a57fe5b90525060" +
+ "00905081602001516003811115613d7157fe5b14613d8d5761382e600960078360200151" +
+ "600381111561107857fe5b613d9b816040015185612688565b6060830181905260208301" +
+ "826003811115613db257fe5b6003811115613dbd57fe5b90525060009050816020015160" +
+ "03811115613dd457fe5b14613df05761382e6009600c8360200151600381111561107857" +
+ "fe5b613dfc600c5485612688565b6080830181905260208301826003811115613e1357fe" +
+ "5b6003811115613e1e57fe5b9052506000905081602001516003811115613e3557fe5b14" +
+ "613e515761382e6009600b8360200151600381111561107857fe5b613e5b85856130db56" +
+ "5b81906010811115613e6857fe5b90816010811115613e7557fe5b905250600081516010" +
+ "811115613e8757fe5b14613edc5760408051600160e51b62461bcd028152602060048201" +
+ "52601a60248201527f626f72726f77207472616e73666572206f7574206661696c656400" +
+ "0000000000604482015290519081900360640190fd5b606080820180516001600160a01b" +
+ "038816600081815260116020908152604091829020938455600b54600190940193909355" +
+ "608080870151600c819055945182519384529383018a9052828201939093529381019290" +
+ "925291517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab" +
+ "80929181900390910190a160065460408051600160e01b635c7786050281523060048201" +
+ "526001600160a01b0388811660248301526044820188905291519190921691635c778605" +
+ "91606480830192600092919082900301818387803b158015613b3d57600080fd5b600654" +
+ "60408051600160e11b632fe3f38f0281523060048201526001600160a01b038481166024" +
+ "830152878116604483015286811660648301526084820186905291516000938493169163" +
+ "5fc7e71e9160a480830192602092919082900301818787803b15801561402f57600080fd" +
+ "5b505af1158015614043573d6000803e3d6000fd5b505050506040513d60208110156140" +
+ "5957600080fd5b50519050801561407057611eab6003601283612593565b6140786125f9" +
+ "565b600a541461408c57611eab600a601661227d565b6140946125f9565b836001600160" +
+ "a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381" +
+ "86803b1580156140cd57600080fd5b505afa1580156140e1573d6000803e3d6000fd5b50" +
+ "5050506040513d60208110156140f757600080fd5b50511461410a57611eab600a601161" +
+ "227d565b856001600160a01b0316856001600160a01b0316141561413057611eab600660" +
+ "1761227d565b8361414157611eab6007601561227d565b60001984141561415757611eab" +
+ "6007601461227d565b60065460408051600160e01b63c488847b02815230600482015260" +
+ "01600160a01b038681166024830152604482018890528251600094859492169263c48884" +
+ "7b926064808301939192829003018186803b1580156141b457600080fd5b505afa158015" +
+ "6141c8573d6000803e3d6000fd5b505050506040513d60408110156141de57600080fd5b" +
+ "50805160209091015190925090508115614209576141ff6004601384612593565b935050" +
+ "5050610ab7565b846001600160a01b03166370a08231886040518263ffffffff1660e01b" +
+ "815260040180826001600160a01b03166001600160a01b03168152602001915050602060" +
+ "40518083038186803b15801561425f57600080fd5b505afa158015614273573d6000803e" +
+ "3d6000fd5b505050506040513d602081101561428957600080fd5b505181111561429e57" +
+ "6141ff600d601d61227d565b60006142ab898989612b82565b905080156142d4576142c9" +
+ "8160108111156142c257fe5b601861227d565b945050505050610ab7565b604080516001" +
+ "60e01b63b2a02ff10281526001600160a01b038b811660048301528a8116602483015260" +
+ "448201859052915160009289169163b2a02ff19160648083019260209291908290030181" +
+ "8787803b15801561433257600080fd5b505af1158015614346573d6000803e3d6000fd5b" +
+ "505050506040513d602081101561435c57600080fd5b5051905080156143b65760408051" +
+ "600160e51b62461bcd02815260206004820152601460248201527f746f6b656e20736569" +
+ "7a757265206661696c656400000000000000000000000060448201529051908190036064" +
+ "0190fd5b604080516001600160a01b03808d168252808c1660208301528183018b905289" +
+ "1660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a33" +
+ "5ab1e7d6215a4b2484d8bb529181900360a00190a160065460408051600160e01b6347ef" +
+ "3b3b0281523060048201526001600160a01b038a811660248301528d811660448301528c" +
+ "81166064830152608482018c905260a48201879052915191909216916347ef3b3b9160c4" +
+ "80830192600092919082900301818387803b15801561448457600080fd5b505af1158015" +
+ "614498573d6000803e3d6000fd5b50600092506144a5915050565b9a9950505050505050" +
+ "505050565b60125460408051600160e11b636eb1769f0281526001600160a01b03858116" +
+ "6004830152306024830152915160009392909216918491839163dd62ed3e916044808201" +
+ "92602092909190829003018186803b15801561451157600080fd5b505afa158015614525" +
+ "573d6000803e3d6000fd5b505050506040513d602081101561453b57600080fd5b505110" +
+ "1561454d57600c91505061086f565b82816001600160a01b03166370a082318660405182" +
+ "63ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152" +
+ "60200191505060206040518083038186803b1580156145a457600080fd5b505afa158015" +
+ "6145b8573d6000803e3d6000fd5b505050506040513d60208110156145ce57600080fd5b" +
+ "505110156145e057600d91505061086f565b5060009392505050565b6012546040805160" +
+ "0160e01b6323b872dd0281526001600160a01b0385811660048301523060248301526044" +
+ "820185905291516000939290921691839183916323b872dd916064808201928692909190" +
+ "82900301818387803b15801561464f57600080fd5b505af1158015614663573d6000803e" +
+ "3d6000fd5b505050503d6000811461467d576020811461468757600080fd5b6000199150" +
+ "614693565b60206000803e60005191505b508061318f57600f9250505061086f565b6000" +
+ "8060006146b16146bb565b6121bd868661270a565b604051806020016040528060008152" +
+ "5090565b6040805161014081019091528060008152602001600081526020016000815260" +
+ "200160008152602001600081526020016147066146bb565b815260200160008152602001" +
+ "6000815260200160008152602001600081525090565b6040805160e08101909152806000" +
+ "815260200160008152602001600081526020016000815260200160008152602001600081" +
+ "52602001600081525090565b6040805160c0810190915280600081526020016000614706" +
+ "565b6040805160a081019091528060008152602001600081526020016000815260200160" +
+ "00815260200160008152509056fe737570706c7952617465506572426c6f636b3a206361" +
+ "6c63756c6174696e6720626f72726f7773506572206661696c6564726564756365207265" +
+ "736572766573207472616e73666572206f7574206661696c6564737570706c7952617465" +
+ "506572426c6f636b3a2063616c63756c6174696e6720737570706c795261746520666169" +
+ "6c6564626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e63" +
+ "6553746f726564496e7465726e616c206661696c6564737570706c795261746550657242" +
+ "6c6f636b3a2063616c63756c6174696e6720756e6465726c79696e67206661696c656462" +
+ "6f72726f7752617465506572426c6f636b3a20696e746572657374526174654d6f64656c" +
+ "2e626f72726f7752617465206661696c6564737570706c7952617465506572426c6f636b" +
+ "3a2063616c63756c6174696e6720626f72726f7752617465206661696c6564ddf252ad1b" +
+ "e2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef737570706c79526174" +
+ "65506572426c6f636b3a2063616c63756c6174696e67206f6e654d696e75735265736572" +
+ "7665466163746f72206661696c656465786368616e67655261746553746f7265643a2065" +
+ "786368616e67655261746553746f726564496e7465726e616c206661696c65646f6e6520" +
+ "6f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e20" +
+ "6d757374206265207a65726f72656475636520726573657276657320756e657870656374" +
+ "656420756e646572666c6f77a165627a7a72305820ae92d0e3e70b657d01891c7457bc6c" +
+ "8a5ce2401a1a8857f346a2fa9af4627145002953657474696e6720696e74657265737420" +
+ "72617465206d6f64656c206661696c6564496e697469616c2065786368616e6765207261" +
+ "7465206d7573742062652067726561746572207468616e207a65726f2e" +
+ "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + // usdc
+ "0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b" + // troll
+ "000000000000000000000000c64c4cba055efa614ce01f4bad8a9f519c4f8fab" + // IRM
+ "0000000000000000000000000000000000000000000000000000b5e620f48000" +
+ "00000000000000000000000000000000000000000000000000000000000000e0" +
+ "0000000000000000000000000000000000000000000000000000000000000120" +
+ "0000000000000000000000000000000000000000000000000000000000000008" +
+ "0000000000000000000000000000000000000000000000000000000000000011" +
+ "436f6d706f756e642055534420436f696e000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000005" +
+ "6355534443000000000000000000000000000000000000000000000000000000";
+
+ // ************************** helper functions **************************** //
+ async function send(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ shouldSucceed,
+ assertionCallback
+ ) {
+ const receipt = await instance.methods[method](...args)
+ .send({
+ from: from,
+ value: value,
+ gas: gas,
+ gasPrice: gasPrice
+ })
+ .on("confirmation", (confirmationNumber, r) => {
+ confirmations[r.transactionHash] = confirmationNumber;
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+ return { status: false };
+ });
+
+ if (receipt.status !== shouldSucceed) {
+ return false;
+ } else if (!shouldSucceed) {
+ return true;
+ }
+
+ let assertionsPassed;
+ try {
+ assertionCallback(receipt);
+ assertionsPassed = true;
+ } catch (error) {
+ assertionsPassed = false;
+ console.log(error);
+ }
+
+ return assertionsPassed;
}
- ],
- "name": "redeemAllowed",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
+
+ async function call(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ shouldSucceed,
+ assertionCallback
+ ) {
+ let succeeded = true;
+ returnValues = await instance.methods[method](...args)
+ .call({
+ from: from,
+ value: value,
+ gas: gas,
+ gasPrice: gasPrice
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+ succeeded = false;
+ });
+
+ if (succeeded !== shouldSucceed) {
+ return false;
+ } else if (!shouldSucceed) {
+ return true;
+ }
+
+ let assertionsPassed;
+ try {
+ assertionCallback(returnValues);
+ assertionsPassed = true;
+ } catch (error) {
+ assertionsPassed = false;
+ console.log(error);
+ }
+
+ return assertionsPassed;
}
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "cTokenAddress",
- "type": "address"
+
+ async function deploy(
+ title,
+ instance,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ shouldSucceed,
+ assertionCallback
+ ) {
+ let deployData = instance.deploy({ arguments: args }).encodeABI();
+ let deployGas = await web3.eth
+ .estimateGas({
+ from: from,
+ data: deployData
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+ return gasLimit;
+ });
+
+ if (deployGas > gasLimit) {
+ console.error(
+ ` ✘ ${title}: deployment costs exceed block gas limit!`
+ );
+ process.exit(1);
+ }
+
+ if (typeof gas === "undefined") {
+ gas = deployGas;
+ }
+
+ if (deployGas > gas) {
+ console.error(
+ ` ✘ ${title}: deployment costs exceed supplied gas.`
+ );
+ process.exit(1);
+ }
+
+ let signed;
+ let deployHash;
+ let receipt;
+ const contract = await instance
+ .deploy({ arguments: args })
+ .send({
+ from: from,
+ gas: gas,
+ gasPrice: gasPrice
+ })
+ .on("transactionHash", hash => {
+ deployHash = hash;
+ })
+ .on("receipt", r => {
+ receipt = r;
+ })
+ .on("confirmation", (confirmationNumber, r) => {
+ confirmations[r.transactionHash] = confirmationNumber;
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+
+ receipt = { status: false };
+ });
+
+ if (receipt.status !== shouldSucceed) {
+ if (contract) {
+ return [false, contract, gas];
+ }
+ return [false, instance, gas];
+ } else if (!shouldSucceed) {
+ if (contract) {
+ return [true, contract, gas];
+ }
+ return [true, instance, gas];
+ }
+
+ assert.ok(receipt.status);
+
+ let assertionsPassed;
+ try {
+ assertionCallback(receipt);
+ assertionsPassed = true;
+ } catch (error) {
+ assertionsPassed = false;
+ }
+
+ if (contract) {
+ return [assertionsPassed, contract, gas];
+ }
+ return [assertionsPassed, instance, gas];
}
- ],
- "name": "exitMarket",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
+
+ async function runTest(
+ title,
+ instance,
+ method,
+ callOrSend,
+ args,
+ shouldSucceed,
+ assertionCallback,
+ from,
+ value,
+ gas
+ ) {
+ if (typeof callOrSend === "undefined") {
+ callOrSend = "send";
+ }
+ if (typeof args === "undefined") {
+ args = [];
+ }
+ if (typeof shouldSucceed === "undefined") {
+ shouldSucceed = true;
+ }
+ if (typeof assertionCallback === "undefined") {
+ assertionCallback = value => {};
+ }
+ if (typeof from === "undefined") {
+ from = address;
+ }
+ if (typeof value === "undefined") {
+ value = 0;
+ }
+ if (typeof gas === "undefined" && callOrSend !== "deploy") {
+ gas = 6009006;
+ if (testingContext === "coverage") {
+ gas = gasLimit - 1;
+ }
+ }
+ let ok = false;
+ let contract;
+ let deployGas;
+ if (callOrSend === "send") {
+ ok = await send(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback
+ );
+ } else if (callOrSend === "call") {
+ ok = await call(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback
+ );
+ } else if (callOrSend === "deploy") {
+ const fields = await deploy(
+ title,
+ instance,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback
+ );
+ ok = fields[0];
+ contract = fields[1];
+ deployGas = fields[2];
+ } else {
+ console.error("must use call, send, or deploy!");
+ process.exit(1);
+ }
+
+ if (ok) {
+ console.log(
+ ` ✓ ${
+ callOrSend === "deploy" ? "successful " : ""
+ }${title}${
+ callOrSend === "deploy" ? ` (${deployGas} gas)` : ""
+ }`
+ );
+ passed++;
+ } else {
+ console.log(
+ ` ✘ ${callOrSend === "deploy" ? "failed " : ""}${title}${
+ callOrSend === "deploy" ? ` (${deployGas} gas)` : ""
+ }`
+ );
+ failed++;
+ }
+
+ if (contract) {
+ return contract;
+ }
}
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
-
- ],
- "name": "admin",
- "outputs": [
- {
- "name": "",
- "type": "address"
+
+ async function setupNewDefaultAddress(newPrivateKey) {
+ const pubKey = await web3.eth.accounts.privateKeyToAccount(
+ newPrivateKey
+ );
+ await web3.eth.accounts.wallet.add(pubKey);
+
+ const txCount = await web3.eth.getTransactionCount(pubKey.address);
+
+ if (txCount > 0) {
+ console.warn(
+ `warning: ${
+ pubKey.address
+ } has already been used, which may cause ` +
+ "some tests to fail or to be skipped."
+ );
+ }
+
+ await web3.eth.sendTransaction({
+ from: originalAddress,
+ to: pubKey.address,
+ value: 10 ** 18,
+ gas: "0x5208",
+ gasPrice: "0x4A817C800"
+ });
+
+ return pubKey.address;
}
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
-
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "constructor"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "cToken",
- "type": "address"
+
+ // *************************** deploy contracts *************************** //
+ const currentSaiCode = await web3.eth.getCode(
+ constants.SAI_MAINNET_ADDRESS
+ );
+ if (currentSaiCode !== "0x") {
+ console.log("contracts already set up, skipping...");
+ return 0;
}
- ],
- "name": "MarketListed",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "cToken",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "account",
- "type": "address"
+
+ console.log("funding mcd deployer address...");
+ await web3.eth.sendTransaction({
+ from: originalAddress,
+ to: "0xb5b06a16621616875A6C2637948bF98eA57c58fa",
+ value: web3.utils.toWei("0.1", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : gasLimit - 1,
+ gasPrice: 1
+ });
+
+ 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
+ });
+
+ console.log("funding dai deployer address...");
+ await web3.eth.sendTransaction({
+ from: originalAddress,
+ to: "0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9",
+ value: web3.utils.toWei("10", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : gasLimit - 1,
+ gasPrice: 1
+ });
+
+ console.log("funding usdc deployer address...");
+ await web3.eth.sendTransaction({
+ from: originalAddress,
+ to: "0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911",
+ value: web3.utils.toWei("10", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : gasLimit - 1,
+ gasPrice: 1
+ });
+
+ console.log("funding Compound deployer address...");
+ await web3.eth.sendTransaction({
+ from: originalAddress,
+ to: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ value: web3.utils.toWei("10", "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
+ });
+
+ assert.strictEqual(
+ priceOracleDeployReceipt.contractAddress,
+ "0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14"
+ );
+
+ console.log("incrementing dai deployment nonce...");
+ let daiDeployReceipt;
+ for (i = 0; i < 1; i++) {
+ daiDeployReceipt = await web3.eth.sendTransaction({
+ from: "0xb5b06a16621616875A6C2637948bF98eA57c58fa",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "MarketEntered",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "cToken",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "account",
- "type": "address"
+
+ 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,
+ constants.DAI_MAINNET_ADDRESS
+ );
+
+ 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"
+ });
}
- ],
- "name": "MarketExited",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldCloseFactorMantissa",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "newCloseFactorMantissa",
- "type": "uint256"
+
+ console.log("deploying mock Sai...");
+ saiDeployReceipt = await web3.eth.sendTransaction({
+ from: "0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockDaiDeploymentData
+ });
+
+ assert.strictEqual(
+ 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);
}
- ],
- "name": "NewCloseFactor",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "cToken",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "oldCollateralFactorMantissa",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "newCollateralFactorMantissa",
- "type": "uint256"
+
+ 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,
+ "transfer",
+ "send",
+ [
+ constants.DAI_WHALE_ADDRESS,
+ "8555083659983933209597798445644913612440610624038028786991485007418559037440"
+ ],
+ true,
+ receipt => {},
+ "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,
+ "transfer",
+ "send",
+ [
+ constants.SAI_WHALE_ADDRESS,
+ "8555083659983933209597798445644913612440610624038028786991485007418559037440"
+ ],
+ true,
+ receipt => {},
+ "0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9"
+ );
+
+ await runTest(
+ "Transfer Dai to primary address",
+ SAI,
+ "transfer",
+ "send",
+ [
+ address,
+ "1000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ true,
+ receipt => {},
+ "0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9"
+ );
+
+ await runTest(
+ "Dai totalSupply is reachable",
+ SAI,
+ "totalSupply",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ "108555083659983933209597798445644913612440610624038028786991485007418559037440"
+ );
+ }
+ );
+
+ console.log("incrementing usdc deployment nonce...");
+ let usdcDeployReceipt;
+ for (i = 0; i < 20; i++) {
+ usdcDeployReceipt = await web3.eth.sendTransaction({
+ from: "0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "NewCollateralFactor",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldLiquidationIncentiveMantissa",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "newLiquidationIncentiveMantissa",
- "type": "uint256"
+
+ console.log("deploying mock USDC...");
+ usdcDeployReceipt = await web3.eth.sendTransaction({
+ from: "0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911",
+ gas: testingContext !== "coverage" ? "4000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockUSDCDeploymentData
+ });
+
+ assert.strictEqual(
+ usdcDeployReceipt.contractAddress,
+ constants.USDC_MAINNET_ADDRESS
+ );
+
+ await runTest("initialize USDC", FIAT_TOKEN, "initialize", "send", [
+ "USD//C",
+ "USDC",
+ "USD",
+ 6,
+ address,
+ address,
+ address,
+ address
+ ]);
+
+ await runTest(
+ "add USDC minter",
+ FIAT_TOKEN,
+ "configureMinter",
+ "send",
+ [
+ address,
+ "0xf000000000000000000000000000000000000000000000000000000000000000"
+ ]
+ );
+
+ await runTest(
+ "Mint USDC to whale address",
+ FIAT_TOKEN,
+ "mint",
+ "send",
+ [
+ constants.USDC_WHALE_ADDRESS,
+ "8555083659983933209597798445644913612440610624038028786991485007418559037440"
+ ]
+ );
+
+ await runTest(
+ "Mint USDC to primary address",
+ FIAT_TOKEN,
+ "mint",
+ "send",
+ [
+ address,
+ "100000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ]
+ );
+
+ await runTest(
+ "USDC totalSupply is reachable",
+ USDC,
+ "totalSupply",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ "108555083659983933209597798445644913612440610624038028786991485007418559037440"
+ );
+ }
+ );
+
+ await runTest(
+ "blacklist a USDC address",
+ FIAT_TOKEN,
+ "blacklist",
+ "send",
+ [constants.MOCK_USDC_BLACKLISTED_ADDRESS]
+ );
+
+ console.log("deploying Compound unitroller...");
+ const unitrollerDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockUnitrollerDeploymentData
+ });
+
+ assert.strictEqual(
+ unitrollerDeploymentReceipt.contractAddress,
+ constants.COMPTROLLER_MAINNET_ADDRESS
+ );
+
+ console.log("deploying v0 Compound comptroller...");
+ let comptrollerDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "5000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCurrentComptrollerDeploymentData
+ });
+
+ let COMPTROLLER = new web3.eth.Contract(
+ COMPTROLLER_ABI,
+ comptrollerDeploymentReceipt.contractAddress
+ );
+
+ const UNITROLLER_COMPTROLLER = new web3.eth.Contract(
+ COMPTROLLER_ABI,
+ UNITROLLER.options.address
+ );
+
+ await runTest(
+ "Set pending Comptroller on Unitroller",
+ UNITROLLER,
+ "_setPendingImplementation",
+ "send",
+ [COMPTROLLER.options.address],
+ true,
+ receipt => {},
+ "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6"
+ );
+
+ await runTest(
+ "Set Comptroller on Unitroller",
+ COMPTROLLER,
+ "_become",
+ "send",
+ [
+ UNITROLLER.options.address,
+ priceOracleDeployReceipt.contractAddress,
+ "500000000000000000",
+ 20,
+ false
+ ],
+ true,
+ receipt => {},
+ "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6"
+ );
+
+ await runTest(
+ "comptroller implementation is set correctly",
+ UNITROLLER,
+ "comptrollerImplementation",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, COMPTROLLER.options.address);
+ }
+ );
+
+ console.log("incrementing Compound deployment nonce...");
+ let compoundDeployReceipt;
+ for (i = 4; i < 7; i++) {
+ compoundDeployReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "NewLiquidationIncentive",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldMaxAssets",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "newMaxAssets",
- "type": "uint256"
+
+ console.log("deploying Compound cSAI IRM...");
+ const cSAIIRMDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCDaiIRMDeploymentData
+ });
+
+ assert.strictEqual(
+ cSAIIRMDeploymentReceipt.contractAddress,
+ "0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a"
+ );
+
+ console.log("deploying Compound cUSDC IRM...");
+ const cUSDCIRMDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCUSDCIRMDeploymentData
+ });
+
+ assert.strictEqual(
+ cUSDCIRMDeploymentReceipt.contractAddress,
+ "0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB"
+ );
+
+ console.log("incrementing Compound deployment nonce...");
+ for (i = 9; i < 14; i++) {
+ compoundDeployReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "NewMaxAssets",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "oldPriceOracle",
- "type": "address"
- },
- {
- "indexed": false,
- "name": "newPriceOracle",
- "type": "address"
+
+ console.log("deploying Compound cSai...");
+ const cSaiDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "7000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCDaiDeploymentData
+ });
+
+ assert.strictEqual(
+ cSaiDeploymentReceipt.contractAddress,
+ constants.CSAI_MAINNET_ADDRESS
+ );
+
+ for (i = 15; i < 17; i++) {
+ compoundDeployReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "NewPriceOracle",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": false,
- "name": "error",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "info",
- "type": "uint256"
- },
- {
- "indexed": false,
- "name": "detail",
- "type": "uint256"
+
+ console.log("deploying Compound cUSDC...");
+ const cUSDCDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "7000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCUSDCDeploymentData
+ });
+
+ assert.strictEqual(
+ cUSDCDeploymentReceipt.contractAddress,
+ constants.CUSDC_MAINNET_ADDRESS
+ );
+
+ for (i = 18; i < 68; i++) {
+ compoundDeployReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "1000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: "0x3838533838f3"
+ });
}
- ],
- "name": "Failure",
- "type": "event"
- }
- ]
-
- // get available addresses and assign them to various roles
- const addresses = await web3.eth.getAccounts()
- if (addresses.length < 1) {
- console.log('cannot find enough addresses to run tests!')
- process.exit(1)
- }
-
- let latestBlock = await web3.eth.getBlock('latest')
-
- const originalAddress = addresses[0]
-
- let address = await setupNewDefaultAddress(
- '0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed'
- )
-
- let addressTwo = await setupNewDefaultAddress(
- '0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d'
- )
-
- const gasLimit = latestBlock.gasLimit
-
- // 0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14
- // primary address, nonce: 0
- const mockPriceOracleDeploymentData = (
- '0x608060405234801561001057600080fd5b5060cd8061001f6000396000f3fe60806040' +
- '52348015600f57600080fd5b506004361060325760003560e01c806366331bba14603757' +
- '8063fc57d4df146051575b600080fd5b603d6086565b6040805191151582525190819003' +
- '60200190f35b607460048036036020811015606557600080fd5b50356001600160a01b03' +
- '16608b565b60408051918252519081900360200190f35b600190565b50670de0b6b3a764' +
- '00009056fea265627a7a72315820cf3b4d1c8f3041ebb02fbc6b404dd54636a41af89e8a' +
- '04ea19bf35f04b48fae764736f6c634300050b0032'
- )
-
- // 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
- // nonce: 4
- const mockDaiDeploymentData = (
- '0x608060405234801561001057600080fd5b5060405160208061085d8339810180604052' +
- '810190808051906020019092919050505080600160003373ffffffffffffffffffffffff' +
- 'ffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001' +
- '9081526020016000208190555080600081905550506107cf8061008e6000396000f30060' +
- '8060405260043610610078576000357c0100000000000000000000000000000000000000' +
- '000000000000000000900463ffffffff168063095ea7b31461007d57806318160ddd1461' +
- '00e257806323b872dd1461010d57806370a0823114610192578063a9059cbb146101e957' +
- '8063dd62ed3e1461024e575b600080fd5b34801561008957600080fd5b506100c8600480' +
- '360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092' +
- '9190803590602001909291905050506102c5565b60405180821515151581526020019150' +
- '5060405180910390f35b3480156100ee57600080fd5b506100f76103b7565b6040518082' +
- '815260200191505060405180910390f35b34801561011957600080fd5b50610178600480' +
- '360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092' +
- '9190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035' +
- '90602001909291905050506103c0565b6040518082151515158152602001915050604051' +
- '80910390f35b34801561019e57600080fd5b506101d3600480360381019080803573ffff' +
- 'ffffffffffffffffffffffffffffffffffff169060200190929190505050610686565b60' +
- '40518082815260200191505060405180910390f35b3480156101f557600080fd5b506102' +
- '34600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060' +
- '200190929190803590602001909291905050506106cf565b604051808215151515815260' +
- '200191505060405180910390f35b34801561025a57600080fd5b506102af600480360381' +
- '019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080' +
- '3573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506106' +
- 'e4565b6040518082815260200191505060405180910390f35b600081600260003373ffff' +
- 'ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff' +
- 'ffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffff' +
- 'ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190' +
- '8152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff1633' +
- '73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d' +
- '1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405180828152602001915050604051' +
- '80910390a36001905092915050565b60008054905090565b60003373ffffffffffffffff' +
- 'ffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16' +
- '1415156104fe5761047d600260008673ffffffffffffffffffffffffffffffffffffffff' +
- '1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000' +
- '2060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffff' +
- 'ffffffffffffffffffffff168152602001908152602001600020548361076b565b600260' +
- '008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff' +
- 'ffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffff' +
- 'ffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681' +
- '52602001908152602001600020819055505b610547600160008673ffffffffffffffffff' +
- 'ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152' +
- '602001908152602001600020548361076b565b600160008673ffffffffffffffffffffff' +
- 'ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020' +
- '01908152602001600020819055506105d3600160008573ffffffffffffffffffffffffff' +
- 'ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190' +
- '81526020016000205483610787565b600160008573ffffffffffffffffffffffffffffff' +
- 'ffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152' +
- '602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ff' +
- 'ffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378d' +
- 'aa952ba7f163c4a11628f55a4df523b3ef84604051808281526020019150506040518091' +
- '0390a3600190509392505050565b6000600160008373ffffffffffffffffffffffffffff' +
- 'ffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081' +
- '52602001600020549050919050565b60006106dc3384846103c0565b905092915050565b' +
- '6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff' +
- 'ffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffff' +
- 'ffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffff' +
- 'ffffff16815260200190815260200160002054905092915050565b600082828403915081' +
- '1115151561078157600080fd5b92915050565b6000828284019150811015151561079d57' +
- '600080fd5b929150505600a165627a7a72305820b4ab3c13e840dd08d9787883bde3458d' +
- 'cbab9a56f185c55a59574286095eb6e80029f00000000000000000000000000000000000' +
- '0000000000000000000000000000'
- )
-
- // 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
- // nonce: 20
- const mockUSDCDeploymentData = (
- '0x60806040526000600460146101000a81548160ff021916908315150217905550600060' +
- '0e5561003c33610041640100000000026401000000009004565b610084565b8060008061' +
- '01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff' +
- 'ffffffffffffffffffffffffffffffffff16021790555050565b6135c580620000946000' +
- '396000f3006080604052600436106101a1576000357c0100000000000000000000000000' +
- '000000000000000000000000000000900463ffffffff16806306fdde03146101a6578063' +
- '095ea7b31461023657806318160ddd1461029b5780631a895266146102c657806323b872' +
- 'dd146103095780633092afd51461038e578063313ce567146103e95780633357162b1461' +
- '041a57806335d99f351461059c57806339509351146105f35780633f4ba83a1461065857' +
- '806340c10f191461066f57806342966c68146106d45780634e44d9561461070157806355' +
- '4bab3c146107665780635c975abb146107a957806370a08231146107d85780638456cb59' +
- '1461082f5780638a6db9c3146108465780638da5cb5b1461089d57806395d89b41146108' +
- 'f45780639fd0506d14610984578063a457c2d7146109db578063a9059cbb14610a405780' +
- '63aa20e1e414610aa5578063aa271e1a14610ae8578063ad38bf2214610b43578063bd10' +
- '243014610b86578063dd62ed3e14610bdd578063e5a6b10f14610c54578063f2fde38b14' +
- '610ce4578063f9f92be414610d27578063fe575a8714610d6a575b600080fd5b34801561' +
- '01b257600080fd5b506101bb610dc5565b60405180806020018281038252838181518152' +
- '60200191508051906020019080838360005b838110156101fb5780820151818401526020' +
- '810190506101e0565b50505050905090810190601f168015610228578082038051600183' +
- '6020036101000a031916815260200191505b509250505060405180910390f35b34801561' +
- '024257600080fd5b50610281600480360381019080803573ffffffffffffffffffffffff' +
- 'ffffffffffffffff16906020019092919080359060200190929190505050610e63565b60' +
- '4051808215151515815260200191505060405180910390f35b3480156102a757600080fd' +
- '5b506102b0611033565b6040518082815260200191505060405180910390f35b34801561' +
- '02d257600080fd5b50610307600480360381019080803573ffffffffffffffffffffffff' +
- 'ffffffffffffffff16906020019092919050505061103d565b005b348015610315576000' +
- '80fd5b50610374600480360381019080803573ffffffffffffffffffffffffffffffffff' +
- 'ffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16' +
- '906020019092919080359060200190929190505050611137565b60405180821515151581' +
- '5260200191505060405180910390f35b34801561039a57600080fd5b506103cf60048036' +
- '0381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291' +
- '90505050611636565b604051808215151515815260200191505060405180910390f35b34' +
- '80156103f557600080fd5b506103fe61177d565b604051808260ff1660ff168152602001' +
- '91505060405180910390f35b34801561042657600080fd5b5061059a6004803603810190' +
- '80803590602001908201803590602001908080601f016020809104026020016040519081' +
- '016040528093929190818152602001838380828437820191505050505050919291929080' +
- '3590602001908201803590602001908080601f0160208091040260200160405190810160' +
- '405280939291908181526020018383808284378201915050505050509192919290803590' +
- '602001908201803590602001908080601f01602080910402602001604051908101604052' +
- '80939291908181526020018383808284378201915050505050509192919290803560ff16' +
- '9060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001' +
- '90929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190' +
- '803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ff' +
- 'ffffffffffffffffffffffffffffffffffffff169060200190929190505050611790565b' +
- '005b3480156105a857600080fd5b506105b16119ed565b604051808273ffffffffffffff' +
- 'ffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16' +
- '815260200191505060405180910390f35b3480156105ff57600080fd5b5061063e600480' +
- '360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092' +
- '919080359060200190929190505050611a13565b60405180821515151581526020019150' +
- '5060405180910390f35b34801561066457600080fd5b5061066d611ab8565b005b348015' +
- '61067b57600080fd5b506106ba600480360381019080803573ffffffffffffffffffffff' +
- 'ffffffffffffffffff16906020019092919080359060200190929190505050611b5d565b' +
- '604051808215151515815260200191505060405180910390f35b3480156106e057600080' +
- 'fd5b506106ff60048036038101908080359060200190929190505050611eff565b005b34' +
- '801561070d57600080fd5b5061074c600480360381019080803573ffffffffffffffffff' +
- 'ffffffffffffffffffffff16906020019092919080359060200190929190505050612166' +
- '565b604051808215151515815260200191505060405180910390f35b3480156107725760' +
- '0080fd5b506107a7600480360381019080803573ffffffffffffffffffffffffffffffff' +
- 'ffffffff1690602001909291905050506122d4565b005b3480156107b557600080fd5b50' +
- '6107be6123fa565b604051808215151515815260200191505060405180910390f35b3480' +
- '156107e457600080fd5b50610819600480360381019080803573ffffffffffffffffffff' +
- 'ffffffffffffffffffff16906020019092919050505061240d565b604051808281526020' +
- '0191505060405180910390f35b34801561083b57600080fd5b50610844612456565b005b' +
- '34801561085257600080fd5b50610887600480360381019080803573ffffffffffffffff' +
- 'ffffffffffffffffffffffff1690602001909291905050506124fb565b60405180828152' +
- '60200191505060405180910390f35b3480156108a957600080fd5b506108b2612544565b' +
- '604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffff' +
- 'ffffffffffffffffffffffff16815260200191505060405180910390f35b348015610900' +
- '57600080fd5b5061090961256d565b604051808060200182810382528381815181526020' +
- '0191508051906020019080838360005b8381101561094957808201518184015260208101' +
- '905061092e565b50505050905090810190601f1680156109765780820380516001836020' +
- '036101000a031916815260200191505b509250505060405180910390f35b348015610990' +
- '57600080fd5b5061099961260b565b604051808273ffffffffffffffffffffffffffffff' +
- 'ffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050' +
- '60405180910390f35b3480156109e757600080fd5b50610a266004803603810190808035' +
- '73ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001' +
- '90929190505050612631565b604051808215151515815260200191505060405180910390' +
- 'f35b348015610a4c57600080fd5b50610a8b600480360381019080803573ffffffffffff' +
- 'ffffffffffffffffffffffffffff16906020019092919080359060200190929190505050' +
- '612734565b604051808215151515815260200191505060405180910390f35b348015610a' +
- 'b157600080fd5b50610ae6600480360381019080803573ffffffffffffffffffffffffff' +
- 'ffffffffffffff169060200190929190505050612a37565b005b348015610af457600080' +
- 'fd5b50610b29600480360381019080803573ffffffffffffffffffffffffffffffffffff' +
- 'ffff169060200190929190505050612b5d565b6040518082151515158152602001915050' +
- '60405180910390f35b348015610b4f57600080fd5b50610b846004803603810190808035' +
- '73ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612bb3' +
- '565b005b348015610b9257600080fd5b50610b9b612cd9565b604051808273ffffffffff' +
- 'ffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffff' +
- 'ff16815260200191505060405180910390f35b348015610be957600080fd5b50610c3e60' +
- '0480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001' +
- '90929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190' +
- '505050612cff565b6040518082815260200191505060405180910390f35b348015610c60' +
- '57600080fd5b50610c69612d86565b604051808060200182810382528381815181526020' +
- '0191508051906020019080838360005b83811015610ca957808201518184015260208101' +
- '9050610c8e565b50505050905090810190601f168015610cd65780820380516001836020' +
- '036101000a031916815260200191505b509250505060405180910390f35b348015610cf0' +
- '57600080fd5b50610d25600480360381019080803573ffffffffffffffffffffffffffff' +
- 'ffffffffffff169060200190929190505050612e24565b005b348015610d3357600080fd' +
- '5b50610d68600480360381019080803573ffffffffffffffffffffffffffffffffffffff' +
- 'ff169060200190929190505050612f4b565b005b348015610d7657600080fd5b50610dab' +
- '600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020' +
- '0190929190505050613045565b6040518082151515158152602001915050604051809103' +
- '90f35b60078054600181600116156101000203166002900480601f016020809104026020' +
- '016040519081016040528092919081815260200182805460018160011615610100020316' +
- '600290048015610e5b5780601f10610e3057610100808354040283529160200191610e5b' +
- '565b820191906000526020600020905b815481529060010190602001808311610e3e5782' +
- '9003601f168201915b505050505081565b6000600460149054906101000a900460ff1615' +
- '1515610e8157600080fd5b3360001515600660008373ffffffffffffffffffffffffffff' +
- 'ffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081' +
- '5260200160002060009054906101000a900460ff161515141515610ee157600080fd5b83' +
- '60001515600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffff' +
- 'ffffffffffffffffffffffffffffffff1681526020019081526020016000206000905490' +
- '6101000a900460ff161515141515610f4157600080fd5b83600d60003373ffffffffffff' +
- 'ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff' +
- '16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffff' +
- 'ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020' +
- '01600020819055508473ffffffffffffffffffffffffffffffffffffffff163373ffffff' +
- 'ffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd' +
- '0314c0f7b2291e5b200ac8c7c3b925866040518082815260200191505060405180910390' +
- 'a360019250505092915050565b6000600e54905090565b600560009054906101000a9004' +
- '73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff' +
- 'ffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156110' +
- '9957600080fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff16' +
- '73ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020' +
- '60006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffff' +
- 'ffffffffffffffffff167f117e3210bb9aa7d9baff172026820255c6f6c30ba8999d1c2f' +
- 'd88e2848137c4e60405160405180910390a250565b6000600460149054906101000a9004' +
- '60ff1615151561115557600080fd5b8260001515600660008373ffffffffffffffffffff' +
- 'ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260' +
- '200190815260200160002060009054906101000a900460ff1615151415156111b5576000' +
- '80fd5b3360001515600660008373ffffffffffffffffffffffffffffffffffffffff1673' +
- 'ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060' +
- '009054906101000a900460ff16151514151561121557600080fd5b856000151560066000' +
- '8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff' +
- 'ffffffffffffffff16815260200190815260200160002060009054906101000a900460ff' +
- '16151514151561127557600080fd5b600073ffffffffffffffffffffffffffffffffffff' +
- 'ffff168673ffffffffffffffffffffffffffffffffffffffff16141515156112b1576000' +
- '80fd5b600c60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffff' +
- 'ffffffffffffffffffffffffffffff168152602001908152602001600020548511151515' +
- '6112ff57600080fd5b600d60008873ffffffffffffffffffffffffffffffffffffffff16' +
- '73ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020' +
- '60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffff' +
- 'ffffffffffffffffffff16815260200190815260200160002054851115151561138a5760' +
- '0080fd5b6113dc85600c60008a73ffffffffffffffffffffffffffffffffffffffff1673' +
- 'ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054' +
- '61309b90919063ffffffff16565b600c60008973ffffffffffffffffffffffffffffffff' +
- 'ffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260' +
- '20016000208190555061147185600c60008973ffffffffffffffffffffffffffffffffff' +
- 'ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020' +
- '01600020546130e590919063ffffffff16565b600c60008873ffffffffffffffffffffff' +
- 'ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020' +
- '019081526020016000208190555061154385600d60008a73ffffffffffffffffffffffff' +
- 'ffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001' +
- '90815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ff' +
- 'ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461' +
- '309b90919063ffffffff16565b600d60008973ffffffffffffffffffffffffffffffffff' +
- 'ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020' +
- '0160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff' +
- 'ffffffffffffffffffffffffffff168152602001908152602001600020819055508573ff' +
- 'ffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffff' +
- 'ffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4d' +
- 'f523b3ef876040518082815260200191505060405180910390a360019350505050939250' +
- '5050565b6000600b60009054906101000a900473ffffffffffffffffffffffffffffffff' +
- 'ffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff' +
- 'ffffffffffffffffffffffffff1614151561169457600080fd5b6000600f60008473ffff' +
- 'ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff' +
- 'ffffffff16815260200190815260200160002060006101000a81548160ff021916908315' +
- '1502179055506000601060008473ffffffffffffffffffffffffffffffffffffffff1673' +
- 'ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081' +
- '9055508173ffffffffffffffffffffffffffffffffffffffff167fe94479a9f7e1952cc7' +
- '8f2d6baab678adc1b772d936c6583def489e524cb6669260405160405180910390a26001' +
- '9050919050565b600960009054906101000a900460ff1681565b600b6014905490610100' +
- '0a900460ff161515156117ac57600080fd5b600073ffffffffffffffffffffffffffffff' +
- 'ffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156117e8' +
- '57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffff' +
- 'ffffffffffffffffffffffffffffffff161415151561182457600080fd5b600073ffffff' +
- 'ffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffff' +
- 'ffffffff161415151561186057600080fd5b600073ffffffffffffffffffffffffffffff' +
- 'ffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561189c' +
- '57600080fd5b87600790805190602001906118b29291906134f4565b5086600890805190' +
- '602001906118c99291906134f4565b5085600a90805190602001906118e09291906134f4' +
- '565b5084600960006101000a81548160ff021916908360ff16021790555083600b600061' +
- '01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff' +
- 'ffffffffffffffffffffffffffffffffff16021790555082600460006101000a81548173' +
- 'ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffff' +
- 'ffffffffffffffffffff16021790555081600560006101000a81548173ffffffffffffff' +
- 'ffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffff' +
- 'ffffff1602179055506119c88161316f565b6001600b60146101000a81548160ff021916' +
- '9083151502179055505050505050505050565b600b60009054906101000a900473ffffff' +
- 'ffffffffffffffffffffffffffffffffff1681565b6000611aae3384611aa98560026000' +
- '3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff' +
- 'ffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffff' +
- 'ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152' +
- '602001908152602001600020546130e590919063ffffffff16565b6131b2565b60019050' +
- '92915050565b600460009054906101000a900473ffffffffffffffffffffffffffffffff' +
- 'ffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff' +
- 'ffffffffffffffffffffffffff16141515611b1457600080fd5b6000600460146101000a' +
- '81548160ff0219169083151502179055507f7805862f689e2f13df9f062ff482ad3ad112' +
- 'aca9e0847911ed832e158c525b3360405160405180910390a1565b600080600460149054' +
- '906101000a900460ff16151515611b7c57600080fd5b60011515600f60003373ffffffff' +
- 'ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff' +
- 'ffff16815260200190815260200160002060009054906101000a900460ff161515141515' +
- '611bdb57600080fd5b3360001515600660008373ffffffffffffffffffffffffffffffff' +
- 'ffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260' +
- '200160002060009054906101000a900460ff161515141515611c3b57600080fd5b846000' +
- '1515600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff' +
- 'ffffffffffffffffffffffffffff16815260200190815260200160002060009054906101' +
- '000a900460ff161515141515611c9b57600080fd5b600073ffffffffffffffffffffffff' +
- 'ffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614151515' +
- '611cd757600080fd5b600085111515611ce657600080fd5b601060003373ffffffffffff' +
- 'ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff' +
- '168152602001908152602001600020549250828511151515611d3757600080fd5b611d4c' +
- '85600e546130e590919063ffffffff16565b600e81905550611da485600c60008973ffff' +
- 'ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff' +
- 'ffffffff168152602001908152602001600020546130e590919063ffffffff16565b600c' +
- '60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffff' +
- 'ffffffffffffffffffff16815260200190815260200160002081905550611dfa85846130' +
- '9b90919063ffffffff16565b601060003373ffffffffffffffffffffffffffffffffffff' +
- 'ffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001' +
- '600020819055508573ffffffffffffffffffffffffffffffffffffffff163373ffffffff' +
- 'ffffffffffffffffffffffffffffffff167fab8530f87dc9b59234c4623bf917212bb253' +
- '6d647574c8e7e5da92c2ede0c9f8876040518082815260200191505060405180910390a3' +
- '8573ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2' +
- 'b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405180828152602001915050' +
- '60405180910390a36001935050505092915050565b6000600460149054906101000a9004' +
- '60ff16151515611f1d57600080fd5b60011515600f60003373ffffffffffffffffffffff' +
- 'ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020' +
- '0190815260200160002060009054906101000a900460ff161515141515611f7c57600080' +
- 'fd5b3360001515600660008373ffffffffffffffffffffffffffffffffffffffff1673ff' +
- 'ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000' +
- '9054906101000a900460ff161515141515611fdc57600080fd5b600c60003373ffffffff' +
- 'ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff' +
- 'ffff16815260200190815260200160002054915060008311151561202d57600080fd5b82' +
- '821015151561203c57600080fd5b61205183600e5461309b90919063ffffffff16565b60' +
- '0e8190555061206a838361309b90919063ffffffff16565b600c60003373ffffffffffff' +
- 'ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff' +
- '168152602001908152602001600020819055503373ffffffffffffffffffffffffffffff' +
- 'ffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d' +
- '397ca5846040518082815260200191505060405180910390a2600073ffffffffffffffff' +
- 'ffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16' +
- '7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040' +
- '518082815260200191505060405180910390a3505050565b600060046014905490610100' +
- '0a900460ff1615151561218457600080fd5b600b60009054906101000a900473ffffffff' +
- 'ffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffff' +
- 'ffff163373ffffffffffffffffffffffffffffffffffffffff161415156121e057600080' +
- 'fd5b6001600f60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffff' +
- 'ffffffffffffffffffffffffffffffff1681526020019081526020016000206000610100' +
- '0a81548160ff02191690831515021790555081601060008573ffffffffffffffffffffff' +
- 'ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020' +
- '01908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff' +
- '167f46980fca912ef9bcdbd36877427b6b90e860769f604e89c0e67720cece530d208360' +
- '40518082815260200191505060405180910390a26001905092915050565b6122dc612544' +
- '565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffff' +
- 'ffffffffffffffffffff1614151561231557600080fd5b600073ffffffffffffffffffff' +
- 'ffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415' +
- '151561235157600080fd5b80600460006101000a81548173ffffffffffffffffffffffff' +
- 'ffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602' +
- '17905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffff' +
- 'ffff1673ffffffffffffffffffffffffffffffffffffffff167fb80482a293ca2e013eda' +
- '8683c9bd7fc8347cfdaeea5ede58cba46df502c2a60460405160405180910390a250565b' +
- '600460149054906101000a900460ff1681565b6000600c60008373ffffffffffffffffff' +
- 'ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152' +
- '602001908152602001600020549050919050565b600460009054906101000a900473ffff' +
- 'ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff' +
- 'ffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156124b25760' +
- '0080fd5b6001600460146101000a81548160ff0219169083151502179055507f6985a022' +
- '10a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff6256040516040518091' +
- '0390a1565b6000601060008373ffffffffffffffffffffffffffffffffffffffff1673ff' +
- 'ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490' +
- '50919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffff' +
- 'ffffffffff16905090565b60088054600181600116156101000203166002900480601f01' +
- '602080910402602001604051908101604052809291908181526020018280546001816001' +
- '16156101000203166002900480156126035780601f106125d85761010080835404028352' +
- '9160200191612603565b820191906000526020600020905b815481529060010190602001' +
- '8083116125e657829003601f168201915b505050505081565b600460009054906101000a' +
- '900473ffffffffffffffffffffffffffffffffffffffff1681565b600061272a33846127' +
- '2585606060405190810160405280602581526020017f45524332303a2064656372656173' +
- '656420616c6c6f77616e63652062656c6f7781526020017f207a65726f00000000000000' +
- '0000000000000000000000000000000000000000815250600260003373ffffffffffffff' +
- 'ffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16' +
- '815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffff' +
- 'ffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001' +
- '600020546134339092919063ffffffff16565b6131b2565b6001905092915050565b6000' +
- '600460149054906101000a900460ff1615151561275257600080fd5b3360001515600660' +
- '008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff' +
- 'ffffffffffffffffff16815260200190815260200160002060009054906101000a900460' +
- 'ff1615151415156127b257600080fd5b8360001515600660008373ffffffffffffffffff' +
- 'ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152' +
- '60200190815260200160002060009054906101000a900460ff1615151415156128125760' +
- '0080fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffff' +
- 'ffffffffffffffffffffffffffff161415151561284e57600080fd5b600c60003373ffff' +
- 'ffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffff' +
- 'ffffffff16815260200190815260200160002054841115151561289c57600080fd5b6128' +
- 'ee84600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffff' +
- 'ffffffffffffffffffffffffffff1681526020019081526020016000205461309b909190' +
- '63ffffffff16565b600c60003373ffffffffffffffffffffffffffffffffffffffff1673' +
- 'ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081' +
- '90555061298384600c60008873ffffffffffffffffffffffffffffffffffffffff1673ff' +
- 'ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461' +
- '30e590919063ffffffff16565b600c60008773ffffffffffffffffffffffffffffffffff' +
- 'ffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020' +
- '01600020819055508473ffffffffffffffffffffffffffffffffffffffff163373ffffff' +
- 'ffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa95' +
- '2ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390' +
- 'a360019250505092915050565b612a3f612544565b73ffffffffffffffffffffffffffff' +
- 'ffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612a78' +
- '57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffff' +
- 'ffffffffffffffffffffffffffffffff1614151515612ab457600080fd5b80600b600061' +
- '01000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffff' +
- 'ffffffffffffffffffffffffffffffffff160217905550600b60009054906101000a9004' +
- '73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff' +
- 'ffffffffffffff167fdb66dfa9c6b8f5226fe9aac7e51897ae8ee94ac31dc70bb6c9900b' +
- '2574b707e660405160405180910390a250565b6000600f60008373ffffffffffffffffff' +
- 'ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152' +
- '60200190815260200160002060009054906101000a900460ff169050919050565b612bbb' +
- '612544565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffff' +
- 'ffffffffffffffffffffffffff16141515612bf457600080fd5b600073ffffffffffffff' +
- 'ffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff' +
- '1614151515612c3057600080fd5b80600560006101000a81548173ffffffffffffffffff' +
- 'ffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffff' +
- 'ff160217905550600560009054906101000a900473ffffffffffffffffffffffffffffff' +
- 'ffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fc67398012c111c' +
- 'e95ecb7429b933096c977380ee6c421175a71a4a4c6c88c06e60405160405180910390a2' +
- '50565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffff' +
- 'ff1681565b6000600d60008473ffffffffffffffffffffffffffffffffffffffff1673ff' +
- 'ffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000' +
- '8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffff' +
- 'ffffffffffffffff16815260200190815260200160002054905092915050565b600a8054' +
- '600181600116156101000203166002900480601f01602080910402602001604051908101' +
- '604052809291908181526020018280546001816001161561010002031660029004801561' +
- '2e1c5780601f10612df157610100808354040283529160200191612e1c565b8201919060' +
- '00526020600020905b815481529060010190602001808311612dff57829003601f168201' +
- '915b505050505081565b612e2c612544565b73ffffffffffffffffffffffffffffffffff' +
- 'ffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612e65576000' +
- '80fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffff' +
- 'ffffffffffffffffffffffffff1614151515612ea157600080fd5b7f8be0079c53165914' +
- '1344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0612eca612544565b82604051' +
- '808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff' +
- 'ffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffff' +
- 'ff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050604051' +
- '80910390a1612f488161316f565b50565b600560009054906101000a900473ffffffffff' +
- 'ffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffff' +
- 'ff163373ffffffffffffffffffffffffffffffffffffffff16141515612fa757600080fd' +
- '5b6001600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffff' +
- 'ffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a' +
- '81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffff' +
- 'ffffff167fffa4e6181777692565cf28528fc88fd1516ea86b56da075235fa575af6a4b8' +
- '5560405160405180910390a250565b6000600660008373ffffffffffffffffffffffffff' +
- 'ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190' +
- '815260200160002060009054906101000a900460ff169050919050565b60006130dd8383' +
- '6040805190810160405280601e81526020017f536166654d6174683a2073756274726163' +
- '74696f6e206f766572666c6f770000815250613433565b905092915050565b6000808284' +
- '019050838110151515613165576040517f08c379a0000000000000000000000000000000' +
- '00000000000000000000000000815260040180806020018281038252601b815260200180' +
- '7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815250' +
- '60200191505060405180910390fd5b8091505092915050565b806000806101000a815481' +
- '73ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffff' +
- 'ffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffff' +
- 'ffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561' +
- '327d576040517f08c379a000000000000000000000000000000000000000000000000000' +
- '00000081526004018080602001828103825260248152602001807f45524332303a206170' +
- '70726f76652066726f6d20746865207a65726f2061646481526020017f72657373000000' +
- '000000000000000000000000000000000000000000000000008152506040019150506040' +
- '5180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffff' +
- 'ffffffffffffffffffffffffffffffffff1614151515613348576040517f08c379a00000' +
- '000000000000000000000000000000000000000000000000000081526004018080602001' +
- '828103825260228152602001807f45524332303a20617070726f766520746f2074686520' +
- '7a65726f20616464726581526020017f7373000000000000000000000000000000000000' +
- '00000000000000000000000081525060400191505060405180910390fd5b806002600085' +
- '73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff' +
- 'ffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffff' +
- 'ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260' +
- '2001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffff' +
- 'ff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f' +
- '71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405180828152602001915050' +
- '60405180910390a3505050565b60008084841115839015156134e3576040517f08c379a0' +
- '000000000000000000000000000000000000000000000000000000008152600401808060' +
- '2001828103825283818151815260200191508051906020019080838360005b8381101561' +
- '34a857808201518184015260208101905061348d565b50505050905090810190601f1680' +
- '156134d55780820380516001836020036101000a031916815260200191505b5092505050' +
- '60405180910390fd5b508385039050809150509392505050565b82805460018160011615' +
- '6101000203166002900490600052602060002090601f016020900481019282601f106135' +
- '3557805160ff1916838001178555613563565b8280016001018555821561356357918201' +
- '5b82811115613562578251825591602001919060010190613547565b5b50905061357091' +
- '90613574565b5090565b61359691905b8082111561359257600081600090555060010161' +
- '357a565b5090565b905600a165627a7a72305820e15de5c992fd476a4778192f1e437474' +
- 'd0da61a53e449a2db2ec25213f4be8620029'
- )
-
- // 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B
- // nonce: 0
- const mockUnitrollerDeploymentData = (
- '0x608060405234801561001057600080fd5b50600080546001600160a01b031916331790' +
- '556105db806100326000396000f3fe60806040526004361061007b5760003560e01c8063' +
- 'dcfbc0c71161004e578063dcfbc0c71461019e578063e992a041146101b3578063e9c714' +
- 'f2146101e6578063f851a440146101fb5761007b565b806326782247146100fe578063b7' +
- '1d1a0c1461012f578063bb82aa5e14610174578063c1e8033414610189575b6002546040' +
- '516000916001600160a01b03169082903690808383808284376040519201945060009350' +
- '9091505080830381855af49150503d80600081146100de576040519150601f19603f3d01' +
- '1682016040523d82523d6000602084013e6100e3565b606091505b505090506040513d60' +
- '00823e8180156100fa573d82f35b3d82fd5b34801561010a57600080fd5b506101136102' +
- '10565b604080516001600160a01b039092168252519081900360200190f35b3480156101' +
- '3b57600080fd5b506101626004803603602081101561015257600080fd5b503560016001' +
- '60a01b031661021f565b60408051918252519081900360200190f35b3480156101805760' +
- '0080fd5b506101136102b0565b34801561019557600080fd5b506101626102bf565b3480' +
- '156101aa57600080fd5b506101136103ba565b3480156101bf57600080fd5b5061016260' +
- '0480360360208110156101d657600080fd5b50356001600160a01b03166103c9565b3480' +
- '156101f257600080fd5b5061016261044d565b34801561020757600080fd5b5061011361' +
- '0533565b6001546001600160a01b031681565b600080546001600160a01b031633146102' +
- '455761023e6001600e610542565b90506102ab565b600180546001600160a01b03848116' +
- '6001600160a01b0319831681179093556040805191909216808252602082019390935281' +
- '517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99291' +
- '81900390910190a160005b9150505b919050565b6002546001600160a01b031681565b60' +
- '03546000906001600160a01b0316331415806102e557506003546001600160a01b031615' +
- '5b156102fc576102f5600180610542565b90506103b7565b600280546003805460016001' +
- '60a01b038082166001600160a01b03198086168217968790559092169092556040805193' +
- '8316808552949092166020840152815190927fd604de94d45953f9138079ec1b82d533cb' +
- '2160c906d1076d1f7ed54befbca97a92908290030190a1600354604080516001600160a0' +
- '1b038085168252909216602083015280517fe945ccee5d701fc83f9b8aa8ca94ea4219ec' +
- '1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160005b925050505b90565b6003' +
- '546001600160a01b031681565b600080546001600160a01b031633146103e85761023e60' +
- '01600f610542565b600380546001600160a01b038481166001600160a01b031983161792' +
- '8390556040805192821680845293909116602083015280517fe945ccee5d701fc83f9b8a' +
- 'a8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160006102a756' +
- '5b6001546000906001600160a01b031633141580610468575033155b15610479576102f5' +
- '60016000610542565b60008054600180546001600160a01b038082166001600160a01b03' +
- '198086168217968790559092169092556040805193831680855294909216602084015281' +
- '5190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc' +
- '92908290030190a1600154604080516001600160a01b0380851682529092166020830152' +
- '80517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a992' +
- '81900390910190a160006103b2565b6000546001600160a01b031681565b60007f45b96f' +
- 'e442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561' +
- '057157fe5b83601381111561057d57fe5b60408051928352602083019190915260008282' +
- '0152519081900360600190a18260118111156105a857fe5b939250505056fea165627a7a' +
- '72305820deb1fa7c9392a8cb5591582fb6e4b04575db52ce8ef799b0a7a5140ae6ff75d8' +
- '0029'
- )
-
- // 0x178053c06006e67e09879C09Ff012fF9d263dF29
- // nonce: 68
- const mockCurrentComptrollerDeploymentData = (
- '0x608060405234801561001057600080fd5b50600080546001600160a01b031916331790' +
- '55612d15806100326000396000f3fe608060405234801561001057600080fd5b50600436' +
- '106102315760003560e01c80638e8f294b11610130578063d02f7351116100b8578063e4' +
- '028eee1161007c578063e4028eee1461090e578063e87554461461093a578063eabe7d91' +
- '14610942578063ede4edd014610978578063f851a4401461099e57610231565b8063d02f' +
- '735114610841578063d9226ced14610887578063da3d454c146108a4578063dce1544914' +
- '6108da578063dcfbc0c71461090657610231565b8063abfceffc116100ff578063abfcef' +
- 'fc14610695578063bb82aa5e1461070b578063bdcdc25814610713578063c29982381461' +
- '074f578063c488847b146107f257610231565b80638e8f294b146105f8578063929fe9a1' +
- '1461063957806394b2294b14610667578063a76b3fda1461066f57610231565b80634ef4' +
- 'c3e1116101be5780635ec88c79116101825780635ec88c79146104e45780635fc7e71e14' +
- '6105285780636a56947e1461056e5780636d35bf91146105aa5780637dc0d1d0146105f0' +
- '57610231565b80634ef4c3e1146103f95780634fd42e171461042f57806351dff9891461' +
- '044c57806355ee1fe1146104885780635c778605146104ae57610231565b8063317b0b77' +
- '11610205578063317b0b771461030857806332000e001461032557806341c728b9146103' +
- '6957806347ef3b3b146103a55780634ada90af146103f157610231565b80627e3dd21461' +
- '02365780631ededc911461025257806324008a621461029657806326782247146102e457' +
- '5b600080fd5b61023e6109a6565b604080519115158252519081900360200190f35b6102' +
- '94600480360360a081101561026857600080fd5b506001600160a01b0381358116916020' +
- '81013582169160408201351690606081013590608001356109ab565b005b6102d2600480' +
- '360360808110156102ac57600080fd5b506001600160a01b038135811691602081013582' +
- '169160408201351690606001356109b2565b60408051918252519081900360200190f35b' +
- '6102ec6109e8565b604080516001600160a01b039092168252519081900360200190f35b' +
- '6102d26004803603602081101561031e57600080fd5b50356109f7565b61029460048036' +
- '0360a081101561033b57600080fd5b506001600160a01b03813581169160208101359091' +
- '1690604081013590606081013590608001351515610b05565b6102946004803603608081' +
- '101561037f57600080fd5b506001600160a01b0381358116916020810135909116906040' +
- '8101359060600135610fcd565b610294600480360360c08110156103bb57600080fd5b50' +
- '6001600160a01b0381358116916020810135821691604082013581169160608101359091' +
- '169060808101359060a00135610fd3565b6102d2610fd8565b6102d26004803603606081' +
- '101561040f57600080fd5b506001600160a01b0381358116916020810135909116906040' +
- '0135610fde565b6102d26004803603602081101561044557600080fd5b5035611015565b' +
- '6102946004803603608081101561046257600080fd5b506001600160a01b038135811691' +
- '60208101359091169060408101359060600135611104565b6102d2600480360360208110' +
- '1561049e57600080fd5b50356001600160a01b0316611167565b61029460048036036060' +
- '8110156104c457600080fd5b506001600160a01b03813581169160208101359091169060' +
- '4001356111e9565b61050a600480360360208110156104fa57600080fd5b503560016001' +
- '60a01b03166111ee565b6040805193845260208401929092528282015251908190036060' +
- '0190f35b6102d2600480360360a081101561053e57600080fd5b506001600160a01b0381' +
- '358116916020810135821691604082013581169160608101359091169060800135611223' +
- '565b6102946004803603608081101561058457600080fd5b506001600160a01b03813581' +
- '169160208101358216916040820135169060600135610fcd565b610294600480360360a0' +
- '8110156105c057600080fd5b506001600160a01b03813581169160208101358216916040' +
- '820135811691606081013590911690608001356109ab565b6102ec6113aa565b61061e60' +
- '04803603602081101561060e57600080fd5b50356001600160a01b03166113b9565b6040' +
- '8051921515835260208301919091528051918290030190f35b61023e6004803603604081' +
- '101561064f57600080fd5b506001600160a01b03813581169160200135166113d8565b61' +
- '02d261140c565b6102d26004803603602081101561068557600080fd5b50356001600160' +
- 'a01b0316611412565b6106bb600480360360208110156106ab57600080fd5b5035600160' +
- '0160a01b0316611541565b60408051602080825283518183015283519192839290830191' +
- '858101910280838360005b838110156106f75781810151838201526020016106df565b50' +
- '5050509050019250505060405180910390f35b6102ec6115ca565b6102d2600480360360' +
- '8081101561072957600080fd5b506001600160a01b038135811691602081013582169160' +
- '408201351690606001356115d9565b6106bb6004803603602081101561076557600080fd' +
- '5b81019060208101813564010000000081111561078057600080fd5b8201836020820111' +
- '1561079257600080fd5b8035906020019184602083028401116401000000008311171561' +
- '07b457600080fd5b91908080602002602001604051908101604052809392919081815260' +
- '20018383602002808284376000920191909152509295506115e6945050505050565b6108' +
- '286004803603606081101561080857600080fd5b506001600160a01b0381358116916020' +
- '810135909116906040013561178a565b6040805192835260208301919091528051918290' +
- '030190f35b6102d2600480360360a081101561085757600080fd5b506001600160a01b03' +
- '81358116916020810135821691604082013581169160608101359091169060800135611a' +
- '05565b6102d26004803603602081101561089d57600080fd5b5035611b4b565b6102d260' +
- '0480360360608110156108ba57600080fd5b506001600160a01b03813581169160208101' +
- '359091169060400135611baf565b6102ec600480360360408110156108f057600080fd5b' +
- '506001600160a01b038135169060200135611ce6565b6102ec611d1b565b6102d2600480' +
- '3603604081101561092457600080fd5b506001600160a01b038135169060200135611d2a' +
- '565b6102d2611edd565b6102d26004803603606081101561095857600080fd5b50600160' +
- '0160a01b03813581169160208101359091169060400135611ee3565b6102d26004803603' +
- '602081101561098e57600080fd5b50356001600160a01b0316611ef0565b6102ec612206' +
- '565b600181565b5050505050565b6001600160a01b038416600090815260096020526040' +
- '81205460ff166109da575060096109e0565b60005b90505b949350505050565b60015460' +
- '01600160a01b031681565b6000610a01612215565b610a1857610a116001600461226056' +
- '5b9050610b00565b610a20612bde565b506040805160208101909152828152610a37612b' +
- 'de565b50604080516020810190915266b1a2bc2ec500008152610a5782826122c6565b15' +
- '610a7057610a67600580612260565b92505050610b00565b610a78612bde565b50604080' +
- '5160208101909152670c7d713b49da00008152610a9981846122ce565b15610ab357610a' +
- 'a9600580612260565b9350505050610b00565b6005805490869055604080518281526020' +
- '810188905281517f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f3' +
- '46110fd9929181900390910190a160005b9450505050505b919050565b846001600160a0' +
- '1b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186' +
- '803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d6000fd5b5050' +
- '50506040513d6020811015610b6857600080fd5b50516001600160a01b03163314610bb3' +
- '57604051600160e51b62461bcd0281526004018080602001828103825260278152602001' +
- '80612cc36027913960400191505060405180910390fd5b6000856001600160a01b031663' +
- 'c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b' +
- '158015610bf057600080fd5b505af1158015610c04573d6000803e3d6000fd5b50505050' +
- '6040513d6020811015610c1a57600080fd5b505190508015610c745760408051600160e5' +
- '1b62461bcd02815260206004820152601560248201527f6368616e6765206e6f74206175' +
- '74686f72697a65640000000000000000000000604482015290519081900360640190fd5b' +
- '81610fc55760008690506000816001600160a01b03166355ee1fe1886040518263ffffff' +
- 'ff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191' +
- '5050602060405180830381600087803b158015610cd857600080fd5b505af1158015610c' +
- 'ec573d6000803e3d6000fd5b505050506040513d6020811015610d0257600080fd5b5051' +
- '90508015610d5c5760408051600160e51b62461bcd028152602060048201526016602482' +
- '01527f736574207072696365206f7261636c65206572726f720000000000000000000060' +
- '4482015290519081900360640190fd5b816001600160a01b031663317b0b778760405182' +
- '63ffffffff1660e01b815260040180828152602001915050602060405180830381600087' +
- '803b158015610da257600080fd5b505af1158015610db6573d6000803e3d6000fd5b5050' +
- '50506040513d6020811015610dcc57600080fd5b505190508015610e2657604080516001' +
- '60e51b62461bcd02815260206004820152601660248201527f73657420636c6f73652066' +
- '6163746f72206572726f7200000000000000000000604482015290519081900360640190' +
- 'fd5b816001600160a01b031663d9226ced866040518263ffffffff1660e01b8152600401' +
- '80828152602001915050602060405180830381600087803b158015610e6c57600080fd5b' +
- '505af1158015610e80573d6000803e3d6000fd5b505050506040513d6020811015610e96' +
- '57600080fd5b505190508015610ef05760408051600160e51b62461bcd02815260206004' +
- '820152601560248201527f736574206d61782061737373657473206572726f7200000000' +
- '00000000000000604482015290519081900360640190fd5b816001600160a01b0316634f' +
- 'd42e17670de0b6b3a76400006040518263ffffffff1660e01b8152600401808281526020' +
- '01915050602060405180830381600087803b158015610f3e57600080fd5b505af1158015' +
- '610f52573d6000803e3d6000fd5b505050506040513d6020811015610f6857600080fd5b' +
- '505190508015610fc25760408051600160e51b62461bcd02815260206004820152601f60' +
- '248201527f736574206c69717569646174696f6e20696e63656e74697665206572726f72' +
- '00604482015290519081900360640190fd5b50505b505050505050565b50505050565b61' +
- '0fc5565b60065481565b6001600160a01b03831660009081526009602052604081205460' +
- 'ff166110085760095b905061100e565b60005b90505b9392505050565b600061101f6122' +
- '15565b61102f57610a116001600b612260565b611037612bde565b506040805160208101' +
- '90915282815261104e612bde565b506040805160208101909152670de0b6b3a764000081' +
- '5261106f82826122ce565b1561108057610a676007600c612260565b611088612bde565b' +
- '5060408051602081019091526714d1120d7b16000081526110a981846122ce565b156110' +
- 'ba57610aa96007600c612260565b60068054908690556040805182815260208101889052' +
- '81517faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec131692' +
- '9181900390910190a16000610af9565b801580156111125750600082115b15610fcd5760' +
- '408051600160e51b62461bcd02815260206004820152601160248201527f72656465656d' +
- '546f6b656e73207a65726f00000000000000000000000000000060448201529051908190' +
- '0360640190fd5b6000611171612215565b61118157610a1160016010612260565b600480' +
- '546001600160a01b038481166001600160a01b0319831681179093556040805191909216' +
- '808252602082019390935281517fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d' +
- '2d0ea78402d576d22e22929181900390910190a160009392505050565b505050565b6000' +
- '806000806000806112058760008060006122d5565b925092509250826011811115611217' +
- '57fe5b97919650945092505050565b6001600160a01b0385166000908152600960205260' +
- '4081205460ff16158061126457506001600160a01b038516600090815260096020526040' +
- '90205460ff16155b156112735760095b90506113a1565b60008061127f856126fd565b91' +
- '93509091506000905082601181111561129557fe5b146112af578160118111156112a657' +
- 'fe5b925050506113a1565b806112bb5760036112a6565b6000886001600160a01b031663' +
- '95dd9193876040518263ffffffff1660e01b815260040180826001600160a01b03166001' +
- '600160a01b0316815260200191505060206040518083038186803b158015611313576000' +
- '80fd5b505afa158015611327573d6000803e3d6000fd5b505050506040513d6020811015' +
- '61133d57600080fd5b505160408051602081019091526005548152909150600090819061' +
- '1361908461271d565b9092509050600082600381111561137457fe5b1461138857600b5b' +
- '955050505050506113a1565b8087111561139757601161137c565b600095505050505050' +
- '5b95945050505050565b6004546001600160a01b031681565b6009602052600090815260' +
- '409020805460019091015460ff9091169082565b6001600160a01b038082166000908152' +
- '600960209081526040808320938616835260029093019052205460ff165b92915050565b' +
- '60075481565b600080546001600160a01b0316331461143157610a116001601261226056' +
- '5b6001600160a01b03821660009081526009602052604090205460ff161561145e57610a' +
- '11600a6011612260565b816001600160a01b031663fe9c44ae6040518163ffffffff1660' +
- 'e01b815260040160206040518083038186803b15801561149757600080fd5b505afa1580' +
- '156114ab573d6000803e3d6000fd5b505050506040513d60208110156114c157600080fd' +
- '5b50506040805180820182526001808252600060208084018281526001600160a01b0388' +
- '1680845260098352928690209451855460ff191690151517855551939092019290925582' +
- '5191825291517fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f2' +
- '12321f929181900390910190a1600092915050565b60608060086000846001600160a01b' +
- '03166001600160a01b031681526020019081526020016000208054806020026020016040' +
- '519081016040528092919081815260200182805480156115bd5760200282019190600052' +
- '6020600020905b81546001600160a01b0316815260019091019060200180831161159f57' +
- '5b5093979650505050505050565b6002546001600160a01b031681565b60006109dd8585' +
- '84612771565b606060008251905060608160405190808252806020026020018201604052' +
- '801561161a578160200160208202803883390190505b50905060005b8281101561178257' +
- '600085828151811061163657fe5b6020908102919091018101516001600160a01b038116' +
- '60009081526009909252604090912080549192509060ff1661168a5760095b8484815181' +
- '1061167757fe5b602002602001018181525050505061177a565b33600090815260028201' +
- '602052604090205460ff161515600114156116b057600061166b565b6007543360009081' +
- '5260086020526040902054106116cf57601061166b565b33600081815260028301602090' +
- '81526040808320805460ff19166001908117909155600883528184208054918201815584' +
- '529282902090920180546001600160a01b0387166001600160a01b031990911681179091' +
- '5582519081529081019290925280517f3ab23ab0d51cccc0c3085aec51f99228625aa1a9' +
- '22b3a8ca89a26b0f2027a1a59281900390910190a1600084848151811061176b57fe5b60' +
- '200260200101818152505050505b600101611620565b509392505050565b600480546040' +
- '8051600160e01b63fc57d4df0281526001600160a01b0387811694820194909452905160' +
- '00938493849391169163fc57d4df91602480820192602092909190829003018186803b15' +
- '80156117e357600080fd5b505afa1580156117f7573d6000803e3d6000fd5b5050505060' +
- '40513d602081101561180d57600080fd5b50516004805460408051600160e01b63fc57d4' +
- 'df0281526001600160a01b038a8116948201949094529051939450600093929091169163' +
- 'fc57d4df91602480820192602092909190829003018186803b15801561186957600080fd' +
- '5b505afa15801561187d573d6000803e3d6000fd5b505050506040513d60208110156118' +
- '9357600080fd5b505190508115806118a2575080155b156118b757600d93506000925061' +
- '19fd915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e0' +
- '1b815260040160206040518083038186803b1580156118f257600080fd5b505afa158015' +
- '611906573d6000803e3d6000fd5b505050506040513d602081101561191c57600080fd5b' +
- '50519050600061192a612bde565b611932612bde565b61193a612bde565b600061194860' +
- '0654896127e0565b94509050600081600381111561195a57fe5b1461197657600b5b9950' +
- '600098506119fd975050505050505050565b61198087876127e0565b9350905060008160' +
- '0381111561199257fe5b1461199e57600b611962565b6119a8848461281b565b92509050' +
- '60008160038111156119ba57fe5b146119c657600b611962565b6119d0828c61271d565b' +
- '9550905060008160038111156119e257fe5b146119ee57600b611962565b600099509397' +
- '50505050505050505b935093915050565b6001600160a01b038516600090815260096020' +
- '52604081205460ff161580611a4657506001600160a01b03851660009081526009602052' +
- '604090205460ff16155b15611a5257600961126c565b846001600160a01b0316635fe3b5' +
- '676040518163ffffffff1660e01b815260040160206040518083038186803b158015611a' +
- '8b57600080fd5b505afa158015611a9f573d6000803e3d6000fd5b505050506040513d60' +
- '20811015611ab557600080fd5b505160408051600160e01b635fe3b56702815290516001' +
- '600160a01b0392831692891691635fe3b567916004808301926020929190829003018186' +
- '803b158015611afe57600080fd5b505afa158015611b12573d6000803e3d6000fd5b5050' +
- '50506040513d6020811015611b2857600080fd5b50516001600160a01b031614611b3f57' +
- '600261126c565b60009695505050505050565b6000611b55612215565b611b6557610a11' +
- '6001600d612260565b6007805490839055604080518281526020810185905281517f7093' +
- 'cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea929181900390' +
- '910190a1600061100e565b6001600160a01b038316600090815260096020526040812054' +
- '60ff16611bd6576009611001565b6001600160a01b038085166000908152600960209081' +
- '526040808320938716835260029093019052205460ff16611c0e576008611001565b6004' +
- '805460408051600160e01b63fc57d4df0281526001600160a01b03888116948201949094' +
- '529051929091169163fc57d4df91602480820192602092909190829003018186803b1580' +
- '15611c6257600080fd5b505afa158015611c76573d6000803e3d6000fd5b505050506040' +
- '513d6020811015611c8c57600080fd5b5051611c9957600d611001565b600080611ca985' +
- '876000876122d5565b91935090915060009050826011811115611cbf57fe5b14611cd957' +
- '816011811115611cd057fe5b9250505061100e565b8015611b3f576004611cd0565b6008' +
- '6020528160005260406000208181548110611cff57fe5b60009182526020909120015460' +
- '01600160a01b03169150829050565b6003546001600160a01b031681565b600080546001' +
- '600160a01b03163314611d5057611d4960016006612260565b9050611406565b60016001' +
- '60a01b0383166000908152600960205260409020805460ff16611d8557611d7d60096007' +
- '612260565b915050611406565b611d8d612bde565b506040805160208101909152838152' +
- '611da4612bde565b506040805160208101909152670c7d713b49da00008152611dc58183' +
- '6122ce565b15611de057611dd660066008612260565b9350505050611406565b84158015' +
- '90611e6c57506004805460408051600160e01b63fc57d4df0281526001600160a01b038a' +
- '8116948201949094529051929091169163fc57d4df916024808201926020929091908290' +
- '03018186803b158015611e3e57600080fd5b505afa158015611e52573d6000803e3d6000' +
- 'fd5b505050506040513d6020811015611e6857600080fd5b5051155b15611e7d57611dd6' +
- '600d6009612260565b60018301805490869055604080516001600160a01b038916815260' +
- '20810183905280820188905290517f70483e6592cd5182d45ac970e05bc62cdcc90e9d8e' +
- 'f2c2dbe686cf383bcd7fc59181900360600190a16000979650505050505050565b600554' +
- '81565b600061100b848484612771565b6000808290506000806000836001600160a01b03' +
- '1663c37f68e2336040518263ffffffff1660e01b815260040180826001600160a01b0316' +
- '6001600160a01b0316815260200191505060806040518083038186803b158015611f5157' +
- '600080fd5b505afa158015611f65573d6000803e3d6000fd5b505050506040513d608081' +
- '1015611f7b57600080fd5b50805160208201516040909201519094509092509050821561' +
- '1fd157604051600160e51b62461bcd028152600401808060200182810382526025815260' +
- '200180612c9e6025913960400191505060405180910390fd5b8015611fee57611fe3600c' +
- '6002612260565b945050505050610b00565b6000611ffb873385612771565b9050801561' +
- '201c57612010600e600383612833565b95505050505050610b00565b6001600160a01b03' +
- '85166000908152600960209081526040808320338452600281019092529091205460ff16' +
- '61205b5760009650505050505050610b00565b3360009081526002820160209081526040' +
- '808320805460ff1916905560088252918290208054835181840281018401909452808452' +
- '606093928301828280156120cd57602002820191906000526020600020905b8154600160' +
- '0160a01b031681526001909101906020018083116120af575b5050835193945083925060' +
- '009150505b8281101561212257896001600160a01b03168482815181106120fb57fe5b60' +
- '200260200101516001600160a01b0316141561211a57809150612122565b6001016120dd' +
- '565b5081811061212c57fe5b336000908152600860205260409020805481906000198101' +
- '90811061214d57fe5b9060005260206000200160009054906101000a90046001600160a0' +
- '1b031681838154811061217757fe5b600091825260209091200180546001600160a01b03' +
- '19166001600160a01b039290921691909117905580546121b0826000198301612bf1565b' +
- '50604080516001600160a01b038c16815233602082015281517fe699a64c18b07ac5b730' +
- '1aa273f36a2287239eb9501d81950672794afba29a0d929181900390910190a160009c9b' +
- '505050505050505050505050565b6000546001600160a01b031681565b60025460009081' +
- '906001600160a01b03163314801561223e57506000546001600160a01b031632145b6000' +
- '549091506001600160a01b0316331480806122585750815b925050505b90565b60007f45' +
- 'b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360118111' +
- '1561228f57fe5b83601381111561229b57fe5b6040805192835260208301919091526000' +
- '82820152519081900360600190a182601181111561100e57fe5b519051111590565b5190' +
- '511090565b60008060006122e2612c15565b6001600160a01b0388166000908152600860' +
- '209081526040808320805482518185028101850190935280835284936060939291908301' +
- '8282801561234f57602002820191906000526020600020905b81546001600160a01b0316' +
- '8152600190910190602001808311612331575b50939450600093505050505b8151811015' +
- '6126ae57600082828151811061237257fe5b60200260200101519050806001600160a01b' +
- '031663c37f68e28e6040518263ffffffff1660e01b815260040180826001600160a01b03' +
- '166001600160a01b0316815260200191505060806040518083038186803b1580156123d2' +
- '57600080fd5b505afa1580156123e6573d6000803e3d6000fd5b505050506040513d6080' +
- '8110156123fc57600080fd5b508051602082015160408084015160609485015160808c01' +
- '52938a019390935291880191909152945084156124425750600f97506000965086955061' +
- '26f3945050505050565b60408051602080820183526001600160a01b0380851660008181' +
- '526009845285902060010154845260c08b01939093528351808301855260808b01518152' +
- '60e08b0152600480548551600160e01b63fc57d4df028152918201949094529351921692' +
- '63fc57d4df9260248083019392829003018186803b1580156124c557600080fd5b505afa' +
- '1580156124d9573d6000803e3d6000fd5b505050506040513d60208110156124ef576000' +
- '80fd5b505160a087018190526125135750600d9750600096508695506126f39450505050' +
- '50565b604080516020810190915260a08701518152610100870181905260c087015160e0' +
- '88015161254092612899565b6101208801529350600084600381111561255657fe5b1461' +
- '25725750600b9750600096508695506126f3945050505050565b61258a86610120015187' +
- '6040015188600001516128f1565b87529350600084600381111561259c57fe5b146125b8' +
- '5750600b9750600096508695506126f3945050505050565b6125d0866101000151876060' +
- '015188602001516128f1565b6020880152935060008460038111156125e557fe5b146126' +
- '015750600b9750600096508695506126f3945050505050565b8b6001600160a01b031681' +
- '6001600160a01b031614156126a55761262f8661012001518c88602001516128f1565b60' +
- '208801529350600084600381111561264457fe5b146126605750600b9750600096508695' +
- '506126f3945050505050565b6126748661010001518b88602001516128f1565b60208801' +
- '529350600084600381111561268957fe5b146126a55750600b9750600096508695506126' +
- 'f3945050505050565b5060010161235b565b506020840151845111156126d55750505060' +
- '208101519051600094500391508290506126f3565b505081516020909201516000955085' +
- '94509190910391506126f39050565b9450945094915050565b6000806000612710846000' +
- '8060006122d5565b9250925092509193909250565b600080600061272a612bde565b6127' +
- '34868661293e565b9092509050600082600381111561274757fe5b146127585750915060' +
- '00905061276a565b6000612763826129a6565b9350935050505b9250929050565b600160' +
- '0160a01b03831660009081526009602052604081205460ff16612798576009611001565b' +
- '6001600160a01b0380851660009081526009602090815260408083209387168352600290' +
- '93019052205460ff166127d0576000611001565b600080611ca985878660006122d5565b' +
- '60006127ea612bde565b6128106040518060200160405280868152506040518060200160' +
- '405280868152506129b5565b915091509250929050565b6000612825612bde565b835183' +
- '516128109190612a9e565b60007f45b96fe442630264581b197e84bbada861235052c5a1' +
- 'aadfff9ea4e40a969aa084601181111561286257fe5b84601381111561286e57fe5b6040' +
- '80519283526020830191909152818101859052519081900360600190a183601181111561' +
- '100b57fe5b60006128a3612bde565b60006128ad612bde565b6128b787876129b5565b90' +
- '9250905060008260038111156128ca57fe5b146128d95790925090506119fd565b6128e3' +
- '81866129b5565b935093505050935093915050565b60008060006128fe612bde565b6129' +
- '08878761293e565b9092509050600082600381111561291b57fe5b1461292c5750915060' +
- '0090506119fd565b6128e3612938826129a6565b86612b4e565b6000612948612bde565b' +
- '600080612959866000015186612b74565b9092509050600082600381111561296c57fe5b' +
- '1461298b5750604080516020810190915260008152909250905061276a565b6040805160' +
- '2081019091529081526000969095509350505050565b51670de0b6b3a764000090049056' +
- '5b60006129bf612bde565b6000806129d486600001518660000151612b74565b90925090' +
- '5060008260038111156129e757fe5b14612a065750604080516020810190915260008152' +
- '909250905061276a565b600080612a1b6706f05b59d3b2000084612b4e565b9092509050' +
- '6000826003811115612a2e57fe5b14612a50575060408051602081019091526000815290' +
- '9450925061276a915050565b600080612a6583670de0b6b3a7640000612bb3565b909250' +
- '90506000826003811115612a7857fe5b14612a7f57fe5b60408051602081019091529081' +
- '5260009a909950975050505050505050565b6000612aa8612bde565b600080612abd8667' +
- '0de0b6b3a7640000612b74565b90925090506000826003811115612ad057fe5b14612aef' +
- '5750604080516020810190915260008152909250905061276a565b600080612afc838861' +
- '2bb3565b90925090506000826003811115612b0f57fe5b14612b31575060408051602081' +
- '0190915260008152909450925061276a915050565b604080516020810190915290815260' +
- '009890975095505050505050565b600080838301848110612b665760009250905061276a' +
- '565b50600291506000905061276a565b60008083612b875750600090508061276a565b83' +
- '830283858281612b9457fe5b0414612ba85750600291506000905061276a565b60009250' +
- '905061276a565b60008082612bc7575060019050600061276a565b6000838581612bd257' +
- 'fe5b04915091509250929050565b6040518060200160405280600081525090565b815481' +
- '8355818111156111e9576000838152602090206111e9918101908301612c7f565b604051' +
- '806101400160405280600081526020016000815260200160008152602001600081526020' +
- '016000815260200160008152602001612c53612bde565b8152602001612c60612bde565b' +
- '8152602001612c6d612bde565b8152602001612c7a612bde565b905290565b61225d9190' +
- '5b80821115612c995760008155600101612c85565b509056fe657869744d61726b65743a' +
- '206765744163636f756e74536e617073686f74206661696c65646f6e6c7920756e697472' +
- '6f6c6c65722061646d696e2063616e206368616e676520627261696e73a165627a7a7230' +
- '582075d92d0e96eb01957b794704a02af0b7e3c5efe630de7186f3688639d7128e900029'
- )
-
- // 0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a
- // nonce: 7
- const mockCDaiIRMDeploymentData = (
- '0x608060405234801561001057600080fd5b506040516040806106638339810180604052' +
- '604081101561003057600080fd5b50805160209091015160019190915560005561061280' +
- '6100516000396000f3fe608060405234801561001057600080fd5b506004361061005757' +
- '60003560e01c806315f240531461005c5780631b3ed7221461009e5780631f68f20a1461' +
- '00b85780632191f92a146100c0578063a385fb96146100dc575b600080fd5b6100856004' +
- '803603606081101561007257600080fd5b50803590602081013590604001356100e4565b' +
- '6040805192835260208301919091528051918290030190f35b6100a661017d565b604080' +
- '51918252519081900360200190f35b6100a6610183565b6100c8610189565b6040805191' +
- '15158252519081900360200190f35b6100a661018e565b60008060006100f16105d3565b' +
- '6100f96105d3565b6101038888610195565b919450925090506000836004811115610118' +
- '57fe5b146101385782600481111561012957fe5b94506000935061017592505050565b60' +
- '006101426105d3565b61014f8362201480610312565b9092509050600082600381111561' +
- '016257fe5b1461016957fe5b51600096509450505050505b935093915050565b60005481' +
- '565b60015481565b600181565b6220148081565b600061019f6105d3565b6101a76105d3' +
- '565b60006101b16105d3565b6101bb878761037c565b9092509050600082600481111561' +
- '01ce57fe5b146101fc575060408051602080820183526000808352835191820190935291' +
- '8252919450909250905061030b565b60006102066105d3565b6102128360005461043e56' +
- '5b9092509050600082600381111561022557fe5b14610257575050604080516020808201' +
- '835260008083528351918201909352918252600396509450925061030b915050565b6000' +
- '6102616105d3565b61027383670de0b6b3a7640000610312565b90925090506000826003' +
- '81111561028657fe5b1461028d57fe5b60006102976105d3565b6102b183604051806020' +
- '0160405280600154815250610459565b909250905060008260038111156102c457fe5b14' +
- '6102fa57505060408051602080820183526000808352835191820190935291825260049a' +
- '509850965061030b95505050505050565b60009a509598509496505050505050505b9250' +
- '925092565b600061031c6105d3565b60008061032d866000015186610493565b90925090' +
- '50600082600381111561034057fe5b1461035f5750604080516020810190915260008152' +
- '9092509050610375565b6040805160208101909152908152600093509150505b92509290' +
- '50565b60006103866105d3565b826103a357505060408051602081019091526000808252' +
- '90610375565b6000806103b086866104be565b909250905060008260038111156103c357' +
- 'fe5b146103e4575050604080516020810190915260008152600192509050610375565b60' +
- '006103ee6105d3565b6103f887846104e4565b9092509050600082600381111561040b57' +
- 'fe5b1461042f575050604080516020810190915260008152600294509250610375915050' +
- '565b60009890975095505050505050565b60006104486105d3565b60008061032d866000' +
- '015186610594565b60006104636105d3565b600080610478866000015186600001516104' +
- 'be565b60408051602081019091529081529097909650945050505050565b600080826104' +
- 'a75750600190506000610375565b60008385816104b257fe5b0491509150925092905056' +
- '5b6000808383018481106104d657600092509050610375565b5060029150600090506103' +
- '75565b60006104ee6105d3565b60008061050386670de0b6b3a7640000610594565b9092' +
- '509050600082600381111561051657fe5b14610535575060408051602081019091526000' +
- '81529092509050610375565b6000806105428388610493565b9092509050600082600381' +
- '111561055557fe5b14610577575060408051602081019091526000815290945092506103' +
- '75915050565b604080516020810190915290815260009890975095505050505050565b60' +
- '0080836105a757506000905080610375565b838302838582816105b457fe5b04146105c8' +
- '57506002915060009050610375565b600092509050610375565b60405180602001604052' +
- '8060008152509056fea165627a7a7230582021d1e96de1a54e5aaf17c19ae397dd393fa0' +
- 'cd21afedd016b0e6d1fb0e4c749600290000000000000000000000000000000000000000' +
- '0000000000b1a2bc2ec50000000000000000000000000000000000000000000000000000' +
- '01aa535d3d0c0000'
- )
-
- // 0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB
- // nonce: 8
- const mockCUSDCIRMDeploymentData = (
- '0x608060405234801561001057600080fd5b506040516040806106638339810180604052' +
- '604081101561003057600080fd5b50805160209091015160019190915560005561061280' +
- '6100516000396000f3fe608060405234801561001057600080fd5b506004361061005757' +
- '60003560e01c806315f240531461005c5780631b3ed7221461009e5780631f68f20a1461' +
- '00b85780632191f92a146100c0578063a385fb96146100dc575b600080fd5b6100856004' +
- '803603606081101561007257600080fd5b50803590602081013590604001356100e4565b' +
- '6040805192835260208301919091528051918290030190f35b6100a661017d565b604080' +
- '51918252519081900360200190f35b6100a6610183565b6100c8610189565b6040805191' +
- '15158252519081900360200190f35b6100a661018e565b60008060006100f16105d3565b' +
- '6100f96105d3565b6101038888610195565b919450925090506000836004811115610118' +
- '57fe5b146101385782600481111561012957fe5b94506000935061017592505050565b60' +
- '006101426105d3565b61014f8362201480610312565b9092509050600082600381111561' +
- '016257fe5b1461016957fe5b51600096509450505050505b935093915050565b60005481' +
- '565b60015481565b600181565b6220148081565b600061019f6105d3565b6101a76105d3' +
- '565b60006101b16105d3565b6101bb878761037c565b9092509050600082600481111561' +
- '01ce57fe5b146101fc575060408051602080820183526000808352835191820190935291' +
- '8252919450909250905061030b565b60006102066105d3565b6102128360005461043e56' +
- '5b9092509050600082600381111561022557fe5b14610257575050604080516020808201' +
- '835260008083528351918201909352918252600396509450925061030b915050565b6000' +
- '6102616105d3565b61027383670de0b6b3a7640000610312565b90925090506000826003' +
- '81111561028657fe5b1461028d57fe5b60006102976105d3565b6102b183604051806020' +
- '0160405280600154815250610459565b909250905060008260038111156102c457fe5b14' +
- '6102fa57505060408051602080820183526000808352835191820190935291825260049a' +
- '509850965061030b95505050505050565b60009a509598509496505050505050505b9250' +
- '925092565b600061031c6105d3565b60008061032d866000015186610493565b90925090' +
- '50600082600381111561034057fe5b1461035f5750604080516020810190915260008152' +
- '9092509050610375565b6040805160208101909152908152600093509150505b92509290' +
- '50565b60006103866105d3565b826103a357505060408051602081019091526000808252' +
- '90610375565b6000806103b086866104be565b909250905060008260038111156103c357' +
- 'fe5b146103e4575050604080516020810190915260008152600192509050610375565b60' +
- '006103ee6105d3565b6103f887846104e4565b9092509050600082600381111561040b57' +
- 'fe5b1461042f575050604080516020810190915260008152600294509250610375915050' +
- '565b60009890975095505050505050565b60006104486105d3565b60008061032d866000' +
- '015186610594565b60006104636105d3565b600080610478866000015186600001516104' +
- 'be565b60408051602081019091529081529097909650945050505050565b600080826104' +
- 'a75750600190506000610375565b60008385816104b257fe5b0491509150925092905056' +
- '5b6000808383018481106104d657600092509050610375565b5060029150600090506103' +
- '75565b60006104ee6105d3565b60008061050386670de0b6b3a7640000610594565b9092' +
- '509050600082600381111561051657fe5b14610535575060408051602081019091526000' +
- '81529092509050610375565b6000806105428388610493565b9092509050600082600381' +
- '111561055557fe5b14610577575060408051602081019091526000815290945092506103' +
- '75915050565b604080516020810190915290815260009890975095505050505050565b60' +
- '0080836105a757506000905080610375565b838302838582816105b457fe5b04146105c8' +
- '57506002915060009050610375565b600092509050610375565b60405180602001604052' +
- '8060008152509056fea165627a7a7230582021d1e96de1a54e5aaf17c19ae397dd393fa0' +
- 'cd21afedd016b0e6d1fb0e4c749600290000000000000000000000000000000000000000' +
- '000000000000000000000000000000000000000000000000000000000000000000000000' +
- '02c68af0bb140000'
- )
-
- // 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC
- // nonce: 14
- const mockCDaiDeploymentData = (
- '0x60806040523480156200001157600080fd5b506040516200523c3803806200523c8339' +
- '81018060405260e08110156200003757600080fd5b815160208301516040840151606085' +
- '0151608086018051949693959294919392830192916401000000008111156200006e5760' +
- '0080fd5b820160208101848111156200008257600080fd5b815164010000000081118282' +
- '01871017156200009d57600080fd5b505092919060200180516401000000008111156200' +
- '00ba57600080fd5b82016020810184811115620000ce57600080fd5b8151640100000000' +
- '811182820187101715620000e957600080fd5b5050602090910151600160005560048054' +
- '6001600160a01b0319163317905560088690559092509050858585858585836200017057' +
- '6040517f08c379a000000000000000000000000000000000000000000000000000000000' +
- '81526004018080602001828103825260308152602001806200520c603091396040019150' +
- '5060405180910390fd5b600062000183876200036460201b60201c565b90508015620001' +
- 'f357604080517f08c379a000000000000000000000000000000000000000000000000000' +
- '000000815260206004820152601a60248201527f53657474696e6720636f6d7074726f6c' +
- '6c6572206661696c6564000000000000604482015290519081900360640190fd5b620002' +
- '03620004f760201b60201c565b600a55670de0b6b3a7640000600b556200022486620004' +
- 'fc602090811b901c565b905080156200027f576040517f08c379a0000000000000000000' +
- '000000000000000000000000000000000000008152600401808060200182810382526022' +
- '815260200180620051ea6022913960400191505060405180910390fd5b83516200029490' +
- '60019060208701906200071e565b508251620002aa9060029060208601906200071e565b' +
- '50506003555050601280546001600160a01b0319166001600160a01b038c811691909117' +
- '91829055604080517f18160ddd0000000000000000000000000000000000000000000000' +
- '0000000000815290519290911694506318160ddd93506004808201935060209291829003' +
- '018186803b1580156200032857600080fd5b505afa1580156200033d573d6000803e3d60' +
- '00fd5b505050506040513d60208110156200035457600080fd5b50620007c09750505050' +
- '50505050565b6004546000906001600160a01b0316331462000396576200038e6001603f' +
- '620006ae60201b60201c565b9050620004f2565b600654604080517e7e3dd20000000000' +
- '0000000000000000000000000000000000000000000000815290516001600160a01b0392' +
- '831692851691627e3dd2916004808301926020929190829003018186803b158015620003' +
- 'f557600080fd5b505afa1580156200040a573d6000803e3d6000fd5b505050506040513d' +
- '60208110156200042157600080fd5b50516200048f57604080517f08c379a00000000000' +
- '0000000000000000000000000000000000000000000000815260206004820152601c6024' +
- '8201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000' +
- '604482015290519081900360640190fd5b600680546001600160a01b0319166001600160' +
- 'a01b03858116918217909255604080519284168352602083019190915280517f7ac369db' +
- 'd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190' +
- 'a160005b9150505b919050565b435b90565b60045460009081906001600160a01b031633' +
- '1462000531576200052860016042620006ae60201b60201c565b915050620004f2565b62' +
- '000541620004f760201b60201c565b600a54146200055e5762000528600a6041620006ae' +
- '60201b60201c565b600760009054906101000a90046001600160a01b0316905082600160' +
- '0160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083' +
- '038186803b158015620005b057600080fd5b505afa158015620005c5573d6000803e3d60' +
- '00fd5b505050506040513d6020811015620005dc57600080fd5b50516200064a57604080' +
- '517f08c379a0000000000000000000000000000000000000000000000000000000008152' +
- '60206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65' +
- '642066616c736500000000604482015290519081900360640190fd5b6007805460016001' +
- '60a01b0319166001600160a01b0385811691821790925560408051928416835260208301' +
- '9190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d' +
- '72f9269281900390910190a16000620004ee565b60007f45b96fe442630264581b197e84' +
- 'bbada861235052c5a1aadfff9ea4e40a969aa0836010811115620006de57fe5b83604d81' +
- '1115620006eb57fe5b604080519283526020830191909152600082820152519081900360' +
- '600190a18260108111156200071757fe5b9392505050565b828054600181600116156101' +
- '000203166002900490600052602060002090601f016020900481019282601f1062000761' +
- '57805160ff191683800117855562000791565b8280016001018555821562000791579182' +
- '015b828111156200079157825182559160200191906001019062000774565b506200079f' +
- '929150620007a3565b5090565b620004f991905b808211156200079f5760008155600101' +
- '620007aa565b614a1a80620007d06000396000f3fe608060405234801561001057600080' +
- 'fd5b506004361061028a5760003560e01c80638f840ddd1161015c578063c37f68e21161' +
- '00ce578063f3fdb15a11610087578063f3fdb15a14610708578063f5e3c4621461071057' +
- '8063f851a44014610746578063f8f9da281461074e578063fca7820b14610756578063fe' +
- '9c44ae146107735761028a565b8063c37f68e214610626578063c5ebeaec146106725780' +
- '63db006a751461068f578063dd62ed3e146106ac578063e9c714f2146106da578063f2b3' +
- 'abbd146106e25761028a565b8063a9059cbb11610120578063a9059cbb14610586578063' +
- 'aa5af0fd146105b2578063ae9d70b0146105ba578063b2a02ff1146105c2578063b71d1a' +
- '0c146105f8578063bd6d894d1461061e5761028a565b80638f840ddd1461052b57806395' +
- 'd89b411461053357806395dd91931461053b578063a0712d6814610561578063a6afed95' +
- '1461057e5761028a565b80633af9e66911610200578063675d972c116101b9578063675d' +
- '972c146104c85780636c540baf146104d05780636f307dc3146104d857806370a0823114' +
- '6104e057806373acee9814610506578063852a12e31461050e5761028a565b80633af9e6' +
- '69146104475780633b1d21a21461046d5780634576b5db1461047557806347bd37181461' +
- '049b5780635fe3b567146104a3578063601a0bf1146104ab5761028a565b806318160ddd' +
- '1161025257806318160ddd146103a9578063182df0f5146103b157806323b872dd146103' +
- 'b95780632608f818146103ef578063267822471461041b578063313ce5671461043f5761' +
- '028a565b806306fdde031461028f578063095ea7b31461030c5780630e7527021461034c' +
- '578063173b99041461037b57806317bfdfbc14610383575b600080fd5b61029761077b56' +
- '5b6040805160208082528351818301528351919283929083019185019080838360005b83' +
- '8110156102d15781810151838201526020016102b9565b50505050905090810190601f16' +
- '80156102fe5780820380516001836020036101000a031916815260200191505b50925050' +
- '5060405180910390f35b6103386004803603604081101561032257600080fd5b50600160' +
- '0160a01b038135169060200135610808565b604080519115158252519081900360200190' +
- 'f35b6103696004803603602081101561036257600080fd5b5035610875565b6040805191' +
- '8252519081900360200190f35b610369610888565b610369600480360360208110156103' +
- '9957600080fd5b50356001600160a01b031661088e565b610369610951565b6103696109' +
- '57565b610338600480360360608110156103cf57600080fd5b506001600160a01b038135' +
- '811691602081013590911690604001356109bd565b610369600480360360408110156104' +
- '0557600080fd5b506001600160a01b038135169060200135610a29565b610423610a3c56' +
- '5b604080516001600160a01b039092168252519081900360200190f35b610369610a4b56' +
- '5b6103696004803603602081101561045d57600080fd5b50356001600160a01b0316610a' +
- '51565b610369610abf565b6103696004803603602081101561048b57600080fd5b503560' +
- '01600160a01b0316610ace565b610369610c23565b610423610c29565b61036960048036' +
- '0360208110156104c157600080fd5b5035610c38565b610369610cc6565b610369610ccc' +
- '565b610423610cd2565b610369600480360360208110156104f657600080fd5b50356001' +
- '600160a01b0316610ce1565b610369610cfc565b61036960048036036020811015610524' +
- '57600080fd5b5035610db6565b610369610dc1565b610297610dc7565b61036960048036' +
- '03602081101561055157600080fd5b50356001600160a01b0316610e1f565b6103696004' +
- '803603602081101561057757600080fd5b5035610e7f565b610369610e8a565b61033860' +
- '04803603604081101561059c57600080fd5b506001600160a01b03813516906020013561' +
- '1286565b6103696112f1565b6103696112f7565b610369600480360360608110156105d8' +
- '57600080fd5b506001600160a01b038135811691602081013590911690604001356115d1' +
- '565b6103696004803603602081101561060e57600080fd5b50356001600160a01b031661' +
- '188e565b610369611915565b61064c6004803603602081101561063c57600080fd5b5035' +
- '6001600160a01b03166119d0565b60408051948552602085019390935283830191909152' +
- '6060830152519081900360800190f35b6103696004803603602081101561068857600080' +
- 'fd5b5035611a65565b610369600480360360208110156106a557600080fd5b5035611a70' +
- '565b610369600480360360408110156106c257600080fd5b506001600160a01b03813581' +
- '16916020013516611a7b565b610369611aa6565b610369600480360360208110156106f8' +
- '57600080fd5b50356001600160a01b0316611b95565b610423611bcf565b610369600480' +
- '3603606081101561072657600080fd5b506001600160a01b038135811691602081013591' +
- '60409091013516611bde565b610423611beb565b610369611bfa565b6103696004803603' +
- '602081101561076c57600080fd5b5035611cd9565b610338611d13565b60018054604080' +
- '516020600284861615610100026000190190941693909304601f81018490048402820184' +
- '0190925281815292918301828280156108005780601f106107d557610100808354040283' +
- '529160200191610800565b820191906000526020600020905b8154815290600101906020' +
- '018083116107e357829003601f168201915b505050505081565b33600081815260106020' +
- '90815260408083206001600160a01b038716808552908352818420869055815186815291' +
- '51939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200a' +
- 'c8c7c3b925929081900390910190a360019150505b92915050565b600061088082611d18' +
- '565b90505b919050565b60095481565b60008054600101808255816108a1610e8a565b14' +
- '6108f65760408051600160e51b62461bcd02815260206004820152601660248201527f61' +
- '636372756520696e746572657374206661696c6564000000000000000000006044820152' +
- '90519081900360640190fd5b6108ff83610e1f565b91505b600054811461094b57604080' +
- '51600160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b' +
- '595b9d195c995902604482015290519081900360640190fd5b50919050565b600e548156' +
- '5b6000806000610964611d54565b9092509050600082600381111561097757fe5b146109' +
- 'b657604051600160e51b62461bcd02815260040180806020018281038252603581526020' +
- '01806149626035913960400191505060405180910390fd5b9150505b90565b6000805460' +
- '0101808255816109d433878787611e02565b1491505b6000548114610a21576040805160' +
- '0160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b595b' +
- '9d195c995902604482015290519081900360640190fd5b509392505050565b6000610a35' +
- '8383612116565b9392505050565b6005546001600160a01b031681565b60035481565b60' +
- '00610a5b6146bb565b6040518060200160405280610a6e611915565b90526001600160a0' +
- '1b0384166000908152600f6020526040812054919250908190610a9a9084906121a6565b' +
- '90925090506000826003811115610aad57fe5b14610ab757600080fd5b94935050505056' +
- '5b6000610ac96121fa565b905090565b6004546000906001600160a01b03163314610af6' +
- '57610aef6001603f61227d565b9050610883565b60065460408051600160e11b623f1ee9' +
- '02815290516001600160a01b0392831692851691627e3dd2916004808301926020929190' +
- '829003018186803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d' +
- '6000fd5b505050506040513d6020811015610b6857600080fd5b5051610bbe5760408051' +
- '600160e51b62461bcd02815260206004820152601c60248201527f6d61726b6572206d65' +
- '74686f642072657475726e65642066616c73650000000060448201529051908190036064' +
- '0190fd5b600680546001600160a01b0319166001600160a01b0385811691821790925560' +
- '4080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d59896' +
- '4a77501540ba6751eb0b3decf5870d9281900390910190a160009392505050565b600c54' +
- '81565b6006546001600160a01b031681565b6000805460010180825581610c4b610e8a56' +
- '5b90508015610c7157610c69816010811115610c6257fe5b603061227d565b9250506109' +
- '02565b610c7a846122e3565b925050600054811461094b5760408051600160e51b62461b' +
- 'cd02815260206004820152600a6024820152600160b21b691c994b595b9d195c99590260' +
- '4482015290519081900360640190fd5b60085481565b600a5481565b6012546001600160' +
- 'a01b031681565b6001600160a01b03166000908152600f602052604090205490565b6000' +
- '805460010180825581610d0f610e8a565b14610d645760408051600160e51b62461bcd02' +
- '815260206004820152601660248201527f61636372756520696e74657265737420666169' +
- '6c656400000000000000000000604482015290519081900360640190fd5b600c54915060' +
- '00548114610db25760408051600160e51b62461bcd02815260206004820152600a602482' +
- '0152600160b21b691c994b595b9d195c995902604482015290519081900360640190fd5b' +
- '5090565b600061088082612467565b600d5481565b600280546040805160206001841615' +
- '6101000260001901909316849004601f8101849004840282018401909252818152929183' +
- '01828280156108005780601f106107d55761010080835404028352916020019161080056' +
- '5b6000806000610e2d846124a4565b90925090506000826003811115610e4057fe5b1461' +
- '0a3557604051600160e51b62461bcd028152600401808060200182810382526037815260' +
- '2001806148366037913960400191505060405180910390fd5b600061088082612558565b' +
- '6000610e946146ce565b6007546001600160a01b03166315f24053610ead6121fa565b60' +
- '0c54600d546040518463ffffffff1660e01b815260040180848152602001838152602001' +
- '8281526020019350505050604080518083038186803b158015610ef457600080fd5b505a' +
- 'fa158015610f08573d6000803e3d6000fd5b505050506040513d6040811015610f1e5760' +
- '0080fd5b50805160209182015160408401819052918301526601c6bf526340001015610f' +
- '905760408051600160e51b62461bcd02815260206004820152601c60248201527f626f72' +
- '726f772072617465206973206162737572646c7920686967680000000060448201529051' +
- '9081900360640190fd5b602081015115610fb357610fab60056002836020015161259356' +
- '5b9150506109ba565b610fbb6125f9565b60608201819052600a54610fcf91906125fd56' +
- '5b6080830181905282826003811115610fe357fe5b6003811115610fee57fe5b90525060' +
- '0090508151600381111561100257fe5b1461100957fe5b61102960405180602001604052' +
- '8083604001518152508260800151612620565b60a083018190528282600381111561103d' +
- '57fe5b600381111561104857fe5b905250600090508151600381111561105c57fe5b1461' +
- '107d57610fab600960068360000151600381111561107857fe5b612593565b61108d8160' +
- 'a00151600c546121a6565b60c08301819052828260038111156110a157fe5b6003811115' +
- '6110ac57fe5b90525060009050815160038111156110c057fe5b146110dc57610fab6009' +
- '60018360000151600381111561107857fe5b6110ec8160c00151600c54612688565b60e0' +
- '83018190528282600381111561110057fe5b600381111561110b57fe5b90525060009050' +
- '8151600381111561111f57fe5b1461113b57610fab600960048360000151600381111561' +
- '107857fe5b61115c60405180602001604052806009548152508260c00151600d546126ae' +
- '565b61010083018190528282600381111561117157fe5b600381111561117c57fe5b9052' +
- '50600090508151600381111561119057fe5b146111ac57610fab60096005836000015160' +
- '0381111561107857fe5b6111bf8160a00151600b54600b546126ae565b61012083018190' +
- '52828260038111156111d457fe5b60038111156111df57fe5b9052506000905081516003' +
- '8111156111f357fe5b1461120f57610fab600960038360000151600381111561107857fe' +
- '5b606080820151600a55610120820151600b81905560e0830151600c8190556101008401' +
- '51600d5560c08401516040805191825260208201939093528083019190915290517f8753' +
- '52fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9929181900390' +
- '910190a1600091505090565b600080546001018082558161129d33338787611e02565b14' +
- '91505b60005481146112ea5760408051600160e51b62461bcd0281526020600482015260' +
- '0a6024820152600160b21b691c994b595b9d195c99590260448201529051908190036064' +
- '0190fd5b5092915050565b600b5481565b600080611302610957565b6007549091506000' +
- '9081906001600160a01b03166315f240536113236121fa565b600c54600d546040518463' +
- 'ffffffff1660e01b81526004018084815260200183815260200182815260200193505050' +
- '50604080518083038186803b15801561136a57600080fd5b505afa15801561137e573d60' +
- '00803e3d6000fd5b505050506040513d604081101561139457600080fd5b508051602090' +
- '910151909250905081156113e257604051600160e51b62461bcd02815260040180806020' +
- '01828103825260318152602001806148d56031913960400191505060405180910390fd5b' +
- '60006113ec6146bb565b611406604051806020016040528087815250600e54612620565b' +
- '9092509050600082600381111561141957fe5b1461145857604051600160e51b62461bcd' +
- '02815260040180806020018281038252603181526020018061486d603191396040019150' +
- '5060405180910390fd5b60006114626146bb565b61146e600c548461270a565b90925090' +
- '50600082600381111561148157fe5b146114c057604051600160e51b62461bcd02815260' +
- '04018080602001828103825260318152602001806147b160319139604001915050604051' +
- '80910390fd5b60006114ca6146bb565b6114fa6040518060200160405280670de0b6b3a7' +
- '6400008152506040518060200160405280600954815250612769565b9092509050600082' +
- '600381111561150d57fe5b1461154c57604051600160e51b62461bcd0281526004018080' +
- '6020018281038252603c815260200180614926603c913960400191505060405180910390' +
- 'fd5b60006115566146bb565b61156f60405180602001604052808b81525084876127a356' +
- '5b9092509050600082600381111561158257fe5b146115c157604051600160e51b62461b' +
- 'cd0281526004018080602001828103825260318152602001806148056031913960400191' +
- '505060405180910390fd5b519a505050505050505050505090565b600080546001018082' +
- '5560065460408051600160e01b63d02f7351028152306004820152336024820152600160' +
- '0160a01b0388811660448301528781166064830152608482018790529151859392909216' +
- '9163d02f73519160a48082019260209290919082900301818787803b15801561164a5760' +
- '0080fd5b505af115801561165e573d6000803e3d6000fd5b505050506040513d60208110' +
- '1561167457600080fd5b5051905080156116935761168b6003601b83612593565b925050' +
- '6109d8565b856001600160a01b0316856001600160a01b031614156116b95761168b6006' +
- '601c61227d565b6001600160a01b0385166000908152600f602052604081205481908190' +
- '6116e090886125fd565b909350915060008360038111156116f357fe5b14611716576117' +
- '0b6009601a85600381111561107857fe5b9550505050506109d8565b6001600160a01b03' +
- '89166000908152600f60205260409020546117399088612688565b909350905060008360' +
- '0381111561174c57fe5b146117645761170b6009601985600381111561107857fe5b6001' +
- '600160a01b038089166000818152600f60209081526040808320879055938d1680835291' +
- '84902085905583518b815293519193600080516020614906833981519152929081900390' +
- '910190a360065460408051600160e01b636d35bf91028152306004820152336024820152' +
- '6001600160a01b038c811660448301528b81166064830152608482018b90529151919092' +
- '1691636d35bf919160a480830192600092919082900301818387803b15801561181e5760' +
- '0080fd5b505af1158015611832573d6000803e3d6000fd5b506000925061183f91505056' +
- '5b9550505050506000548114610a215760408051600160e51b62461bcd02815260206004' +
- '820152600a6024820152600160b21b691c994b595b9d195c995902604482015290519081' +
- '900360640190fd5b6004546000906001600160a01b031633146118af57610aef60016045' +
- '61227d565b600580546001600160a01b038481166001600160a01b031983168117909355' +
- '6040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94' +
- '012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610a35565b60' +
- '00805460010180825581611928610e8a565b1461197d5760408051600160e51b62461bcd' +
- '02815260206004820152601660248201527f61636372756520696e746572657374206661' +
- '696c656400000000000000000000604482015290519081900360640190fd5b6119856109' +
- '57565b91506000548114610db25760408051600160e51b62461bcd028152602060048201' +
- '52600a6024820152600160b21b691c994b595b9d195c9959026044820152905190819003' +
- '60640190fd5b6001600160a01b0381166000908152600f60205260408120548190819081' +
- '908180806119fb896124a4565b935090506000816003811115611a0d57fe5b14611a2b57' +
- '60095b975060009650869550859450611a5e9350505050565b611a33611d54565b925090' +
- '506000816003811115611a4557fe5b14611a51576009611a15565b506000965091945092' +
- '5090505b9193509193565b6000610880826127ed565b600061088082612828565b600160' +
- '0160a01b0391821660009081526010602090815260408083209390941682529190915220' +
- '5490565b6005546000906001600160a01b031633141580611ac1575033155b15611ad957' +
- '611ad26001600061227d565b90506109ba565b60048054600580546001600160a01b0380' +
- '82166001600160a01b031980861682179687905590921690925560408051938316808552' +
- '949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f' +
- '21c4e8146d8519b417dc92908290030190a1600554604080516001600160a01b03808516' +
- '8252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b0' +
- '93e7720646a95b16a99281900390910190a160009250505090565b600080611ba0610e8a' +
- '565b90508015611bc657611bbe816010811115611bb757fe5b604061227d565b91505061' +
- '0883565b610a358361285e565b6007546001600160a01b031681565b6000610ab7848484' +
- '6129d1565b6004546001600160a01b031681565b600754600090819081906001600160a0' +
- '1b03166315f24053611c1a6121fa565b600c54600d546040518463ffffffff1660e01b81' +
- '526004018084815260200183815260200182815260200193505050506040805180830381' +
- '86803b158015611c6157600080fd5b505afa158015611c75573d6000803e3d6000fd5b50' +
- '5050506040513d6040811015611c8b57600080fd5b508051602090910151909250905081' +
- '156109b657604051600160e51b62461bcd02815260040180806020018281038252603781' +
- '526020018061489e6037913960400191505060405180910390fd5b600080546001018082' +
- '5581611cec610e8a565b90508015611d0a57610c69816010811115611d0357fe5b604661' +
- '227d565b610c7a84612adf565b600181565b6000805460010180825581611d2b610e8a56' +
- '5b90508015611d4957610c69816010811115611d4257fe5b603661227d565b610c7a3333' +
- '86612b82565b600080600e5460001415611d6f575050600854600090611dfe565b600061' +
- '1d796121fa565b90506000611d856146bb565b6000611d9684600c54600d54612fde565b' +
- '935090506000816003811115611da857fe5b14611dbc57945060009350611dfe92505050' +
- '565b611dc883600e5461301c565b925090506000816003811115611dda57fe5b14611dee' +
- '57945060009350611dfe92505050565b5051600094509250611dfe915050565b9091565b' +
- '60065460408051600160e31b6317b9b84b0281523060048201526001600160a01b038681' +
- '16602483015285811660448301526064820185905291516000938493169163bdcdc25891' +
- '608480830192602092919082900301818787803b158015611e6a57600080fd5b505af115' +
- '8015611e7e573d6000803e3d6000fd5b505050506040513d6020811015611e9457600080' +
- 'fd5b505190508015611eb357611eab6003604a83612593565b915050610ab7565b836001' +
- '600160a01b0316856001600160a01b03161415611ed957611eab6002604b61227d565b60' +
- '006001600160a01b038781169087161415611ef85750600019611f20565b506001600160' +
- 'a01b038086166000908152601060209081526040808320938a16835292905220545b6000' +
- '80600080611f3085896125fd565b90945092506000846003811115611f4357fe5b14611f' +
- '6157611f546009604b61227d565b9650505050505050610ab7565b6001600160a01b038a' +
- '166000908152600f6020526040902054611f8490896125fd565b90945091506000846003' +
- '811115611f9757fe5b14611fa857611f546009604c61227d565b6001600160a01b038916' +
- '6000908152600f6020526040902054611fcb9089612688565b9094509050600084600381' +
- '1115611fde57fe5b14611fef57611f546009604d61227d565b6001600160a01b03808b16' +
- '6000908152600f6020526040808220859055918b16815220819055600019851461204757' +
- '6001600160a01b03808b166000908152601060209081526040808320938f168352929052' +
- '208390555b886001600160a01b03168a6001600160a01b03166000805160206149068339' +
- '815191528a6040518082815260200191505060405180910390a360065460408051600160' +
- 'e11b63352b4a3f0281523060048201526001600160a01b038d811660248301528c811660' +
- '44830152606482018c905291519190921691636a56947e91608480830192600092919082' +
- '900301818387803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d' +
- '6000fd5b5060009250612107915050565b9b9a5050505050505050505050565b60008054' +
- '60010180825581612129610e8a565b9050801561214f5761214781601081111561214057' +
- 'fe5b603561227d565b9250506112a1565b61215a338686612b82565b9250506000548114' +
- '6112ea5760408051600160e51b62461bcd02815260206004820152600a60248201526001' +
- '60b21b691c994b595b9d195c995902604482015290519081900360640190fd5b60008060' +
- '006121b36146bb565b6121bd8686612620565b909250905060008260038111156121d057' +
- 'fe5b146121e157509150600090506121f3565b60006121ec826130cc565b935093505050' +
- '5b9250929050565b60125460408051600160e01b6370a082310281523060048201529051' +
- '6000926001600160a01b03169182916370a0823191602480820192602092909190829003' +
- '018186803b15801561224b57600080fd5b505afa15801561225f573d6000803e3d6000fd' +
- '5b505050506040513d602081101561227557600080fd5b505191505090565b60007f45b9' +
- '6fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836010811115' +
- '6122ac57fe5b83604d8111156122b857fe5b604080519283526020830191909152600082' +
- '820152519081900360600190a1826010811115610a3557fe5b6004546000908190819060' +
- '01600160a01b03163314612311576123086001603161227d565b92505050610883565b61' +
- '23196125f9565b600a541461232d57612308600a603361227d565b836123366121fa565b' +
- '101561234857612308600e603261227d565b600d5484111561235e576123086002603461' +
- '227d565b50600d54838103908111156123a757604051600160e51b62461bcd0281526004' +
- '018080602001828103825260248152602001806149cb6024913960400191505060405180' +
- '910390fd5b600d8190556004546123c2906001600160a01b0316856130db565b91506000' +
- '8260108111156123d257fe5b1461241157604051600160e51b62461bcd02815260040180' +
- '80602001828103825260238152602001806147e260239139604001915050604051809103' +
- '90fd5b600454604080516001600160a01b03909216825260208201869052818101839052' +
- '517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e9181' +
- '900360600190a16000949350505050565b600080546001018082558161247a610e8a565b' +
- '9050801561249857610c6981601081111561249157fe5b602761227d565b610c7a336000' +
- '8661319a565b6001600160a01b0381166000908152601160205260408120805482918291' +
- '829182916124db57506000945084935061255392505050565b6124eb8160000154600b54' +
- '6136af565b909450925060008460038111156124fe57fe5b146125135750919350600092' +
- '50612553915050565b6125218382600101546136ee565b90945091506000846003811115' +
- '61253457fe5b14612549575091935060009250612553915050565b506000945092505050' +
- '5b915091565b600080546001018082558161256b610e8a565b9050801561258957610c69' +
- '81601081111561258257fe5b601e61227d565b610c7a3385613719565b60007f45b96fe4' +
- '42630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156125' +
- 'c257fe5b84604d8111156125ce57fe5b6040805192835260208301919091528181018590' +
- '52519081900360600190a1836010811115610ab757fe5b4390565b600080838311612614' +
- '5750600090508183036121f3565b506003905060006121f3565b600061262a6146bb565b' +
- '60008061263b8660000151866136af565b9092509050600082600381111561264e57fe5b' +
- '1461266d575060408051602081019091526000815290925090506121f3565b6040805160' +
- '2081019091529081526000969095509350505050565b6000808383018481106126a05760' +
- '00925090506121f3565b5060029150600090506121f3565b60008060006126bb6146bb56' +
- '5b6126c58787612620565b909250905060008260038111156126d857fe5b146126e95750' +
- '915060009050612702565b6126fb6126f5826130cc565b86612688565b9350935050505b' +
- '935093915050565b60006127146146bb565b600080612729670de0b6b3a7640000876136' +
- 'af565b9092509050600082600381111561273c57fe5b1461275b57506040805160208101' +
- '9091526000815290925090506121f3565b6121ec81866000015161301c565b6000612773' +
- '6146bb565b600080612788866000015186600001516125fd565b60408051602081019091' +
- '529081529097909650945050505050565b60006127ad6146bb565b60006127b76146bb56' +
- '5b6127c18787613b67565b909250905060008260038111156127d457fe5b146127e35790' +
- '92509050612702565b6126fb8186613b67565b6000805460010180825581612800610e8a' +
- '565b9050801561281e57610c6981601081111561281757fe5b600861227d565b610c7a33' +
- '85613c50565b600080546001018082558161283b610e8a565b9050801561285257610c69' +
- '81601081111561249157fe5b610c7a3385600061319a565b600454600090819060016001' +
- '60a01b0316331461288157611bbe6001604261227d565b6128896125f9565b600a541461' +
- '289d57611bbe600a604161227d565b600760009054906101000a90046001600160a01b03' +
- '169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401' +
- '60206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d60' +
- '00803e3d6000fd5b505050506040513d602081101561291857600080fd5b505161296e57' +
- '60408051600160e51b62461bcd02815260206004820152601c60248201527f6d61726b65' +
- '72206d6574686f642072657475726e65642066616c736500000000604482015290519081' +
- '900360640190fd5b600780546001600160a01b0319166001600160a01b03858116918217' +
- '909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c' +
- '4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610a35565b60' +
- '008054600101808255816129e4610e8a565b90508015612a025761168b81601081111561' +
- '29fb57fe5b600f61227d565b836001600160a01b031663a6afed956040518163ffffffff' +
- '1660e01b8152600401602060405180830381600087803b158015612a3d57600080fd5b50' +
- '5af1158015612a51573d6000803e3d6000fd5b505050506040513d6020811015612a6757' +
- '600080fd5b505190508015612a875761168b816010811115612a8057fe5b601061227d56' +
- '5b612a9333878787613fbf565b9250506000548114610a215760408051600160e51b6246' +
- '1bcd02815260206004820152600a6024820152600160b21b691c994b595b9d195c995902' +
- '604482015290519081900360640190fd5b6004546000906001600160a01b03163314612b' +
- '0057610aef6001604761227d565b612b086125f9565b600a5414612b1c57610aef600a60' +
- '4861227d565b670de0b6b3a7640000821115612b3857610aef6002604961227d565b6009' +
- '805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af50684' +
- '10ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610a35565b' +
- '60065460408051600160e11b63120045310281523060048201526001600160a01b038681' +
- '1660248301528581166044830152606482018590529151600093849316916324008a6291' +
- '608480830192602092919082900301818787803b158015612bea57600080fd5b505af115' +
- '8015612bfe573d6000803e3d6000fd5b505050506040513d6020811015612c1457600080' +
- 'fd5b505190508015612c3357612c2b6003603883612593565b915050610a35565b612c3b' +
- '6125f9565b600a5414612c4f57612c2b600a603961227d565b612c57614728565b600160' +
- '0160a01b0385166000908152601160205260409020600101546060820152612c81856124' +
- 'a4565b6080830181905260208301826003811115612c9857fe5b6003811115612ca357fe' +
- '5b9052506000905081602001516003811115612cba57fe5b14612cdf57612cd660096037' +
- '8360200151600381111561107857fe5b92505050610a35565b600019841415612cf85760' +
- '808101516040820152612d00565b604081018490525b612d0e8682604001516144b3565b' +
- '81906010811115612d1b57fe5b90816010811115612d2857fe5b90525060008151601081' +
- '1115612d3a57fe5b14612d4c578051612cd690603c61227d565b612d5e81608001518260' +
- '4001516125fd565b60a0830181905260208301826003811115612d7557fe5b6003811115' +
- '612d8057fe5b9052506000905081602001516003811115612d9757fe5b14612db357612c' +
- 'd66009603a8360200151600381111561107857fe5b612dc3600c5482604001516125fd56' +
- '5b60c0830181905260208301826003811115612dda57fe5b6003811115612de557fe5b90' +
- '52506000905081602001516003811115612dfc57fe5b14612e1857612cd66009603b8360' +
- '200151600381111561107857fe5b612e268682604001516145ea565b8190601081111561' +
- '2e3357fe5b90816010811115612e4057fe5b905250600081516010811115612e5257fe5b' +
- '14612ea75760408051600160e51b62461bcd02815260206004820152601f60248201527f' +
- '726570617920626f72726f77207472616e7366657220696e206661696c65640060448201' +
- '5290519081900360640190fd5b60a080820180516001600160a01b038089166000818152' +
- '60116020908152604091829020948555600b5460019095019490945560c0870151600c81' +
- '90558188015195518251948e168552948401929092528281019490945260608201929092' +
- '52608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0' +
- '355478d6f5c362a1929181900390910190a1600654604080830151606084015182516001' +
- '60e01b631ededc910281523060048201526001600160a01b038b811660248301528a8116' +
- '6044830152606482019390935260848101919091529151921691631ededc919160a48082' +
- '019260009290919082900301818387803b158015612fb357600080fd5b505af115801561' +
- '2fc7573d6000803e3d6000fd5b5060009250612fd4915050565b9695505050505050565b' +
- '600080600080612fee8787612688565b9092509050600082600381111561300157fe5b14' +
- '6130125750915060009050612702565b6126fb81866125fd565b60006130266146bb565b' +
- '60008061303b86670de0b6b3a76400006136af565b909250905060008260038111156130' +
- '4e57fe5b1461306d575060408051602081019091526000815290925090506121f3565b60' +
- '008061307a83886136ee565b9092509050600082600381111561308d57fe5b146130af57' +
- '5060408051602081019091526000815290945092506121f3915050565b60408051602081' +
- '0190915290815260009890975095505050505050565b51670de0b6b3a764000090049056' +
- '5b60125460408051600160e01b63a9059cbb0281526001600160a01b0385811660048301' +
- '5260248201859052915160009392909216918391839163a9059cbb916044808201928692' +
- '90919082900301818387803b15801561313a57600080fd5b505af115801561314e573d60' +
- '00803e3d6000fd5b505050503d60008114613168576020811461317257600080fd5b6000' +
- '19915061317e565b60206000803e60005191505b508061318f5760109250505061086f56' +
- '5b506000949350505050565b60008215806131a7575081155b6131e557604051600160e5' +
- '1b62461bcd02815260040180806020018281038252603481526020018061499760349139' +
- '60400191505060405180910390fd5b6131ed614728565b6131f5611d54565b6040830181' +
- '90526020830182600381111561320c57fe5b600381111561321757fe5b90525060009050' +
- '8160200151600381111561322e57fe5b1461324a57612c2b6009602b8360200151600381' +
- '111561107857fe5b83156132cb5760608101849052604080516020810182529082015181' +
- '5261327190856121a6565b608083018190526020830182600381111561328857fe5b6003' +
- '81111561329357fe5b90525060009050816020015160038111156132aa57fe5b146132c6' +
- '57612c2b600960298360200151600381111561107857fe5b613344565b6132e783604051' +
- '806020016040528084604001518152506146a4565b606083018190526020830182600381' +
- '11156132fe57fe5b600381111561330957fe5b9052506000905081602001516003811115' +
- '61332057fe5b1461333c57612c2b6009602a8360200151600381111561107857fe5b6080' +
- '81018390525b600654606082015160408051600160e01b63eabe7d910281523060048201' +
- '526001600160a01b03898116602483015260448201939093529051600093929092169163' +
- 'eabe7d919160648082019260209290919082900301818787803b1580156133ac57600080' +
- 'fd5b505af11580156133c0573d6000803e3d6000fd5b505050506040513d602081101561' +
- '33d657600080fd5b5051905080156133ed57612cd66003602883612593565b6133f56125' +
- 'f9565b600a541461340957612cd6600a602c61227d565b613419600e5483606001516125' +
- 'fd565b60a084018190526020840182600381111561343057fe5b600381111561343b57fe' +
- '5b905250600090508260200151600381111561345257fe5b1461346e57612cd66009602e' +
- '8460200151600381111561107857fe5b6001600160a01b0386166000908152600f602052' +
- '6040902054606083015161349691906125fd565b60c08401819052602084018260038111' +
- '156134ad57fe5b60038111156134b857fe5b905250600090508260200151600381111561' +
- '34cf57fe5b146134eb57612cd66009602d8460200151600381111561107857fe5b816080' +
- '01516134f86121fa565b101561350a57612cd6600e602f61227d565b6135188683608001' +
- '516130db565b8290601081111561352557fe5b9081601081111561353257fe5b90525060' +
- '008251601081111561354457fe5b146135995760408051600160e51b62461bcd02815260' +
- '206004820152601a60248201527f72656465656d207472616e73666572206f7574206661' +
- '696c6564000000000000604482015290519081900360640190fd5b60a0820151600e5560' +
- 'c08201516001600160a01b0387166000818152600f602090815260409182902093909355' +
- '6060850151815190815290513093600080516020614906833981519152928290030190a3' +
- '6080820151606080840151604080516001600160a01b038b168152602081019490945283' +
- '810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4' +
- 'ec31a9299281900390910190a16006546080830151606084015160408051600160e01b63' +
- '51dff9890281523060048201526001600160a01b038b8116602483015260448201949094' +
- '5260648101929092525191909216916351dff98991608480830192600092919082900301' +
- '818387803b158015612fb357600080fd5b600080836136c2575060009050806121f3565b' +
- '838302838582816136cf57fe5b04146136e3575060029150600090506121f3565b600092' +
- '5090506121f3565b6000808261370257506001905060006121f3565b600083858161370d' +
- '57fe5b04915091509250929050565b60065460408051600160e01b634ef4c3e102815230' +
- '60048201526001600160a01b038581166024830152604482018590529151600093849316' +
- '91634ef4c3e191606480830192602092919082900301818787803b158015613779576000' +
- '80fd5b505af115801561378d573d6000803e3d6000fd5b505050506040513d6020811015' +
- '6137a357600080fd5b5051905080156137c2576137ba6003601f83612593565b91505061' +
- '086f565b6137ca6125f9565b600a54146137de576137ba600a602261227d565b6137e661' +
- '4766565b6137f085856144b3565b819060108111156137fd57fe5b908160108111156138' +
- '0a57fe5b90525060008151601081111561381c57fe5b1461383757805161382e90602661' +
- '227d565b9250505061086f565b61383f611d54565b604083018190526020830182600381' +
- '111561385657fe5b600381111561386157fe5b9052506000905081602001516003811115' +
- '61387857fe5b146138945761382e600960218360200151600381111561107857fe5b6138' +
- 'b084604051806020016040528084604001518152506146a4565b60608301819052602083' +
- '018260038111156138c757fe5b60038111156138d257fe5b905250600090508160200151' +
- '60038111156138e957fe5b146139055761382e6009602083602001516003811115611078' +
- '57fe5b613915600e548260600151612688565b6080830181905260208301826003811115' +
- '61392c57fe5b600381111561393757fe5b90525060009050816020015160038111156139' +
- '4e57fe5b1461396a5761382e600960248360200151600381111561107857fe5b60016001' +
- '60a01b0385166000908152600f602052604090205460608201516139929190612688565b' +
- '60a08301819052602083018260038111156139a957fe5b60038111156139b457fe5b9052' +
- '5060009050816020015160038111156139cb57fe5b146139e75761382e60096023836020' +
- '0151600381111561107857fe5b6139f185856145ea565b819060108111156139fe57fe5b' +
- '90816010811115613a0b57fe5b905250600081516010811115613a1d57fe5b14613a2f57' +
- '805161382e90602561227d565b6080810151600e5560a08101516001600160a01b038616' +
- '6000818152600f6020908152604091829020939093556060808501518251938452938301' +
- '88905282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef' +
- '26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160' +
- 'a01b0387169130916000805160206149068339815191529181900360200190a360065460' +
- '6082015160408051600160e01b6341c728b90281523060048201526001600160a01b0389' +
- '81166024830152604482018990526064820193909352905191909216916341c728b99160' +
- '8480830192600092919082900301818387803b158015613b3d57600080fd5b505af11580' +
- '15613b51573d6000803e3d6000fd5b5060009250613b5e915050565b9594505050505056' +
- '5b6000613b716146bb565b600080613b86866000015186600001516136af565b90925090' +
- '506000826003811115613b9957fe5b14613bb85750604080516020810190915260008152' +
- '90925090506121f3565b600080613bcd6706f05b59d3b2000084612688565b9092509050' +
- '6000826003811115613be057fe5b14613c02575060408051602081019091526000815290' +
- '945092506121f3915050565b600080613c1783670de0b6b3a76400006136ee565b909250' +
- '90506000826003811115613c2a57fe5b14613c3157fe5b60408051602081019091529081' +
- '5260009a909950975050505050505050565b60065460408051600160e21b63368f515302' +
- '81523060048201526001600160a01b038581166024830152604482018590529151600093' +
- '8493169163da3d454c91606480830192602092919082900301818787803b158015613cb0' +
- '57600080fd5b505af1158015613cc4573d6000803e3d6000fd5b505050506040513d6020' +
- '811015613cda57600080fd5b505190508015613cf1576137ba6003600e83612593565b61' +
- '3cf96125f9565b600a5414613d0c576137ba600a8061227d565b82613d156121fa565b10' +
- '15613d27576137ba600e600961227d565b613d2f614780565b613d38856124a4565b6040' +
- '830181905260208301826003811115613d4f57fe5b6003811115613d5a57fe5b90525060' +
- '00905081602001516003811115613d7157fe5b14613d8d5761382e600960078360200151' +
- '600381111561107857fe5b613d9b816040015185612688565b6060830181905260208301' +
- '826003811115613db257fe5b6003811115613dbd57fe5b90525060009050816020015160' +
- '03811115613dd457fe5b14613df05761382e6009600c8360200151600381111561107857' +
- 'fe5b613dfc600c5485612688565b6080830181905260208301826003811115613e1357fe' +
- '5b6003811115613e1e57fe5b9052506000905081602001516003811115613e3557fe5b14' +
- '613e515761382e6009600b8360200151600381111561107857fe5b613e5b85856130db56' +
- '5b81906010811115613e6857fe5b90816010811115613e7557fe5b905250600081516010' +
- '811115613e8757fe5b14613edc5760408051600160e51b62461bcd028152602060048201' +
- '52601a60248201527f626f72726f77207472616e73666572206f7574206661696c656400' +
- '0000000000604482015290519081900360640190fd5b606080820180516001600160a01b' +
- '038816600081815260116020908152604091829020938455600b54600190940193909355' +
- '608080870151600c819055945182519384529383018a9052828201939093529381019290' +
- '925291517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab' +
- '80929181900390910190a160065460408051600160e01b635c7786050281523060048201' +
- '526001600160a01b0388811660248301526044820188905291519190921691635c778605' +
- '91606480830192600092919082900301818387803b158015613b3d57600080fd5b600654' +
- '60408051600160e11b632fe3f38f0281523060048201526001600160a01b038481166024' +
- '830152878116604483015286811660648301526084820186905291516000938493169163' +
- '5fc7e71e9160a480830192602092919082900301818787803b15801561402f57600080fd' +
- '5b505af1158015614043573d6000803e3d6000fd5b505050506040513d60208110156140' +
- '5957600080fd5b50519050801561407057611eab6003601283612593565b6140786125f9' +
- '565b600a541461408c57611eab600a601661227d565b6140946125f9565b836001600160' +
- 'a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381' +
- '86803b1580156140cd57600080fd5b505afa1580156140e1573d6000803e3d6000fd5b50' +
- '5050506040513d60208110156140f757600080fd5b50511461410a57611eab600a601161' +
- '227d565b856001600160a01b0316856001600160a01b0316141561413057611eab600660' +
- '1761227d565b8361414157611eab6007601561227d565b60001984141561415757611eab' +
- '6007601461227d565b60065460408051600160e01b63c488847b02815230600482015260' +
- '01600160a01b038681166024830152604482018890528251600094859492169263c48884' +
- '7b926064808301939192829003018186803b1580156141b457600080fd5b505afa158015' +
- '6141c8573d6000803e3d6000fd5b505050506040513d60408110156141de57600080fd5b' +
- '50805160209091015190925090508115614209576141ff6004601384612593565b935050' +
- '5050610ab7565b846001600160a01b03166370a08231886040518263ffffffff1660e01b' +
- '815260040180826001600160a01b03166001600160a01b03168152602001915050602060' +
- '40518083038186803b15801561425f57600080fd5b505afa158015614273573d6000803e' +
- '3d6000fd5b505050506040513d602081101561428957600080fd5b505181111561429e57' +
- '6141ff600d601d61227d565b60006142ab898989612b82565b905080156142d4576142c9' +
- '8160108111156142c257fe5b601861227d565b945050505050610ab7565b604080516001' +
- '60e01b63b2a02ff10281526001600160a01b038b811660048301528a8116602483015260' +
- '448201859052915160009289169163b2a02ff19160648083019260209291908290030181' +
- '8787803b15801561433257600080fd5b505af1158015614346573d6000803e3d6000fd5b' +
- '505050506040513d602081101561435c57600080fd5b5051905080156143b65760408051' +
- '600160e51b62461bcd02815260206004820152601460248201527f746f6b656e20736569' +
- '7a757265206661696c656400000000000000000000000060448201529051908190036064' +
- '0190fd5b604080516001600160a01b03808d168252808c1660208301528183018b905289' +
- '1660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a33' +
- '5ab1e7d6215a4b2484d8bb529181900360a00190a160065460408051600160e01b6347ef' +
- '3b3b0281523060048201526001600160a01b038a811660248301528d811660448301528c' +
- '81166064830152608482018c905260a48201879052915191909216916347ef3b3b9160c4' +
- '80830192600092919082900301818387803b15801561448457600080fd5b505af1158015' +
- '614498573d6000803e3d6000fd5b50600092506144a5915050565b9a9950505050505050' +
- '505050565b60125460408051600160e11b636eb1769f0281526001600160a01b03858116' +
- '6004830152306024830152915160009392909216918491839163dd62ed3e916044808201' +
- '92602092909190829003018186803b15801561451157600080fd5b505afa158015614525' +
- '573d6000803e3d6000fd5b505050506040513d602081101561453b57600080fd5b505110' +
- '1561454d57600c91505061086f565b82816001600160a01b03166370a082318660405182' +
- '63ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152' +
- '60200191505060206040518083038186803b1580156145a457600080fd5b505afa158015' +
- '6145b8573d6000803e3d6000fd5b505050506040513d60208110156145ce57600080fd5b' +
- '505110156145e057600d91505061086f565b5060009392505050565b6012546040805160' +
- '0160e01b6323b872dd0281526001600160a01b0385811660048301523060248301526044' +
- '820185905291516000939290921691839183916323b872dd916064808201928692909190' +
- '82900301818387803b15801561464f57600080fd5b505af1158015614663573d6000803e' +
- '3d6000fd5b505050503d6000811461467d576020811461468757600080fd5b6000199150' +
- '614693565b60206000803e60005191505b508061318f57600f9250505061086f565b6000' +
- '8060006146b16146bb565b6121bd868661270a565b604051806020016040528060008152' +
- '5090565b6040805161014081019091528060008152602001600081526020016000815260' +
- '200160008152602001600081526020016147066146bb565b815260200160008152602001' +
- '6000815260200160008152602001600081525090565b6040805160e08101909152806000' +
- '815260200160008152602001600081526020016000815260200160008152602001600081' +
- '52602001600081525090565b6040805160c0810190915280600081526020016000614706' +
- '565b6040805160a081019091528060008152602001600081526020016000815260200160' +
- '00815260200160008152509056fe737570706c7952617465506572426c6f636b3a206361' +
- '6c63756c6174696e6720626f72726f7773506572206661696c6564726564756365207265' +
- '736572766573207472616e73666572206f7574206661696c6564737570706c7952617465' +
- '506572426c6f636b3a2063616c63756c6174696e6720737570706c795261746520666169' +
- '6c6564626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e63' +
- '6553746f726564496e7465726e616c206661696c6564737570706c795261746550657242' +
- '6c6f636b3a2063616c63756c6174696e6720756e6465726c79696e67206661696c656462' +
- '6f72726f7752617465506572426c6f636b3a20696e746572657374526174654d6f64656c' +
- '2e626f72726f7752617465206661696c6564737570706c7952617465506572426c6f636b' +
- '3a2063616c63756c6174696e6720626f72726f7752617465206661696c6564ddf252ad1b' +
- 'e2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef737570706c79526174' +
- '65506572426c6f636b3a2063616c63756c6174696e67206f6e654d696e75735265736572' +
- '7665466163746f72206661696c656465786368616e67655261746553746f7265643a2065' +
- '786368616e67655261746553746f726564496e7465726e616c206661696c65646f6e6520' +
- '6f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e20' +
- '6d757374206265207a65726f72656475636520726573657276657320756e657870656374' +
- '656420756e646572666c6f77a165627a7a72305820ae92d0e3e70b657d01891c7457bc6c' +
- '8a5ce2401a1a8857f346a2fa9af4627145002953657474696e6720696e74657265737420' +
- '72617465206d6f64656c206661696c6564496e697469616c2065786368616e6765207261' +
- '7465206d7573742062652067726561746572207468616e207a65726f2e' +
- '00000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359' + // dai
- '0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b' + // troll
- '000000000000000000000000a1046abfc2598f48c44fb320d281d3f3c0733c9a' + // IRM
- '000000000000000000000000000000000000000000a56fa5b99019a5c8000000' +
- '00000000000000000000000000000000000000000000000000000000000000e0' +
- '0000000000000000000000000000000000000000000000000000000000000120' +
- '0000000000000000000000000000000000000000000000000000000000000008' +
- '000000000000000000000000000000000000000000000000000000000000000c' +
- '436f6d706f756e64204461690000000000000000000000000000000000000000' +
- '0000000000000000000000000000000000000000000000000000000000000004' +
- '6344414900000000000000000000000000000000000000000000000000000000'
- )
-
- // 0x39AA39c021dfbaE8faC545936693aC917d5E7563
- // nonce: 17
- const mockCUSDCDeploymentData = (
- '0x60806040523480156200001157600080fd5b506040516200523c3803806200523c8339' +
- '81018060405260e08110156200003757600080fd5b815160208301516040840151606085' +
- '0151608086018051949693959294919392830192916401000000008111156200006e5760' +
- '0080fd5b820160208101848111156200008257600080fd5b815164010000000081118282' +
- '01871017156200009d57600080fd5b505092919060200180516401000000008111156200' +
- '00ba57600080fd5b82016020810184811115620000ce57600080fd5b8151640100000000' +
- '811182820187101715620000e957600080fd5b5050602090910151600160005560048054' +
- '6001600160a01b0319163317905560088690559092509050858585858585836200017057' +
- '6040517f08c379a000000000000000000000000000000000000000000000000000000000' +
- '81526004018080602001828103825260308152602001806200520c603091396040019150' +
- '5060405180910390fd5b600062000183876200036460201b60201c565b90508015620001' +
- 'f357604080517f08c379a000000000000000000000000000000000000000000000000000' +
- '000000815260206004820152601a60248201527f53657474696e6720636f6d7074726f6c' +
- '6c6572206661696c6564000000000000604482015290519081900360640190fd5b620002' +
- '03620004f760201b60201c565b600a55670de0b6b3a7640000600b556200022486620004' +
- 'fc602090811b901c565b905080156200027f576040517f08c379a0000000000000000000' +
- '000000000000000000000000000000000000008152600401808060200182810382526022' +
- '815260200180620051ea6022913960400191505060405180910390fd5b83516200029490' +
- '60019060208701906200071e565b508251620002aa9060029060208601906200071e565b' +
- '50506003555050601280546001600160a01b0319166001600160a01b038c811691909117' +
- '91829055604080517f18160ddd0000000000000000000000000000000000000000000000' +
- '0000000000815290519290911694506318160ddd93506004808201935060209291829003' +
- '018186803b1580156200032857600080fd5b505afa1580156200033d573d6000803e3d60' +
- '00fd5b505050506040513d60208110156200035457600080fd5b50620007c09750505050' +
- '50505050565b6004546000906001600160a01b0316331462000396576200038e6001603f' +
- '620006ae60201b60201c565b9050620004f2565b600654604080517e7e3dd20000000000' +
- '0000000000000000000000000000000000000000000000815290516001600160a01b0392' +
- '831692851691627e3dd2916004808301926020929190829003018186803b158015620003' +
- 'f557600080fd5b505afa1580156200040a573d6000803e3d6000fd5b505050506040513d' +
- '60208110156200042157600080fd5b50516200048f57604080517f08c379a00000000000' +
- '0000000000000000000000000000000000000000000000815260206004820152601c6024' +
- '8201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000' +
- '604482015290519081900360640190fd5b600680546001600160a01b0319166001600160' +
- 'a01b03858116918217909255604080519284168352602083019190915280517f7ac369db' +
- 'd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190' +
- 'a160005b9150505b919050565b435b90565b60045460009081906001600160a01b031633' +
- '1462000531576200052860016042620006ae60201b60201c565b915050620004f2565b62' +
- '000541620004f760201b60201c565b600a54146200055e5762000528600a6041620006ae' +
- '60201b60201c565b600760009054906101000a90046001600160a01b0316905082600160' +
- '0160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083' +
- '038186803b158015620005b057600080fd5b505afa158015620005c5573d6000803e3d60' +
- '00fd5b505050506040513d6020811015620005dc57600080fd5b50516200064a57604080' +
- '517f08c379a0000000000000000000000000000000000000000000000000000000008152' +
- '60206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65' +
- '642066616c736500000000604482015290519081900360640190fd5b6007805460016001' +
- '60a01b0319166001600160a01b0385811691821790925560408051928416835260208301' +
- '9190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d' +
- '72f9269281900390910190a16000620004ee565b60007f45b96fe442630264581b197e84' +
- 'bbada861235052c5a1aadfff9ea4e40a969aa0836010811115620006de57fe5b83604d81' +
- '1115620006eb57fe5b604080519283526020830191909152600082820152519081900360' +
- '600190a18260108111156200071757fe5b9392505050565b828054600181600116156101' +
- '000203166002900490600052602060002090601f016020900481019282601f1062000761' +
- '57805160ff191683800117855562000791565b8280016001018555821562000791579182' +
- '015b828111156200079157825182559160200191906001019062000774565b506200079f' +
- '929150620007a3565b5090565b620004f991905b808211156200079f5760008155600101' +
- '620007aa565b614a1a80620007d06000396000f3fe608060405234801561001057600080' +
- 'fd5b506004361061028a5760003560e01c80638f840ddd1161015c578063c37f68e21161' +
- '00ce578063f3fdb15a11610087578063f3fdb15a14610708578063f5e3c4621461071057' +
- '8063f851a44014610746578063f8f9da281461074e578063fca7820b14610756578063fe' +
- '9c44ae146107735761028a565b8063c37f68e214610626578063c5ebeaec146106725780' +
- '63db006a751461068f578063dd62ed3e146106ac578063e9c714f2146106da578063f2b3' +
- 'abbd146106e25761028a565b8063a9059cbb11610120578063a9059cbb14610586578063' +
- 'aa5af0fd146105b2578063ae9d70b0146105ba578063b2a02ff1146105c2578063b71d1a' +
- '0c146105f8578063bd6d894d1461061e5761028a565b80638f840ddd1461052b57806395' +
- 'd89b411461053357806395dd91931461053b578063a0712d6814610561578063a6afed95' +
- '1461057e5761028a565b80633af9e66911610200578063675d972c116101b9578063675d' +
- '972c146104c85780636c540baf146104d05780636f307dc3146104d857806370a0823114' +
- '6104e057806373acee9814610506578063852a12e31461050e5761028a565b80633af9e6' +
- '69146104475780633b1d21a21461046d5780634576b5db1461047557806347bd37181461' +
- '049b5780635fe3b567146104a3578063601a0bf1146104ab5761028a565b806318160ddd' +
- '1161025257806318160ddd146103a9578063182df0f5146103b157806323b872dd146103' +
- 'b95780632608f818146103ef578063267822471461041b578063313ce5671461043f5761' +
- '028a565b806306fdde031461028f578063095ea7b31461030c5780630e7527021461034c' +
- '578063173b99041461037b57806317bfdfbc14610383575b600080fd5b61029761077b56' +
- '5b6040805160208082528351818301528351919283929083019185019080838360005b83' +
- '8110156102d15781810151838201526020016102b9565b50505050905090810190601f16' +
- '80156102fe5780820380516001836020036101000a031916815260200191505b50925050' +
- '5060405180910390f35b6103386004803603604081101561032257600080fd5b50600160' +
- '0160a01b038135169060200135610808565b604080519115158252519081900360200190' +
- 'f35b6103696004803603602081101561036257600080fd5b5035610875565b6040805191' +
- '8252519081900360200190f35b610369610888565b610369600480360360208110156103' +
- '9957600080fd5b50356001600160a01b031661088e565b610369610951565b6103696109' +
- '57565b610338600480360360608110156103cf57600080fd5b506001600160a01b038135' +
- '811691602081013590911690604001356109bd565b610369600480360360408110156104' +
- '0557600080fd5b506001600160a01b038135169060200135610a29565b610423610a3c56' +
- '5b604080516001600160a01b039092168252519081900360200190f35b610369610a4b56' +
- '5b6103696004803603602081101561045d57600080fd5b50356001600160a01b0316610a' +
- '51565b610369610abf565b6103696004803603602081101561048b57600080fd5b503560' +
- '01600160a01b0316610ace565b610369610c23565b610423610c29565b61036960048036' +
- '0360208110156104c157600080fd5b5035610c38565b610369610cc6565b610369610ccc' +
- '565b610423610cd2565b610369600480360360208110156104f657600080fd5b50356001' +
- '600160a01b0316610ce1565b610369610cfc565b61036960048036036020811015610524' +
- '57600080fd5b5035610db6565b610369610dc1565b610297610dc7565b61036960048036' +
- '03602081101561055157600080fd5b50356001600160a01b0316610e1f565b6103696004' +
- '803603602081101561057757600080fd5b5035610e7f565b610369610e8a565b61033860' +
- '04803603604081101561059c57600080fd5b506001600160a01b03813516906020013561' +
- '1286565b6103696112f1565b6103696112f7565b610369600480360360608110156105d8' +
- '57600080fd5b506001600160a01b038135811691602081013590911690604001356115d1' +
- '565b6103696004803603602081101561060e57600080fd5b50356001600160a01b031661' +
- '188e565b610369611915565b61064c6004803603602081101561063c57600080fd5b5035' +
- '6001600160a01b03166119d0565b60408051948552602085019390935283830191909152' +
- '6060830152519081900360800190f35b6103696004803603602081101561068857600080' +
- 'fd5b5035611a65565b610369600480360360208110156106a557600080fd5b5035611a70' +
- '565b610369600480360360408110156106c257600080fd5b506001600160a01b03813581' +
- '16916020013516611a7b565b610369611aa6565b610369600480360360208110156106f8' +
- '57600080fd5b50356001600160a01b0316611b95565b610423611bcf565b610369600480' +
- '3603606081101561072657600080fd5b506001600160a01b038135811691602081013591' +
- '60409091013516611bde565b610423611beb565b610369611bfa565b6103696004803603' +
- '602081101561076c57600080fd5b5035611cd9565b610338611d13565b60018054604080' +
- '516020600284861615610100026000190190941693909304601f81018490048402820184' +
- '0190925281815292918301828280156108005780601f106107d557610100808354040283' +
- '529160200191610800565b820191906000526020600020905b8154815290600101906020' +
- '018083116107e357829003601f168201915b505050505081565b33600081815260106020' +
- '90815260408083206001600160a01b038716808552908352818420869055815186815291' +
- '51939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200a' +
- 'c8c7c3b925929081900390910190a360019150505b92915050565b600061088082611d18' +
- '565b90505b919050565b60095481565b60008054600101808255816108a1610e8a565b14' +
- '6108f65760408051600160e51b62461bcd02815260206004820152601660248201527f61' +
- '636372756520696e746572657374206661696c6564000000000000000000006044820152' +
- '90519081900360640190fd5b6108ff83610e1f565b91505b600054811461094b57604080' +
- '51600160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b' +
- '595b9d195c995902604482015290519081900360640190fd5b50919050565b600e548156' +
- '5b6000806000610964611d54565b9092509050600082600381111561097757fe5b146109' +
- 'b657604051600160e51b62461bcd02815260040180806020018281038252603581526020' +
- '01806149626035913960400191505060405180910390fd5b9150505b90565b6000805460' +
- '0101808255816109d433878787611e02565b1491505b6000548114610a21576040805160' +
- '0160e51b62461bcd02815260206004820152600a6024820152600160b21b691c994b595b' +
- '9d195c995902604482015290519081900360640190fd5b509392505050565b6000610a35' +
- '8383612116565b9392505050565b6005546001600160a01b031681565b60035481565b60' +
- '00610a5b6146bb565b6040518060200160405280610a6e611915565b90526001600160a0' +
- '1b0384166000908152600f6020526040812054919250908190610a9a9084906121a6565b' +
- '90925090506000826003811115610aad57fe5b14610ab757600080fd5b94935050505056' +
- '5b6000610ac96121fa565b905090565b6004546000906001600160a01b03163314610af6' +
- '57610aef6001603f61227d565b9050610883565b60065460408051600160e11b623f1ee9' +
- '02815290516001600160a01b0392831692851691627e3dd2916004808301926020929190' +
- '829003018186803b158015610b3e57600080fd5b505afa158015610b52573d6000803e3d' +
- '6000fd5b505050506040513d6020811015610b6857600080fd5b5051610bbe5760408051' +
- '600160e51b62461bcd02815260206004820152601c60248201527f6d61726b6572206d65' +
- '74686f642072657475726e65642066616c73650000000060448201529051908190036064' +
- '0190fd5b600680546001600160a01b0319166001600160a01b0385811691821790925560' +
- '4080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d59896' +
- '4a77501540ba6751eb0b3decf5870d9281900390910190a160009392505050565b600c54' +
- '81565b6006546001600160a01b031681565b6000805460010180825581610c4b610e8a56' +
- '5b90508015610c7157610c69816010811115610c6257fe5b603061227d565b9250506109' +
- '02565b610c7a846122e3565b925050600054811461094b5760408051600160e51b62461b' +
- 'cd02815260206004820152600a6024820152600160b21b691c994b595b9d195c99590260' +
- '4482015290519081900360640190fd5b60085481565b600a5481565b6012546001600160' +
- 'a01b031681565b6001600160a01b03166000908152600f602052604090205490565b6000' +
- '805460010180825581610d0f610e8a565b14610d645760408051600160e51b62461bcd02' +
- '815260206004820152601660248201527f61636372756520696e74657265737420666169' +
- '6c656400000000000000000000604482015290519081900360640190fd5b600c54915060' +
- '00548114610db25760408051600160e51b62461bcd02815260206004820152600a602482' +
- '0152600160b21b691c994b595b9d195c995902604482015290519081900360640190fd5b' +
- '5090565b600061088082612467565b600d5481565b600280546040805160206001841615' +
- '6101000260001901909316849004601f8101849004840282018401909252818152929183' +
- '01828280156108005780601f106107d55761010080835404028352916020019161080056' +
- '5b6000806000610e2d846124a4565b90925090506000826003811115610e4057fe5b1461' +
- '0a3557604051600160e51b62461bcd028152600401808060200182810382526037815260' +
- '2001806148366037913960400191505060405180910390fd5b600061088082612558565b' +
- '6000610e946146ce565b6007546001600160a01b03166315f24053610ead6121fa565b60' +
- '0c54600d546040518463ffffffff1660e01b815260040180848152602001838152602001' +
- '8281526020019350505050604080518083038186803b158015610ef457600080fd5b505a' +
- 'fa158015610f08573d6000803e3d6000fd5b505050506040513d6040811015610f1e5760' +
- '0080fd5b50805160209182015160408401819052918301526601c6bf526340001015610f' +
- '905760408051600160e51b62461bcd02815260206004820152601c60248201527f626f72' +
- '726f772072617465206973206162737572646c7920686967680000000060448201529051' +
- '9081900360640190fd5b602081015115610fb357610fab60056002836020015161259356' +
- '5b9150506109ba565b610fbb6125f9565b60608201819052600a54610fcf91906125fd56' +
- '5b6080830181905282826003811115610fe357fe5b6003811115610fee57fe5b90525060' +
- '0090508151600381111561100257fe5b1461100957fe5b61102960405180602001604052' +
- '8083604001518152508260800151612620565b60a083018190528282600381111561103d' +
- '57fe5b600381111561104857fe5b905250600090508151600381111561105c57fe5b1461' +
- '107d57610fab600960068360000151600381111561107857fe5b612593565b61108d8160' +
- 'a00151600c546121a6565b60c08301819052828260038111156110a157fe5b6003811115' +
- '6110ac57fe5b90525060009050815160038111156110c057fe5b146110dc57610fab6009' +
- '60018360000151600381111561107857fe5b6110ec8160c00151600c54612688565b60e0' +
- '83018190528282600381111561110057fe5b600381111561110b57fe5b90525060009050' +
- '8151600381111561111f57fe5b1461113b57610fab600960048360000151600381111561' +
- '107857fe5b61115c60405180602001604052806009548152508260c00151600d546126ae' +
- '565b61010083018190528282600381111561117157fe5b600381111561117c57fe5b9052' +
- '50600090508151600381111561119057fe5b146111ac57610fab60096005836000015160' +
- '0381111561107857fe5b6111bf8160a00151600b54600b546126ae565b61012083018190' +
- '52828260038111156111d457fe5b60038111156111df57fe5b9052506000905081516003' +
- '8111156111f357fe5b1461120f57610fab600960038360000151600381111561107857fe' +
- '5b606080820151600a55610120820151600b81905560e0830151600c8190556101008401' +
- '51600d5560c08401516040805191825260208201939093528083019190915290517f8753' +
- '52fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9929181900390' +
- '910190a1600091505090565b600080546001018082558161129d33338787611e02565b14' +
- '91505b60005481146112ea5760408051600160e51b62461bcd0281526020600482015260' +
- '0a6024820152600160b21b691c994b595b9d195c99590260448201529051908190036064' +
- '0190fd5b5092915050565b600b5481565b600080611302610957565b6007549091506000' +
- '9081906001600160a01b03166315f240536113236121fa565b600c54600d546040518463' +
- 'ffffffff1660e01b81526004018084815260200183815260200182815260200193505050' +
- '50604080518083038186803b15801561136a57600080fd5b505afa15801561137e573d60' +
- '00803e3d6000fd5b505050506040513d604081101561139457600080fd5b508051602090' +
- '910151909250905081156113e257604051600160e51b62461bcd02815260040180806020' +
- '01828103825260318152602001806148d56031913960400191505060405180910390fd5b' +
- '60006113ec6146bb565b611406604051806020016040528087815250600e54612620565b' +
- '9092509050600082600381111561141957fe5b1461145857604051600160e51b62461bcd' +
- '02815260040180806020018281038252603181526020018061486d603191396040019150' +
- '5060405180910390fd5b60006114626146bb565b61146e600c548461270a565b90925090' +
- '50600082600381111561148157fe5b146114c057604051600160e51b62461bcd02815260' +
- '04018080602001828103825260318152602001806147b160319139604001915050604051' +
- '80910390fd5b60006114ca6146bb565b6114fa6040518060200160405280670de0b6b3a7' +
- '6400008152506040518060200160405280600954815250612769565b9092509050600082' +
- '600381111561150d57fe5b1461154c57604051600160e51b62461bcd0281526004018080' +
- '6020018281038252603c815260200180614926603c913960400191505060405180910390' +
- 'fd5b60006115566146bb565b61156f60405180602001604052808b81525084876127a356' +
- '5b9092509050600082600381111561158257fe5b146115c157604051600160e51b62461b' +
- 'cd0281526004018080602001828103825260318152602001806148056031913960400191' +
- '505060405180910390fd5b519a505050505050505050505090565b600080546001018082' +
- '5560065460408051600160e01b63d02f7351028152306004820152336024820152600160' +
- '0160a01b0388811660448301528781166064830152608482018790529151859392909216' +
- '9163d02f73519160a48082019260209290919082900301818787803b15801561164a5760' +
- '0080fd5b505af115801561165e573d6000803e3d6000fd5b505050506040513d60208110' +
- '1561167457600080fd5b5051905080156116935761168b6003601b83612593565b925050' +
- '6109d8565b856001600160a01b0316856001600160a01b031614156116b95761168b6006' +
- '601c61227d565b6001600160a01b0385166000908152600f602052604081205481908190' +
- '6116e090886125fd565b909350915060008360038111156116f357fe5b14611716576117' +
- '0b6009601a85600381111561107857fe5b9550505050506109d8565b6001600160a01b03' +
- '89166000908152600f60205260409020546117399088612688565b909350905060008360' +
- '0381111561174c57fe5b146117645761170b6009601985600381111561107857fe5b6001' +
- '600160a01b038089166000818152600f60209081526040808320879055938d1680835291' +
- '84902085905583518b815293519193600080516020614906833981519152929081900390' +
- '910190a360065460408051600160e01b636d35bf91028152306004820152336024820152' +
- '6001600160a01b038c811660448301528b81166064830152608482018b90529151919092' +
- '1691636d35bf919160a480830192600092919082900301818387803b15801561181e5760' +
- '0080fd5b505af1158015611832573d6000803e3d6000fd5b506000925061183f91505056' +
- '5b9550505050506000548114610a215760408051600160e51b62461bcd02815260206004' +
- '820152600a6024820152600160b21b691c994b595b9d195c995902604482015290519081' +
- '900360640190fd5b6004546000906001600160a01b031633146118af57610aef60016045' +
- '61227d565b600580546001600160a01b038481166001600160a01b031983168117909355' +
- '6040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94' +
- '012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610a35565b60' +
- '00805460010180825581611928610e8a565b1461197d5760408051600160e51b62461bcd' +
- '02815260206004820152601660248201527f61636372756520696e746572657374206661' +
- '696c656400000000000000000000604482015290519081900360640190fd5b6119856109' +
- '57565b91506000548114610db25760408051600160e51b62461bcd028152602060048201' +
- '52600a6024820152600160b21b691c994b595b9d195c9959026044820152905190819003' +
- '60640190fd5b6001600160a01b0381166000908152600f60205260408120548190819081' +
- '908180806119fb896124a4565b935090506000816003811115611a0d57fe5b14611a2b57' +
- '60095b975060009650869550859450611a5e9350505050565b611a33611d54565b925090' +
- '506000816003811115611a4557fe5b14611a51576009611a15565b506000965091945092' +
- '5090505b9193509193565b6000610880826127ed565b600061088082612828565b600160' +
- '0160a01b0391821660009081526010602090815260408083209390941682529190915220' +
- '5490565b6005546000906001600160a01b031633141580611ac1575033155b15611ad957' +
- '611ad26001600061227d565b90506109ba565b60048054600580546001600160a01b0380' +
- '82166001600160a01b031980861682179687905590921690925560408051938316808552' +
- '949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f' +
- '21c4e8146d8519b417dc92908290030190a1600554604080516001600160a01b03808516' +
- '8252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b0' +
- '93e7720646a95b16a99281900390910190a160009250505090565b600080611ba0610e8a' +
- '565b90508015611bc657611bbe816010811115611bb757fe5b604061227d565b91505061' +
- '0883565b610a358361285e565b6007546001600160a01b031681565b6000610ab7848484' +
- '6129d1565b6004546001600160a01b031681565b600754600090819081906001600160a0' +
- '1b03166315f24053611c1a6121fa565b600c54600d546040518463ffffffff1660e01b81' +
- '526004018084815260200183815260200182815260200193505050506040805180830381' +
- '86803b158015611c6157600080fd5b505afa158015611c75573d6000803e3d6000fd5b50' +
- '5050506040513d6040811015611c8b57600080fd5b508051602090910151909250905081' +
- '156109b657604051600160e51b62461bcd02815260040180806020018281038252603781' +
- '526020018061489e6037913960400191505060405180910390fd5b600080546001018082' +
- '5581611cec610e8a565b90508015611d0a57610c69816010811115611d0357fe5b604661' +
- '227d565b610c7a84612adf565b600181565b6000805460010180825581611d2b610e8a56' +
- '5b90508015611d4957610c69816010811115611d4257fe5b603661227d565b610c7a3333' +
- '86612b82565b600080600e5460001415611d6f575050600854600090611dfe565b600061' +
- '1d796121fa565b90506000611d856146bb565b6000611d9684600c54600d54612fde565b' +
- '935090506000816003811115611da857fe5b14611dbc57945060009350611dfe92505050' +
- '565b611dc883600e5461301c565b925090506000816003811115611dda57fe5b14611dee' +
- '57945060009350611dfe92505050565b5051600094509250611dfe915050565b9091565b' +
- '60065460408051600160e31b6317b9b84b0281523060048201526001600160a01b038681' +
- '16602483015285811660448301526064820185905291516000938493169163bdcdc25891' +
- '608480830192602092919082900301818787803b158015611e6a57600080fd5b505af115' +
- '8015611e7e573d6000803e3d6000fd5b505050506040513d6020811015611e9457600080' +
- 'fd5b505190508015611eb357611eab6003604a83612593565b915050610ab7565b836001' +
- '600160a01b0316856001600160a01b03161415611ed957611eab6002604b61227d565b60' +
- '006001600160a01b038781169087161415611ef85750600019611f20565b506001600160' +
- 'a01b038086166000908152601060209081526040808320938a16835292905220545b6000' +
- '80600080611f3085896125fd565b90945092506000846003811115611f4357fe5b14611f' +
- '6157611f546009604b61227d565b9650505050505050610ab7565b6001600160a01b038a' +
- '166000908152600f6020526040902054611f8490896125fd565b90945091506000846003' +
- '811115611f9757fe5b14611fa857611f546009604c61227d565b6001600160a01b038916' +
- '6000908152600f6020526040902054611fcb9089612688565b9094509050600084600381' +
- '1115611fde57fe5b14611fef57611f546009604d61227d565b6001600160a01b03808b16' +
- '6000908152600f6020526040808220859055918b16815220819055600019851461204757' +
- '6001600160a01b03808b166000908152601060209081526040808320938f168352929052' +
- '208390555b886001600160a01b03168a6001600160a01b03166000805160206149068339' +
- '815191528a6040518082815260200191505060405180910390a360065460408051600160' +
- 'e11b63352b4a3f0281523060048201526001600160a01b038d811660248301528c811660' +
- '44830152606482018c905291519190921691636a56947e91608480830192600092919082' +
- '900301818387803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d' +
- '6000fd5b5060009250612107915050565b9b9a5050505050505050505050565b60008054' +
- '60010180825581612129610e8a565b9050801561214f5761214781601081111561214057' +
- 'fe5b603561227d565b9250506112a1565b61215a338686612b82565b9250506000548114' +
- '6112ea5760408051600160e51b62461bcd02815260206004820152600a60248201526001' +
- '60b21b691c994b595b9d195c995902604482015290519081900360640190fd5b60008060' +
- '006121b36146bb565b6121bd8686612620565b909250905060008260038111156121d057' +
- 'fe5b146121e157509150600090506121f3565b60006121ec826130cc565b935093505050' +
- '5b9250929050565b60125460408051600160e01b6370a082310281523060048201529051' +
- '6000926001600160a01b03169182916370a0823191602480820192602092909190829003' +
- '018186803b15801561224b57600080fd5b505afa15801561225f573d6000803e3d6000fd' +
- '5b505050506040513d602081101561227557600080fd5b505191505090565b60007f45b9' +
- '6fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836010811115' +
- '6122ac57fe5b83604d8111156122b857fe5b604080519283526020830191909152600082' +
- '820152519081900360600190a1826010811115610a3557fe5b6004546000908190819060' +
- '01600160a01b03163314612311576123086001603161227d565b92505050610883565b61' +
- '23196125f9565b600a541461232d57612308600a603361227d565b836123366121fa565b' +
- '101561234857612308600e603261227d565b600d5484111561235e576123086002603461' +
- '227d565b50600d54838103908111156123a757604051600160e51b62461bcd0281526004' +
- '018080602001828103825260248152602001806149cb6024913960400191505060405180' +
- '910390fd5b600d8190556004546123c2906001600160a01b0316856130db565b91506000' +
- '8260108111156123d257fe5b1461241157604051600160e51b62461bcd02815260040180' +
- '80602001828103825260238152602001806147e260239139604001915050604051809103' +
- '90fd5b600454604080516001600160a01b03909216825260208201869052818101839052' +
- '517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e9181' +
- '900360600190a16000949350505050565b600080546001018082558161247a610e8a565b' +
- '9050801561249857610c6981601081111561249157fe5b602761227d565b610c7a336000' +
- '8661319a565b6001600160a01b0381166000908152601160205260408120805482918291' +
- '829182916124db57506000945084935061255392505050565b6124eb8160000154600b54' +
- '6136af565b909450925060008460038111156124fe57fe5b146125135750919350600092' +
- '50612553915050565b6125218382600101546136ee565b90945091506000846003811115' +
- '61253457fe5b14612549575091935060009250612553915050565b506000945092505050' +
- '5b915091565b600080546001018082558161256b610e8a565b9050801561258957610c69' +
- '81601081111561258257fe5b601e61227d565b610c7a3385613719565b60007f45b96fe4' +
- '42630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156125' +
- 'c257fe5b84604d8111156125ce57fe5b6040805192835260208301919091528181018590' +
- '52519081900360600190a1836010811115610ab757fe5b4390565b600080838311612614' +
- '5750600090508183036121f3565b506003905060006121f3565b600061262a6146bb565b' +
- '60008061263b8660000151866136af565b9092509050600082600381111561264e57fe5b' +
- '1461266d575060408051602081019091526000815290925090506121f3565b6040805160' +
- '2081019091529081526000969095509350505050565b6000808383018481106126a05760' +
- '00925090506121f3565b5060029150600090506121f3565b60008060006126bb6146bb56' +
- '5b6126c58787612620565b909250905060008260038111156126d857fe5b146126e95750' +
- '915060009050612702565b6126fb6126f5826130cc565b86612688565b9350935050505b' +
- '935093915050565b60006127146146bb565b600080612729670de0b6b3a7640000876136' +
- 'af565b9092509050600082600381111561273c57fe5b1461275b57506040805160208101' +
- '9091526000815290925090506121f3565b6121ec81866000015161301c565b6000612773' +
- '6146bb565b600080612788866000015186600001516125fd565b60408051602081019091' +
- '529081529097909650945050505050565b60006127ad6146bb565b60006127b76146bb56' +
- '5b6127c18787613b67565b909250905060008260038111156127d457fe5b146127e35790' +
- '92509050612702565b6126fb8186613b67565b6000805460010180825581612800610e8a' +
- '565b9050801561281e57610c6981601081111561281757fe5b600861227d565b610c7a33' +
- '85613c50565b600080546001018082558161283b610e8a565b9050801561285257610c69' +
- '81601081111561249157fe5b610c7a3385600061319a565b600454600090819060016001' +
- '60a01b0316331461288157611bbe6001604261227d565b6128896125f9565b600a541461' +
- '289d57611bbe600a604161227d565b600760009054906101000a90046001600160a01b03' +
- '169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401' +
- '60206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d60' +
- '00803e3d6000fd5b505050506040513d602081101561291857600080fd5b505161296e57' +
- '60408051600160e51b62461bcd02815260206004820152601c60248201527f6d61726b65' +
- '72206d6574686f642072657475726e65642066616c736500000000604482015290519081' +
- '900360640190fd5b600780546001600160a01b0319166001600160a01b03858116918217' +
- '909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c' +
- '4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610a35565b60' +
- '008054600101808255816129e4610e8a565b90508015612a025761168b81601081111561' +
- '29fb57fe5b600f61227d565b836001600160a01b031663a6afed956040518163ffffffff' +
- '1660e01b8152600401602060405180830381600087803b158015612a3d57600080fd5b50' +
- '5af1158015612a51573d6000803e3d6000fd5b505050506040513d6020811015612a6757' +
- '600080fd5b505190508015612a875761168b816010811115612a8057fe5b601061227d56' +
- '5b612a9333878787613fbf565b9250506000548114610a215760408051600160e51b6246' +
- '1bcd02815260206004820152600a6024820152600160b21b691c994b595b9d195c995902' +
- '604482015290519081900360640190fd5b6004546000906001600160a01b03163314612b' +
- '0057610aef6001604761227d565b612b086125f9565b600a5414612b1c57610aef600a60' +
- '4861227d565b670de0b6b3a7640000821115612b3857610aef6002604961227d565b6009' +
- '805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af50684' +
- '10ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610a35565b' +
- '60065460408051600160e11b63120045310281523060048201526001600160a01b038681' +
- '1660248301528581166044830152606482018590529151600093849316916324008a6291' +
- '608480830192602092919082900301818787803b158015612bea57600080fd5b505af115' +
- '8015612bfe573d6000803e3d6000fd5b505050506040513d6020811015612c1457600080' +
- 'fd5b505190508015612c3357612c2b6003603883612593565b915050610a35565b612c3b' +
- '6125f9565b600a5414612c4f57612c2b600a603961227d565b612c57614728565b600160' +
- '0160a01b0385166000908152601160205260409020600101546060820152612c81856124' +
- 'a4565b6080830181905260208301826003811115612c9857fe5b6003811115612ca357fe' +
- '5b9052506000905081602001516003811115612cba57fe5b14612cdf57612cd660096037' +
- '8360200151600381111561107857fe5b92505050610a35565b600019841415612cf85760' +
- '808101516040820152612d00565b604081018490525b612d0e8682604001516144b3565b' +
- '81906010811115612d1b57fe5b90816010811115612d2857fe5b90525060008151601081' +
- '1115612d3a57fe5b14612d4c578051612cd690603c61227d565b612d5e81608001518260' +
- '4001516125fd565b60a0830181905260208301826003811115612d7557fe5b6003811115' +
- '612d8057fe5b9052506000905081602001516003811115612d9757fe5b14612db357612c' +
- 'd66009603a8360200151600381111561107857fe5b612dc3600c5482604001516125fd56' +
- '5b60c0830181905260208301826003811115612dda57fe5b6003811115612de557fe5b90' +
- '52506000905081602001516003811115612dfc57fe5b14612e1857612cd66009603b8360' +
- '200151600381111561107857fe5b612e268682604001516145ea565b8190601081111561' +
- '2e3357fe5b90816010811115612e4057fe5b905250600081516010811115612e5257fe5b' +
- '14612ea75760408051600160e51b62461bcd02815260206004820152601f60248201527f' +
- '726570617920626f72726f77207472616e7366657220696e206661696c65640060448201' +
- '5290519081900360640190fd5b60a080820180516001600160a01b038089166000818152' +
- '60116020908152604091829020948555600b5460019095019490945560c0870151600c81' +
- '90558188015195518251948e168552948401929092528281019490945260608201929092' +
- '52608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0' +
- '355478d6f5c362a1929181900390910190a1600654604080830151606084015182516001' +
- '60e01b631ededc910281523060048201526001600160a01b038b811660248301528a8116' +
- '6044830152606482019390935260848101919091529151921691631ededc919160a48082' +
- '019260009290919082900301818387803b158015612fb357600080fd5b505af115801561' +
- '2fc7573d6000803e3d6000fd5b5060009250612fd4915050565b9695505050505050565b' +
- '600080600080612fee8787612688565b9092509050600082600381111561300157fe5b14' +
- '6130125750915060009050612702565b6126fb81866125fd565b60006130266146bb565b' +
- '60008061303b86670de0b6b3a76400006136af565b909250905060008260038111156130' +
- '4e57fe5b1461306d575060408051602081019091526000815290925090506121f3565b60' +
- '008061307a83886136ee565b9092509050600082600381111561308d57fe5b146130af57' +
- '5060408051602081019091526000815290945092506121f3915050565b60408051602081' +
- '0190915290815260009890975095505050505050565b51670de0b6b3a764000090049056' +
- '5b60125460408051600160e01b63a9059cbb0281526001600160a01b0385811660048301' +
- '5260248201859052915160009392909216918391839163a9059cbb916044808201928692' +
- '90919082900301818387803b15801561313a57600080fd5b505af115801561314e573d60' +
- '00803e3d6000fd5b505050503d60008114613168576020811461317257600080fd5b6000' +
- '19915061317e565b60206000803e60005191505b508061318f5760109250505061086f56' +
- '5b506000949350505050565b60008215806131a7575081155b6131e557604051600160e5' +
- '1b62461bcd02815260040180806020018281038252603481526020018061499760349139' +
- '60400191505060405180910390fd5b6131ed614728565b6131f5611d54565b6040830181' +
- '90526020830182600381111561320c57fe5b600381111561321757fe5b90525060009050' +
- '8160200151600381111561322e57fe5b1461324a57612c2b6009602b8360200151600381' +
- '111561107857fe5b83156132cb5760608101849052604080516020810182529082015181' +
- '5261327190856121a6565b608083018190526020830182600381111561328857fe5b6003' +
- '81111561329357fe5b90525060009050816020015160038111156132aa57fe5b146132c6' +
- '57612c2b600960298360200151600381111561107857fe5b613344565b6132e783604051' +
- '806020016040528084604001518152506146a4565b606083018190526020830182600381' +
- '11156132fe57fe5b600381111561330957fe5b9052506000905081602001516003811115' +
- '61332057fe5b1461333c57612c2b6009602a8360200151600381111561107857fe5b6080' +
- '81018390525b600654606082015160408051600160e01b63eabe7d910281523060048201' +
- '526001600160a01b03898116602483015260448201939093529051600093929092169163' +
- 'eabe7d919160648082019260209290919082900301818787803b1580156133ac57600080' +
- 'fd5b505af11580156133c0573d6000803e3d6000fd5b505050506040513d602081101561' +
- '33d657600080fd5b5051905080156133ed57612cd66003602883612593565b6133f56125' +
- 'f9565b600a541461340957612cd6600a602c61227d565b613419600e5483606001516125' +
- 'fd565b60a084018190526020840182600381111561343057fe5b600381111561343b57fe' +
- '5b905250600090508260200151600381111561345257fe5b1461346e57612cd66009602e' +
- '8460200151600381111561107857fe5b6001600160a01b0386166000908152600f602052' +
- '6040902054606083015161349691906125fd565b60c08401819052602084018260038111' +
- '156134ad57fe5b60038111156134b857fe5b905250600090508260200151600381111561' +
- '34cf57fe5b146134eb57612cd66009602d8460200151600381111561107857fe5b816080' +
- '01516134f86121fa565b101561350a57612cd6600e602f61227d565b6135188683608001' +
- '516130db565b8290601081111561352557fe5b9081601081111561353257fe5b90525060' +
- '008251601081111561354457fe5b146135995760408051600160e51b62461bcd02815260' +
- '206004820152601a60248201527f72656465656d207472616e73666572206f7574206661' +
- '696c6564000000000000604482015290519081900360640190fd5b60a0820151600e5560' +
- 'c08201516001600160a01b0387166000818152600f602090815260409182902093909355' +
- '6060850151815190815290513093600080516020614906833981519152928290030190a3' +
- '6080820151606080840151604080516001600160a01b038b168152602081019490945283' +
- '810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4' +
- 'ec31a9299281900390910190a16006546080830151606084015160408051600160e01b63' +
- '51dff9890281523060048201526001600160a01b038b8116602483015260448201949094' +
- '5260648101929092525191909216916351dff98991608480830192600092919082900301' +
- '818387803b158015612fb357600080fd5b600080836136c2575060009050806121f3565b' +
- '838302838582816136cf57fe5b04146136e3575060029150600090506121f3565b600092' +
- '5090506121f3565b6000808261370257506001905060006121f3565b600083858161370d' +
- '57fe5b04915091509250929050565b60065460408051600160e01b634ef4c3e102815230' +
- '60048201526001600160a01b038581166024830152604482018590529151600093849316' +
- '91634ef4c3e191606480830192602092919082900301818787803b158015613779576000' +
- '80fd5b505af115801561378d573d6000803e3d6000fd5b505050506040513d6020811015' +
- '6137a357600080fd5b5051905080156137c2576137ba6003601f83612593565b91505061' +
- '086f565b6137ca6125f9565b600a54146137de576137ba600a602261227d565b6137e661' +
- '4766565b6137f085856144b3565b819060108111156137fd57fe5b908160108111156138' +
- '0a57fe5b90525060008151601081111561381c57fe5b1461383757805161382e90602661' +
- '227d565b9250505061086f565b61383f611d54565b604083018190526020830182600381' +
- '111561385657fe5b600381111561386157fe5b9052506000905081602001516003811115' +
- '61387857fe5b146138945761382e600960218360200151600381111561107857fe5b6138' +
- 'b084604051806020016040528084604001518152506146a4565b60608301819052602083' +
- '018260038111156138c757fe5b60038111156138d257fe5b905250600090508160200151' +
- '60038111156138e957fe5b146139055761382e6009602083602001516003811115611078' +
- '57fe5b613915600e548260600151612688565b6080830181905260208301826003811115' +
- '61392c57fe5b600381111561393757fe5b90525060009050816020015160038111156139' +
- '4e57fe5b1461396a5761382e600960248360200151600381111561107857fe5b60016001' +
- '60a01b0385166000908152600f602052604090205460608201516139929190612688565b' +
- '60a08301819052602083018260038111156139a957fe5b60038111156139b457fe5b9052' +
- '5060009050816020015160038111156139cb57fe5b146139e75761382e60096023836020' +
- '0151600381111561107857fe5b6139f185856145ea565b819060108111156139fe57fe5b' +
- '90816010811115613a0b57fe5b905250600081516010811115613a1d57fe5b14613a2f57' +
- '805161382e90602561227d565b6080810151600e5560a08101516001600160a01b038616' +
- '6000818152600f6020908152604091829020939093556060808501518251938452938301' +
- '88905282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef' +
- '26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160' +
- 'a01b0387169130916000805160206149068339815191529181900360200190a360065460' +
- '6082015160408051600160e01b6341c728b90281523060048201526001600160a01b0389' +
- '81166024830152604482018990526064820193909352905191909216916341c728b99160' +
- '8480830192600092919082900301818387803b158015613b3d57600080fd5b505af11580' +
- '15613b51573d6000803e3d6000fd5b5060009250613b5e915050565b9594505050505056' +
- '5b6000613b716146bb565b600080613b86866000015186600001516136af565b90925090' +
- '506000826003811115613b9957fe5b14613bb85750604080516020810190915260008152' +
- '90925090506121f3565b600080613bcd6706f05b59d3b2000084612688565b9092509050' +
- '6000826003811115613be057fe5b14613c02575060408051602081019091526000815290' +
- '945092506121f3915050565b600080613c1783670de0b6b3a76400006136ee565b909250' +
- '90506000826003811115613c2a57fe5b14613c3157fe5b60408051602081019091529081' +
- '5260009a909950975050505050505050565b60065460408051600160e21b63368f515302' +
- '81523060048201526001600160a01b038581166024830152604482018590529151600093' +
- '8493169163da3d454c91606480830192602092919082900301818787803b158015613cb0' +
- '57600080fd5b505af1158015613cc4573d6000803e3d6000fd5b505050506040513d6020' +
- '811015613cda57600080fd5b505190508015613cf1576137ba6003600e83612593565b61' +
- '3cf96125f9565b600a5414613d0c576137ba600a8061227d565b82613d156121fa565b10' +
- '15613d27576137ba600e600961227d565b613d2f614780565b613d38856124a4565b6040' +
- '830181905260208301826003811115613d4f57fe5b6003811115613d5a57fe5b90525060' +
- '00905081602001516003811115613d7157fe5b14613d8d5761382e600960078360200151' +
- '600381111561107857fe5b613d9b816040015185612688565b6060830181905260208301' +
- '826003811115613db257fe5b6003811115613dbd57fe5b90525060009050816020015160' +
- '03811115613dd457fe5b14613df05761382e6009600c8360200151600381111561107857' +
- 'fe5b613dfc600c5485612688565b6080830181905260208301826003811115613e1357fe' +
- '5b6003811115613e1e57fe5b9052506000905081602001516003811115613e3557fe5b14' +
- '613e515761382e6009600b8360200151600381111561107857fe5b613e5b85856130db56' +
- '5b81906010811115613e6857fe5b90816010811115613e7557fe5b905250600081516010' +
- '811115613e8757fe5b14613edc5760408051600160e51b62461bcd028152602060048201' +
- '52601a60248201527f626f72726f77207472616e73666572206f7574206661696c656400' +
- '0000000000604482015290519081900360640190fd5b606080820180516001600160a01b' +
- '038816600081815260116020908152604091829020938455600b54600190940193909355' +
- '608080870151600c819055945182519384529383018a9052828201939093529381019290' +
- '925291517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab' +
- '80929181900390910190a160065460408051600160e01b635c7786050281523060048201' +
- '526001600160a01b0388811660248301526044820188905291519190921691635c778605' +
- '91606480830192600092919082900301818387803b158015613b3d57600080fd5b600654' +
- '60408051600160e11b632fe3f38f0281523060048201526001600160a01b038481166024' +
- '830152878116604483015286811660648301526084820186905291516000938493169163' +
- '5fc7e71e9160a480830192602092919082900301818787803b15801561402f57600080fd' +
- '5b505af1158015614043573d6000803e3d6000fd5b505050506040513d60208110156140' +
- '5957600080fd5b50519050801561407057611eab6003601283612593565b6140786125f9' +
- '565b600a541461408c57611eab600a601661227d565b6140946125f9565b836001600160' +
- 'a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381' +
- '86803b1580156140cd57600080fd5b505afa1580156140e1573d6000803e3d6000fd5b50' +
- '5050506040513d60208110156140f757600080fd5b50511461410a57611eab600a601161' +
- '227d565b856001600160a01b0316856001600160a01b0316141561413057611eab600660' +
- '1761227d565b8361414157611eab6007601561227d565b60001984141561415757611eab' +
- '6007601461227d565b60065460408051600160e01b63c488847b02815230600482015260' +
- '01600160a01b038681166024830152604482018890528251600094859492169263c48884' +
- '7b926064808301939192829003018186803b1580156141b457600080fd5b505afa158015' +
- '6141c8573d6000803e3d6000fd5b505050506040513d60408110156141de57600080fd5b' +
- '50805160209091015190925090508115614209576141ff6004601384612593565b935050' +
- '5050610ab7565b846001600160a01b03166370a08231886040518263ffffffff1660e01b' +
- '815260040180826001600160a01b03166001600160a01b03168152602001915050602060' +
- '40518083038186803b15801561425f57600080fd5b505afa158015614273573d6000803e' +
- '3d6000fd5b505050506040513d602081101561428957600080fd5b505181111561429e57' +
- '6141ff600d601d61227d565b60006142ab898989612b82565b905080156142d4576142c9' +
- '8160108111156142c257fe5b601861227d565b945050505050610ab7565b604080516001' +
- '60e01b63b2a02ff10281526001600160a01b038b811660048301528a8116602483015260' +
- '448201859052915160009289169163b2a02ff19160648083019260209291908290030181' +
- '8787803b15801561433257600080fd5b505af1158015614346573d6000803e3d6000fd5b' +
- '505050506040513d602081101561435c57600080fd5b5051905080156143b65760408051' +
- '600160e51b62461bcd02815260206004820152601460248201527f746f6b656e20736569' +
- '7a757265206661696c656400000000000000000000000060448201529051908190036064' +
- '0190fd5b604080516001600160a01b03808d168252808c1660208301528183018b905289' +
- '1660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a33' +
- '5ab1e7d6215a4b2484d8bb529181900360a00190a160065460408051600160e01b6347ef' +
- '3b3b0281523060048201526001600160a01b038a811660248301528d811660448301528c' +
- '81166064830152608482018c905260a48201879052915191909216916347ef3b3b9160c4' +
- '80830192600092919082900301818387803b15801561448457600080fd5b505af1158015' +
- '614498573d6000803e3d6000fd5b50600092506144a5915050565b9a9950505050505050' +
- '505050565b60125460408051600160e11b636eb1769f0281526001600160a01b03858116' +
- '6004830152306024830152915160009392909216918491839163dd62ed3e916044808201' +
- '92602092909190829003018186803b15801561451157600080fd5b505afa158015614525' +
- '573d6000803e3d6000fd5b505050506040513d602081101561453b57600080fd5b505110' +
- '1561454d57600c91505061086f565b82816001600160a01b03166370a082318660405182' +
- '63ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152' +
- '60200191505060206040518083038186803b1580156145a457600080fd5b505afa158015' +
- '6145b8573d6000803e3d6000fd5b505050506040513d60208110156145ce57600080fd5b' +
- '505110156145e057600d91505061086f565b5060009392505050565b6012546040805160' +
- '0160e01b6323b872dd0281526001600160a01b0385811660048301523060248301526044' +
- '820185905291516000939290921691839183916323b872dd916064808201928692909190' +
- '82900301818387803b15801561464f57600080fd5b505af1158015614663573d6000803e' +
- '3d6000fd5b505050503d6000811461467d576020811461468757600080fd5b6000199150' +
- '614693565b60206000803e60005191505b508061318f57600f9250505061086f565b6000' +
- '8060006146b16146bb565b6121bd868661270a565b604051806020016040528060008152' +
- '5090565b6040805161014081019091528060008152602001600081526020016000815260' +
- '200160008152602001600081526020016147066146bb565b815260200160008152602001' +
- '6000815260200160008152602001600081525090565b6040805160e08101909152806000' +
- '815260200160008152602001600081526020016000815260200160008152602001600081' +
- '52602001600081525090565b6040805160c0810190915280600081526020016000614706' +
- '565b6040805160a081019091528060008152602001600081526020016000815260200160' +
- '00815260200160008152509056fe737570706c7952617465506572426c6f636b3a206361' +
- '6c63756c6174696e6720626f72726f7773506572206661696c6564726564756365207265' +
- '736572766573207472616e73666572206f7574206661696c6564737570706c7952617465' +
- '506572426c6f636b3a2063616c63756c6174696e6720737570706c795261746520666169' +
- '6c6564626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e63' +
- '6553746f726564496e7465726e616c206661696c6564737570706c795261746550657242' +
- '6c6f636b3a2063616c63756c6174696e6720756e6465726c79696e67206661696c656462' +
- '6f72726f7752617465506572426c6f636b3a20696e746572657374526174654d6f64656c' +
- '2e626f72726f7752617465206661696c6564737570706c7952617465506572426c6f636b' +
- '3a2063616c63756c6174696e6720626f72726f7752617465206661696c6564ddf252ad1b' +
- 'e2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef737570706c79526174' +
- '65506572426c6f636b3a2063616c63756c6174696e67206f6e654d696e75735265736572' +
- '7665466163746f72206661696c656465786368616e67655261746553746f7265643a2065' +
- '786368616e67655261746553746f726564496e7465726e616c206661696c65646f6e6520' +
- '6f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e20' +
- '6d757374206265207a65726f72656475636520726573657276657320756e657870656374' +
- '656420756e646572666c6f77a165627a7a72305820ae92d0e3e70b657d01891c7457bc6c' +
- '8a5ce2401a1a8857f346a2fa9af4627145002953657474696e6720696e74657265737420' +
- '72617465206d6f64656c206661696c6564496e697469616c2065786368616e6765207261' +
- '7465206d7573742062652067726561746572207468616e207a65726f2e' +
- '000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' + // usdc
- '0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b' + // troll
- '000000000000000000000000c64c4cba055efa614ce01f4bad8a9f519c4f8fab' + // IRM
- '0000000000000000000000000000000000000000000000000000b5e620f48000' +
- '00000000000000000000000000000000000000000000000000000000000000e0' +
- '0000000000000000000000000000000000000000000000000000000000000120' +
- '0000000000000000000000000000000000000000000000000000000000000008' +
- '0000000000000000000000000000000000000000000000000000000000000011' +
- '436f6d706f756e642055534420436f696e000000000000000000000000000000' +
- '0000000000000000000000000000000000000000000000000000000000000005' +
- '6355534443000000000000000000000000000000000000000000000000000000'
- )
-
- // ************************** helper functions **************************** //
- async function send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- const receipt = await instance.methods[method](...args).send({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
- }
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
+ console.log("deploying current Compound comptroller...");
+ comptrollerDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "5000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCurrentComptrollerDeploymentData
+ });
- return assertionsPassed
- }
-
- async function call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let succeeded = true
- returnValues = await instance.methods[method](...args).call({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- succeeded = false
- })
-
- if (succeeded !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
- }
+ assert.strictEqual(
+ comptrollerDeploymentReceipt.contractAddress,
+ "0x178053c06006e67e09879C09Ff012fF9d263dF29"
+ );
- let assertionsPassed
- try {
- assertionCallback(returnValues)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
+ COMPTROLLER = new web3.eth.Contract(
+ COMPTROLLER_ABI,
+ comptrollerDeploymentReceipt.contractAddress
+ );
- return assertionsPassed
- }
-
- async function deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let deployData = instance.deploy({arguments: args}).encodeABI()
- let deployGas = await web3.eth.estimateGas({
- from: from,
- data: deployData
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return gasLimit
- })
-
- if (deployGas > gasLimit) {
- console.error(` ✘ ${title}: deployment costs exceed block gas limit!`)
- process.exit(1)
- }
+ await runTest(
+ "Set pending Comptroller on Unitroller",
+ UNITROLLER,
+ "_setPendingImplementation",
+ "send",
+ [comptrollerDeploymentReceipt.contractAddress],
+ true,
+ receipt => {},
+ "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6"
+ );
- if (typeof(gas) === 'undefined') {
- gas = deployGas
- }
+ await runTest(
+ "Set Comptroller on Unitroller",
+ COMPTROLLER,
+ "_become",
+ "send",
+ [
+ UNITROLLER.options.address,
+ priceOracleDeployReceipt.contractAddress,
+ "500000000000000000",
+ 20,
+ true
+ ],
+ true,
+ receipt => {},
+ "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6"
+ );
- if (deployGas > gas) {
- console.error(` ✘ ${title}: deployment costs exceed supplied gas.`)
- process.exit(1)
- }
+ await runTest(
+ "comptroller implementation is set correctly",
+ UNITROLLER,
+ "comptrollerImplementation",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, COMPTROLLER.options.address);
+ }
+ );
- let signed
- let deployHash
- let receipt
- const contract = await instance.deploy({arguments: args}).send({
- from: from,
- gas: gas,
- gasPrice: gasPrice
- }).on('transactionHash', hash => {
- deployHash = hash
- }).on('receipt', r => {
- receipt = r
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
-
- receipt = {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- if (contract) {
- return [false, contract, gas]
- }
- return [false, instance, gas]
- } else if (!shouldSucceed) {
- if (contract) {
- return [true, contract, gas]
- }
- return [true, instance, gas]
- }
+ await runTest(
+ "Set pending admin on Unitroller",
+ UNITROLLER,
+ "_setPendingAdmin",
+ "send",
+ [address],
+ true,
+ receipt => {},
+ "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6"
+ );
- assert.ok(receipt.status)
+ await runTest(
+ "Set new admin on Unitroller",
+ UNITROLLER,
+ "_acceptAdmin"
+ );
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- }
+ await runTest(
+ "comptroller admin is set correctly",
+ UNITROLLER,
+ "admin",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, address);
+ }
+ );
- if (contract) {
- return [assertionsPassed, contract, gas]
- }
- return [assertionsPassed, instance, gas]
- }
-
- async function runTest(
- title,
- instance,
- method,
- callOrSend,
- args,
- shouldSucceed,
- assertionCallback,
- from,
- value,
- gas
- ) {
- if (typeof(callOrSend) === 'undefined') {
- callOrSend = 'send'
- }
- if (typeof(args) === 'undefined') {
- args = []
- }
- if (typeof(shouldSucceed) === 'undefined') {
- shouldSucceed = true
- }
- if (typeof(assertionCallback) === 'undefined') {
- assertionCallback = (value) => {}
- }
- if (typeof(from) === 'undefined') {
- from = address
- }
- if (typeof(value) === 'undefined') {
- value = 0
- }
- if (typeof(gas) === 'undefined' && callOrSend !== 'deploy') {
- gas = 6009006
- if (testingContext === 'coverage') {
- gas = gasLimit - 1
- }
- }
- let ok = false
- let contract
- let deployGas
- if (callOrSend === 'send') {
- ok = await send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'call') {
- ok = await call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'deploy') {
- const fields = await deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- ok = fields[0]
- contract = fields[1]
- deployGas = fields[2]
- } else {
- console.error('must use call, send, or deploy!')
- process.exit(1)
- }
+ 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"
+ });
+ }
- if (ok) {
- console.log(
- ` ✓ ${
- callOrSend === 'deploy' ? 'successful ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- passed++
- } else {
- console.log(
- ` ✘ ${
- callOrSend === 'deploy' ? 'failed ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- failed++
- }
+ console.log("deploying Compound cDai...");
+ const daiDeploymentReceipt = await web3.eth.sendTransaction({
+ from: "0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6",
+ gas: testingContext !== "coverage" ? "7000000" : gasLimit - 1,
+ gasPrice: 1,
+ data: mockCDaiDeploymentData.replace(
+ "89d24a6b4ccb1b6faa2625fe562bdd9a23260359",
+ constants.DAI_MAINNET_ADDRESS.slice(2)
+ )
+ });
- if (contract) {
- return contract
- }
- }
+ assert.strictEqual(
+ daiDeploymentReceipt.contractAddress,
+ constants.CDAI_MAINNET_ADDRESS
+ );
- async function setupNewDefaultAddress(newPrivateKey) {
- const pubKey = await web3.eth.accounts.privateKeyToAccount(newPrivateKey)
- await web3.eth.accounts.wallet.add(pubKey)
+ await runTest(
+ "List cSai on Comptroller",
+ UNITROLLER_COMPTROLLER,
+ "_supportMarket",
+ "send",
+ [CSAI.options.address]
+ );
- const txCount = await web3.eth.getTransactionCount(pubKey.address)
+ await runTest(
+ "List cUSDC on Comptroller",
+ UNITROLLER_COMPTROLLER,
+ "_supportMarket",
+ "send",
+ [CUSDC.options.address]
+ );
- if (txCount > 0) {
- console.warn(
- `warning: ${pubKey.address} has already been used, which may cause ` +
- 'some tests to fail or to be skipped.'
- )
- }
+ await runTest(
+ "List cDai on Comptroller",
+ UNITROLLER_COMPTROLLER,
+ "_supportMarket",
+ "send",
+ [CDAI.options.address]
+ );
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: pubKey.address,
- value: 10 ** 18,
- gas: '0x5208',
- gasPrice: '0x4A817C800'
- })
-
- return pubKey.address
- }
-
- // *************************** deploy contracts *************************** //
- const currentSaiCode = await web3.eth.getCode(constants.SAI_MAINNET_ADDRESS)
- if (currentSaiCode !== '0x') {
- console.log('contracts already set up, skipping...')
- return 0
- }
-
- console.log('funding mcd deployer address...')
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: '0xb5b06a16621616875A6C2637948bF98eA57c58fa',
- value: web3.utils.toWei('0.1', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
-
- 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
- })
-
- console.log('funding dai deployer address...')
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9',
- value: web3.utils.toWei('10', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
-
- console.log('funding usdc deployer address...')
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: '0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911',
- value: web3.utils.toWei('10', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
-
- console.log('funding Compound deployer address...')
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- value: web3.utils.toWei('10', '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
- })
-
- assert.strictEqual(
- priceOracleDeployReceipt.contractAddress,
- '0x43Af172dFC1017c775D789f5B6cDD375E3D8Fe14'
- )
-
- console.log('incrementing dai deployment nonce...')
- let daiDeployReceipt
- for (i = 0; i < 1; i++) {
- daiDeployReceipt = await web3.eth.sendTransaction({
- from: '0xb5b06a16621616875A6C2637948bF98eA57c58fa',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- 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, constants.DAI_MAINNET_ADDRESS
- )
-
- 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,
- data: mockDaiDeploymentData
- })
-
- assert.strictEqual(
- 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,
- 'transfer',
- 'send',
- [
- constants.DAI_WHALE_ADDRESS,
- '8555083659983933209597798445644913612440610624038028786991485007418559037440'
- ],
- true,
- receipt => {},
- '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,
- 'transfer',
- 'send',
- [
- constants.SAI_WHALE_ADDRESS,
- '8555083659983933209597798445644913612440610624038028786991485007418559037440'
- ],
- true,
- receipt => {},
- '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9'
- )
-
- await runTest(
- 'Transfer Dai to primary address',
- SAI,
- 'transfer',
- 'send',
- [
- address,
- '1000000000000000000000000000000000000000000000000000000000000000000000000000'
- ],
- true,
- receipt => {},
- '0x552F355CCb9b91C8FB47D9c011AbAD5B72EC30e9'
- )
-
- await runTest(
- 'Dai totalSupply is reachable',
- SAI,
- 'totalSupply',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(
- value,
- '108555083659983933209597798445644913612440610624038028786991485007418559037440'
- )
- }
- )
-
- console.log('incrementing usdc deployment nonce...')
- let usdcDeployReceipt
- for (i = 0; i < 20; i++) {
- usdcDeployReceipt = await web3.eth.sendTransaction({
- from: '0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- console.log('deploying mock USDC...')
- usdcDeployReceipt = await web3.eth.sendTransaction({
- from: '0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911',
- gas: (testingContext !== 'coverage') ? '4000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockUSDCDeploymentData
- })
-
- assert.strictEqual(
- usdcDeployReceipt.contractAddress, constants.USDC_MAINNET_ADDRESS
- )
-
- await runTest(
- 'initialize USDC',
- FIAT_TOKEN,
- 'initialize',
- 'send',
- [
- 'USD//C',
- 'USDC',
- 'USD',
- 6,
- address,
- address,
- address,
- address
- ]
- )
-
- await runTest(
- 'add USDC minter',
- FIAT_TOKEN,
- 'configureMinter',
- 'send',
- [
- address,
- '0xf000000000000000000000000000000000000000000000000000000000000000'
- ]
- )
-
- await runTest(
- 'Mint USDC to whale address',
- FIAT_TOKEN,
- 'mint',
- 'send',
- [
- constants.USDC_WHALE_ADDRESS,
- '8555083659983933209597798445644913612440610624038028786991485007418559037440'
- ]
- )
-
- await runTest(
- 'Mint USDC to primary address',
- FIAT_TOKEN,
- 'mint',
- 'send',
- [
- address,
- '100000000000000000000000000000000000000000000000000000000000000000000000000000'
- ]
- )
-
- await runTest(
- 'USDC totalSupply is reachable',
- USDC,
- 'totalSupply',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(
- value,
- '108555083659983933209597798445644913612440610624038028786991485007418559037440'
- )
- }
- )
-
- await runTest(
- 'blacklist a USDC address',
- FIAT_TOKEN,
- 'blacklist',
- 'send',
- [constants.MOCK_USDC_BLACKLISTED_ADDRESS]
- )
-
- console.log('deploying Compound unitroller...')
- const unitrollerDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockUnitrollerDeploymentData
- })
-
- assert.strictEqual(
- unitrollerDeploymentReceipt.contractAddress,
- constants.COMPTROLLER_MAINNET_ADDRESS
- )
-
- console.log('deploying v0 Compound comptroller...')
- let comptrollerDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '5000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCurrentComptrollerDeploymentData
- })
-
- let COMPTROLLER = new web3.eth.Contract(
- COMPTROLLER_ABI,
- comptrollerDeploymentReceipt.contractAddress
- )
-
- const UNITROLLER_COMPTROLLER = new web3.eth.Contract(
- COMPTROLLER_ABI,
- UNITROLLER.options.address
- )
-
- await runTest(
- 'Set pending Comptroller on Unitroller',
- UNITROLLER,
- '_setPendingImplementation',
- 'send',
- [
- COMPTROLLER.options.address
- ],
- true,
- receipt => {},
- '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6'
- )
-
- await runTest(
- 'Set Comptroller on Unitroller',
- COMPTROLLER,
- '_become',
- 'send',
- [
- UNITROLLER.options.address,
- priceOracleDeployReceipt.contractAddress,
- '500000000000000000',
- 20,
- false
- ],
- true,
- receipt => {},
- '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6'
- )
-
- await runTest(
- 'comptroller implementation is set correctly',
- UNITROLLER,
- 'comptrollerImplementation',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, COMPTROLLER.options.address)
- }
- )
-
- console.log('incrementing Compound deployment nonce...')
- let compoundDeployReceipt
- for (i = 4; i < 7; i++) {
- compoundDeployReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- console.log('deploying Compound cSAI IRM...')
- const cSAIIRMDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCDaiIRMDeploymentData
- })
-
- assert.strictEqual(
- cSAIIRMDeploymentReceipt.contractAddress,
- '0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a'
- )
-
- console.log('deploying Compound cUSDC IRM...')
- const cUSDCIRMDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCUSDCIRMDeploymentData
- })
-
- assert.strictEqual(
- cUSDCIRMDeploymentReceipt.contractAddress,
- '0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB'
- )
-
- console.log('incrementing Compound deployment nonce...')
- for (i = 9; i < 14; i++) {
- compoundDeployReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- console.log('deploying Compound cSai...')
- const cSaiDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCDaiDeploymentData
- })
-
- assert.strictEqual(
- cSaiDeploymentReceipt.contractAddress, constants.CSAI_MAINNET_ADDRESS
- )
-
- for (i = 15; i < 17; i++) {
- compoundDeployReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- console.log('deploying Compound cUSDC...')
- const cUSDCDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCUSDCDeploymentData
- })
-
- assert.strictEqual(
- cUSDCDeploymentReceipt.contractAddress, constants.CUSDC_MAINNET_ADDRESS
- )
-
- for (i = 18; i < 68; i++) {
- compoundDeployReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '1000000' : gasLimit - 1,
- gasPrice: 1,
- data: '0x3838533838f3'
- })
- }
-
- console.log('deploying current Compound comptroller...')
- comptrollerDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '5000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCurrentComptrollerDeploymentData
- })
-
- assert.strictEqual(
- comptrollerDeploymentReceipt.contractAddress,
- '0x178053c06006e67e09879C09Ff012fF9d263dF29'
- )
-
- COMPTROLLER = new web3.eth.Contract(
- COMPTROLLER_ABI,
- comptrollerDeploymentReceipt.contractAddress
- )
-
- await runTest(
- 'Set pending Comptroller on Unitroller',
- UNITROLLER,
- '_setPendingImplementation',
- 'send',
- [
- comptrollerDeploymentReceipt.contractAddress
- ],
- true,
- receipt => {},
- '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6'
- )
-
- await runTest(
- 'Set Comptroller on Unitroller',
- COMPTROLLER,
- '_become',
- 'send',
- [
- UNITROLLER.options.address,
- priceOracleDeployReceipt.contractAddress,
- '500000000000000000',
- 20,
- true
- ],
- true,
- receipt => {},
- '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6'
- )
-
- await runTest(
- 'comptroller implementation is set correctly',
- UNITROLLER,
- 'comptrollerImplementation',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, COMPTROLLER.options.address)
- }
- )
-
- await runTest(
- 'Set pending admin on Unitroller',
- UNITROLLER,
- '_setPendingAdmin',
- 'send',
- [
- address
- ],
- true,
- receipt => {},
- '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6'
- )
-
- await runTest(
- 'Set new admin on Unitroller',
- UNITROLLER,
- '_acceptAdmin'
- )
-
- await runTest(
- 'comptroller admin is set correctly',
- UNITROLLER,
- 'admin',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
+ await runTest(
+ "Call MockSaiToDaiMigrator",
+ MockSaiToDaiMigrator,
+ "swapSaiToDai",
+ "send",
+ [0]
+ );
+
+ // TODO: list increase cDAI and cUSDC collateral factor on comptroller
+
+ // TODO: set prices using price oracle
+
+ // TODO: verify comptroller state
+
+ // TODO: supply and borrow some assets in each market
+
+ console.log(
+ `completed ${passed + failed} test${
+ passed + failed === 1 ? "" : "s"
+ } ` + `with ${failed} failure${failed === 1 ? "" : "s"}.`
+ );
+
+ if (failed > 0) {
+ process.exit(1);
+ }
+
+ // exit.
+ return 0;
}
- )
-
- 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 daiDeploymentReceipt = await web3.eth.sendTransaction({
- from: '0xA7ff0d561cd15eD525e31bbe0aF3fE34ac2059F6',
- gas: (testingContext !== 'coverage') ? '7000000' : gasLimit - 1,
- gasPrice: 1,
- data: mockCDaiDeploymentData.replace(
- '89d24a6b4ccb1b6faa2625fe562bdd9a23260359',
- constants.DAI_MAINNET_ADDRESS.slice(2)
- )
- })
-
- assert.strictEqual(
- daiDeploymentReceipt.contractAddress, constants.CDAI_MAINNET_ADDRESS
- )
-
- await runTest(
- 'List cSai on Comptroller',
- UNITROLLER_COMPTROLLER,
- '_supportMarket',
- 'send',
- [
- CSAI.options.address
- ]
- )
-
- await runTest(
- 'List cUSDC on Comptroller',
- UNITROLLER_COMPTROLLER,
- '_supportMarket',
- 'send',
- [
- CUSDC.options.address
- ]
- )
-
- await runTest(
- 'List cDai on Comptroller',
- UNITROLLER_COMPTROLLER,
- '_supportMarket',
- 'send',
- [
- CDAI.options.address
- ]
- )
-
- await runTest(
- 'Call MockSaiToDaiMigrator',
- MockSaiToDaiMigrator,
- 'swapSaiToDai',
- 'send',
- [0]
- )
-
- // TODO: list increase cDAI and cUSDC collateral factor on comptroller
-
- // TODO: set prices using price oracle
-
- // TODO: verify comptroller state
-
- // TODO: supply and borrow some assets in each market
-
- console.log(
- `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` +
- `with ${failed} failure${failed === 1 ? '' : 's'}.`
- )
-
- if (failed > 0) {
- process.exit(1)
- }
-
- // exit.
- return 0
-}}
+};
diff --git a/scripts/test/test.js b/scripts/test/test.js
index c4ea878..59dec0f 100644
--- a/scripts/test/test.js
+++ b/scripts/test/test.js
@@ -1,13125 +1,9570 @@
-var assert = require('assert')
-var fs = require('fs')
-var util = require('ethereumjs-util')
-const constants = require('./constants.js')
-
-const AdharmaSmartWalletImplementationArtifact = require('../../build/contracts/AdharmaSmartWalletImplementation.json')
-const AdharmaKeyRingImplementationArtifact = require('../../build/contracts/AdharmaKeyRingImplementation.json')
-
-const DharmaUpgradeBeaconControllerManagerArtifact = require('../../build/contracts/DharmaUpgradeBeaconControllerManager.json')
-const DharmaUpgradeBeaconControllerArtifact = require('../../build/contracts/DharmaUpgradeBeaconController.json')
-const DharmaUpgradeBeaconArtifact = require('../../build/contracts/DharmaUpgradeBeacon.json')
-const DharmaKeyRingUpgradeBeaconArtifact = require('../../build/contracts/DharmaKeyRingUpgradeBeacon.json')
-const DharmaUpgradeBeaconEnvoyArtifact = require('../../build/contracts/DharmaUpgradeBeaconEnvoy.json')
-
-const DharmaAccountRecoveryManagerV2Artifact = require('../../build/contracts/DharmaAccountRecoveryManagerV2.json')
-const DharmaKeyRegistryV1Artifact = require('../../build/contracts/DharmaKeyRegistryV1.json')
-const DharmaKeyRegistryV2Artifact = require('../../build/contracts/DharmaKeyRegistryV2.json')
-const DharmaSmartWalletFactoryV1Artifact = require('../../build/contracts/DharmaSmartWalletFactoryV1.json')
-const DharmaSmartWalletFactoryV2Artifact = require('../../build/contracts/DharmaSmartWalletFactoryV2.json')
-
-const DharmaSmartWalletImplementationV0Artifact = require('../../build/contracts/DharmaSmartWalletImplementationV0.json')
-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')
-const DharmaKeyRingFactoryV2Artifact = require('../../build/contracts/DharmaKeyRingFactoryV2.json')
-const DharmaKeyRingFactoryV3Artifact = require('../../build/contracts/DharmaKeyRingFactoryV3.json')
-
-const UpgradeBeaconProxyV1Artifact = require('../../build/contracts/UpgradeBeaconProxyV1.json')
-const KeyRingUpgradeBeaconProxyV1Artifact = require('../../build/contracts/KeyRingUpgradeBeaconProxyV1.json')
-
-const DharmaUpgradeMultisigArtifact = require('../../build/contracts/DharmaUpgradeMultisig.json')
-const DharmaAccountRecoveryMultisigArtifact = require('../../build/contracts/DharmaAccountRecoveryMultisig.json')
-const DharmaAccountRecoveryOperatorMultisigArtifact = require('../../build/contracts/DharmaAccountRecoveryOperatorMultisig.json')
-const DharmaKeyRegistryMultisigArtifact = require('../../build/contracts/DharmaKeyRegistryMultisig.json')
-
-const DharmaEscapeHatchRegistryArtifact = require('../../build/contracts/DharmaEscapeHatchRegistry.json')
-
-const UpgradeBeaconImplementationCheckArtifact = require('../../build/contracts/UpgradeBeaconImplementationCheck.json')
-const BadBeaconArtifact = require('../../build/contracts/BadBeacon.json')
-const BadBeaconTwoArtifact = require('../../build/contracts/BadBeaconTwo.json')
-const TimelockEdgecaseTesterArtifact = require('../../build/contracts/TimelockEdgecaseTester.json')
-
-const MockCodeCheckArtifact = require('../../build/contracts/MockCodeCheck.json')
-const MockDharmaKeyRingFactoryArtifact = require('../../build/contracts/MockDharmaKeyRingFactory.json')
-const IERC20Artifact = require('../../build/contracts/IERC20.json')
-const ComptrollerArtifact = require('../../build/contracts/ComptrollerInterface.json')
-
-const contractNames = Object.assign({}, constants.CONTRACT_NAMES)
-
-// used to wait for more confirmations
-function longer() {
- return new Promise(resolve => {setTimeout(() => {resolve()}, 500)})
-}
-
-module.exports = {test: async function (provider, testingContext) {
- var web3 = provider
- let passed = 0
- let failed = 0
- let gasUsage = {}
- let counts = {}
-
- const DharmaUpgradeBeaconController = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi,
- constants.UPGRADE_BEACON_CONTROLLER_ADDRESS
- )
-
- const DharmaUpgradeBeacon = new web3.eth.Contract(
- DharmaUpgradeBeaconArtifact.abi,
- constants.UPGRADE_BEACON_ADDRESS
- )
-
- const DharmaKeyRingUpgradeBeaconController = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi,
- constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS
- )
-
- const DharmaKeyRingUpgradeBeacon = new web3.eth.Contract(
- DharmaKeyRingUpgradeBeaconArtifact.abi,
- constants.KEY_RING_UPGRADE_BEACON_ADDRESS
- )
-
- const DharmaAccountRecoveryManagerV2 = new web3.eth.Contract(
- DharmaAccountRecoveryManagerV2Artifact.abi,
- constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
- )
-
- const DharmaKeyRegistryV1 = new web3.eth.Contract(
- DharmaKeyRegistryV1Artifact.abi,
- constants.KEY_REGISTRY_ADDRESS
- )
-
- const DharmaKeyRegistryV2 = new web3.eth.Contract(
- DharmaKeyRegistryV2Artifact.abi,
- constants.KEY_REGISTRY_V2_ADDRESS
- )
-
- const DharmaUpgradeBeaconControllerManager = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerManagerArtifact.abi,
- constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS
- )
-
- const DharmaSmartWalletFactoryV1OnChain = new web3.eth.Contract(
- DharmaSmartWalletFactoryV1Artifact.abi,
- constants.FACTORY_ADDRESS
- )
-
- const Comptroller = new web3.eth.Contract(
- ComptrollerArtifact.abi,
- constants.COMPTROLLER_MAINNET_ADDRESS
- )
-
- const CSAI_BORROW = new web3.eth.Contract(
- [{
- "constant": false,
- "inputs": [{"name": "borrowAmount", "type": "uint256"}],
- "name": "borrow",
- "outputs": [{"name": "", "type": "uint256"}],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- }],
- constants.CSAI_MAINNET_ADDRESS
- )
-
- const SAI = new web3.eth.Contract(
- 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
- )
-
- const CSAI = new web3.eth.Contract(
- 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
- )
-
- const BadBeaconDeployer = new web3.eth.Contract(BadBeaconArtifact.abi)
- BadBeaconDeployer.options.data = BadBeaconArtifact.bytecode
-
- const BadBeaconTwoDeployer = new web3.eth.Contract(BadBeaconTwoArtifact.abi)
- BadBeaconTwoDeployer.options.data = BadBeaconTwoArtifact.bytecode
-
-
- const AdharmaSmartWalletImplementationDeployer = new web3.eth.Contract(
- AdharmaSmartWalletImplementationArtifact.abi
- )
- AdharmaSmartWalletImplementationDeployer.options.data = (
- AdharmaSmartWalletImplementationArtifact.bytecode
- )
-
- const DharmaSmartWalletImplementationV0Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV0Artifact.abi
- )
- DharmaSmartWalletImplementationV0Deployer.options.data = (
- DharmaSmartWalletImplementationV0Artifact.bytecode
- )
-
- const DharmaSmartWalletImplementationV1Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV1Artifact.abi
- )
- DharmaSmartWalletImplementationV1Deployer.options.data = (
- DharmaSmartWalletImplementationV1Artifact.bytecode
- )
-
- const DharmaSmartWalletImplementationV2Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV2Artifact.abi
- )
- DharmaSmartWalletImplementationV2Deployer.options.data = (
- DharmaSmartWalletImplementationV2Artifact.bytecode
- )
-
- const DharmaSmartWalletImplementationV5Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV5Artifact.abi
- )
- DharmaSmartWalletImplementationV5Deployer.options.data = (
- DharmaSmartWalletImplementationV5Artifact.bytecode
- )
-
- const DharmaSmartWalletImplementationV6Deployer = new web3.eth.Contract(
- DharmaSmartWalletImplementationV6Artifact.abi
- )
- DharmaSmartWalletImplementationV6Deployer.options.data = (
- DharmaSmartWalletImplementationV6Artifact.bytecode
- )
-
- const AdharmaKeyRingImplementationDeployer = new web3.eth.Contract(
- AdharmaKeyRingImplementationArtifact.abi
- )
- AdharmaKeyRingImplementationDeployer.options.data = (
- AdharmaKeyRingImplementationArtifact.bytecode
- )
-
- const DharmaKeyRingImplementationV1Deployer = new web3.eth.Contract(
- DharmaKeyRingImplementationV1Artifact.abi
- )
- DharmaKeyRingImplementationV1Deployer.options.data = (
- DharmaKeyRingImplementationV1Artifact.bytecode
- )
-
- const UpgradeBeaconImplementationCheckDeployer = new web3.eth.Contract(
- UpgradeBeaconImplementationCheckArtifact.abi
- )
- UpgradeBeaconImplementationCheckDeployer.options.data = (
- UpgradeBeaconImplementationCheckArtifact.bytecode
- )
-
- const TimelockEdgecaseTesterDeployer = new web3.eth.Contract(
- TimelockEdgecaseTesterArtifact.abi
- )
- TimelockEdgecaseTesterDeployer.options.data = (
- TimelockEdgecaseTesterArtifact.bytecode
- )
-
- const MockCodeCheckDeployer = new web3.eth.Contract(
- MockCodeCheckArtifact.abi
- )
- MockCodeCheckDeployer.options.data = MockCodeCheckArtifact.bytecode
-
- const DharmaUpgradeBeaconControllerDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerArtifact.abi
- )
- DharmaUpgradeBeaconControllerDeployer.options.data = (
- DharmaUpgradeBeaconControllerArtifact.bytecode
- )
-
- const DharmaUpgradeBeaconDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconArtifact.abi
- )
- DharmaUpgradeBeaconDeployer.options.data = (
- DharmaUpgradeBeaconArtifact.bytecode
- )
-
- const DharmaKeyRingUpgradeBeaconDeployer = new web3.eth.Contract(
- DharmaKeyRingUpgradeBeaconArtifact.abi
- )
- DharmaKeyRingUpgradeBeaconDeployer.options.data = (
- DharmaKeyRingUpgradeBeaconArtifact.bytecode
- )
-
- const DharmaUpgradeBeaconEnvoyDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconEnvoyArtifact.abi
- )
- DharmaUpgradeBeaconEnvoyDeployer.options.data = (
- DharmaUpgradeBeaconEnvoyArtifact.bytecode
- )
-
- const DharmaUpgradeBeaconControllerManagerDeployer = new web3.eth.Contract(
- DharmaUpgradeBeaconControllerManagerArtifact.abi
- )
- DharmaUpgradeBeaconControllerManagerDeployer.options.data = (
- DharmaUpgradeBeaconControllerManagerArtifact.bytecode
- )
-
- const UpgradeBeaconProxyV1Deployer = new web3.eth.Contract(
- UpgradeBeaconProxyV1Artifact.abi
- )
- UpgradeBeaconProxyV1Deployer.options.data = (
- UpgradeBeaconProxyV1Artifact.bytecode
- )
-
- const KeyRingUpgradeBeaconProxyV1Deployer = new web3.eth.Contract(
- KeyRingUpgradeBeaconProxyV1Artifact.abi
- )
- KeyRingUpgradeBeaconProxyV1Deployer.options.data = (
- KeyRingUpgradeBeaconProxyV1Artifact.bytecode
- )
-
- const DharmaKeyRegistryV2Deployer = new web3.eth.Contract(
- DharmaKeyRegistryV2Artifact.abi
- )
- DharmaKeyRegistryV2Deployer.options.data = (
- DharmaKeyRegistryV2Artifact.bytecode
- )
-
- const DharmaSmartWalletFactoryV1Deployer = new web3.eth.Contract(
- DharmaSmartWalletFactoryV1Artifact.abi
- )
- DharmaSmartWalletFactoryV1Deployer.options.data = (
- DharmaSmartWalletFactoryV1Artifact.bytecode
- )
-
- const DharmaSmartWalletFactoryV2Deployer = new web3.eth.Contract(
- DharmaSmartWalletFactoryV2Artifact.abi
- )
- DharmaSmartWalletFactoryV2Deployer.options.data = (
- DharmaSmartWalletFactoryV2Artifact.bytecode
- )
-
- const DharmaKeyRingFactoryV1Deployer = new web3.eth.Contract(
- DharmaKeyRingFactoryV1Artifact.abi
- )
- DharmaKeyRingFactoryV1Deployer.options.data = (
- DharmaKeyRingFactoryV1Artifact.bytecode
- )
-
- const DharmaKeyRingFactoryV2Deployer = new web3.eth.Contract(
- DharmaKeyRingFactoryV2Artifact.abi
- )
- DharmaKeyRingFactoryV2Deployer.options.data = (
- DharmaKeyRingFactoryV2Artifact.bytecode
- )
-
- const DharmaKeyRingFactoryV3Deployer = new web3.eth.Contract(
- DharmaKeyRingFactoryV3Artifact.abi
- )
- DharmaKeyRingFactoryV3Deployer.options.data = (
- DharmaKeyRingFactoryV3Artifact.bytecode
- )
-
- const MockDharmaKeyRingFactoryDeployer = new web3.eth.Contract(
- MockDharmaKeyRingFactoryArtifact.abi
- )
- MockDharmaKeyRingFactoryDeployer.options.data = (
- MockDharmaKeyRingFactoryArtifact.bytecode
- )
-
- const DharmaAccountRecoveryManagerV2Deployer = new web3.eth.Contract(
- DharmaAccountRecoveryManagerV2Artifact.abi
- )
- DharmaAccountRecoveryManagerV2Deployer.options.data = (
- DharmaAccountRecoveryManagerV2Artifact.bytecode
- )
-
- const DharmaUpgradeMultisigDeployer = new web3.eth.Contract(
- DharmaUpgradeMultisigArtifact.abi
- )
- DharmaUpgradeMultisigDeployer.options.data = (
- DharmaUpgradeMultisigArtifact.bytecode
- )
-
- const DharmaAccountRecoveryMultisigDeployer = new web3.eth.Contract(
- DharmaAccountRecoveryMultisigArtifact.abi
- )
- DharmaAccountRecoveryMultisigDeployer.options.data = (
- DharmaAccountRecoveryMultisigArtifact.bytecode
- )
-
- const DharmaAccountRecoveryOperatorMultisigDeployer = new web3.eth.Contract(
- DharmaAccountRecoveryOperatorMultisigArtifact.abi
- )
- DharmaAccountRecoveryOperatorMultisigDeployer.options.data = (
- DharmaAccountRecoveryOperatorMultisigArtifact.bytecode
- )
-
- const DharmaKeyRegistryMultisigDeployer = new web3.eth.Contract(
- DharmaKeyRegistryMultisigArtifact.abi
- )
- DharmaKeyRegistryMultisigDeployer.options.data = (
- DharmaKeyRegistryMultisigArtifact.bytecode
- )
-
- const DharmaEscapeHatchRegistryDeployer = new web3.eth.Contract(
- DharmaEscapeHatchRegistryArtifact.abi
- )
- DharmaEscapeHatchRegistryDeployer.options.data = (
- DharmaEscapeHatchRegistryArtifact.bytecode
- )
-
- // get available addresses and assign them to various roles
- const addresses = await web3.eth.getAccounts()
- if (addresses.length < 1) {
- console.log('cannot find enough addresses to run tests!')
- process.exit(1)
- }
-
- let latestBlock = await web3.eth.getBlock('latest')
-
- const originalAddress = addresses[0]
-
- let address = await setupNewDefaultAddress(
- '0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed'
- )
-
- let addressTwo = await setupNewDefaultAddress(
- '0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d'
- )
-
- let initialControllerOwner = await setupNewDefaultAddress(
- '0x58e0348ce225c18ece7f2d6a069afa340365019481903b221481706d291a66bf'
- )
-
- const ownerOne = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[0]
- )
- const ownerTwo = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[1]
- )
- const ownerThree = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[2]
- )
- const ownerFour = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[3]
- )
- const ownerFive = await setupNewDefaultAddress(
- constants.MOCK_OWNER_PRIVATE_KEYS[4]
- )
-
- const gasLimit = latestBlock.gasLimit
-
- console.log('running tests...')
-
- // ************************** helper functions **************************** //
- async function send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- const receipt = await instance.methods[method](...args).send({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
- }
-
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
-
- return assertionsPassed
- }
-
- async function call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let succeeded = true
- returnValues = await instance.methods[method](...args).call({
- from: from,
- value: value,
- gas: gas,
- gasPrice: gasPrice
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- succeeded = false
- })
-
- if (succeeded !== shouldSucceed) {
- return false
- } else if (!shouldSucceed) {
- return true
- }
-
- let assertionsPassed
- try {
- assertionCallback(returnValues)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- console.log(error);
- }
-
- return assertionsPassed
- }
-
- async function deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- gasPrice,
- shouldSucceed,
- assertionCallback
- ) {
- let deployData = instance.deploy({arguments: args}).encodeABI()
- let deployGas = await web3.eth.estimateGas({
- from: from,
- data: deployData
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
- return gasLimit
- })
-
- if (deployGas > gasLimit) {
- console.error(` ✘ ${title}: deployment costs exceed block gas limit!`)
- process.exit(1)
- }
-
- if (typeof(gas) === 'undefined') {
- gas = deployGas
- }
-
- if (deployGas > gas) {
- console.error(` ✘ ${title}: deployment costs exceed supplied gas.`)
- process.exit(1)
- }
-
- let signed
- let deployHash
- let receipt
- const contract = await instance.deploy({arguments: args}).send({
- from: from,
- gas: gas,
- gasPrice: gasPrice
- }).on('transactionHash', hash => {
- deployHash = hash
- }).on('receipt', r => {
- receipt = r
- }).on('confirmation', (confirmationNumber, r) => {
- confirmations[r.transactionHash] = confirmationNumber
- }).catch(error => {
- if (shouldSucceed) {
- console.error(error)
- }
-
- receipt = {status: false}
- })
-
- if (receipt.status !== shouldSucceed) {
- if (contract) {
- return [false, contract, gas]
- }
- return [false, instance, gas]
- } else if (!shouldSucceed) {
- if (contract) {
- return [true, contract, gas]
- }
- return [true, instance, gas]
- }
-
- assert.ok(receipt.status)
-
- let assertionsPassed
- try {
- assertionCallback(receipt)
- assertionsPassed = true
- } catch(error) {
- assertionsPassed = false
- }
+var assert = require("assert");
+var fs = require("fs");
+var util = require("ethereumjs-util");
+const constants = require("./constants.js");
+const { web3 } = require("./web3");
+const { Tester, longer } = require("./testHelpers");
+const {
+ testAccountRecoveryManager
+} = require("./contracts/account-recovery/testAccountRecoveryManager");
+const {
+ testUpgradeBeaconController
+} = require("./contracts/upgradeability/testUpgradeBeaconController");
+const {
+ testUpgradeBeaconControllerManagerPartOne,
+ testUpgradeBeaconControllerManagerPartTwo
+} = require("./contracts/upgradeability/testUpgradeBeaconControllerManager");
+const {
+ testKeyRegistryV2
+} = require("./contracts/registries/testKeyRegistryV2");
+const {
+ testPerformingUpgrade
+} = require("./contracts/upgradeability/testPerformingUpgrade");
+
+const AdharmaSmartWalletImplementationArtifact = require("../../build/contracts/AdharmaSmartWalletImplementation.json");
+const AdharmaKeyRingImplementationArtifact = require("../../build/contracts/AdharmaKeyRingImplementation.json");
+
+const DharmaSmartWalletImplementationV6Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV6.json");
+const DharmaSmartWalletImplementationV7Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV7.json");
+
+const DharmaKeyRingImplementationV1Artifact = require("../../build/contracts/DharmaKeyRingImplementationV1.json");
+
+const contractNames = Object.assign({}, constants.CONTRACT_NAMES);
+
+const ONE = web3.utils.toBN("1");
+const ZERO = web3.utils.toBN("0");
+
+async function test(testingContext) {
+ const tester = new Tester(testingContext);
+ await tester.init();
+
+ console.log("running tests...");
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconController can transfer owner`,
+ tester.DharmaUpgradeBeaconController,
+ "transferOwnership",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 gets the initial global key correctly",
+ tester.DharmaKeyRegistryV2,
+ "getGlobalKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ const messageV2 =
+ tester.DharmaKeyRegistryV2.options.address +
+ tester.address.slice(2) +
+ web3.utils
+ .asciiToHex(
+ "This signature demonstrates that the supplied signing key is valid."
+ )
+ .slice(2);
+
+ const v2KeySignature = tester.signHashedPrefixedHashedHexString(
+ messageV2,
+ tester.address
+ );
+
+ await tester.runTest(
+ "Dharma Key Registry V2 cannot set a previously used global key",
+ tester.DharmaKeyRegistryV2,
+ "setGlobalKey",
+ "send",
+ [tester.address, v2KeySignature],
+ false
+ );
+
+ const BadBeacon = await tester.runTest(
+ `Mock Bad Beacon contract deployment`,
+ tester.BadBeaconDeployer,
+ "",
+ "deploy"
+ );
+
+ const BadBeaconTwo = await tester.runTest(
+ `Mock Bad Beacon Two contract deployment`,
+ tester.BadBeaconTwoDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletImplementationV6 = await tester.runTest(
+ `DharmaSmartWalletImplementationV6 contract deployment`,
+ tester.DharmaSmartWalletImplementationV6Deployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletImplementationV7 = await tester.runTest(
+ `DharmaSmartWalletImplementationV7 contract deployment`,
+ tester.DharmaSmartWalletImplementationV7Deployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaKeyRingImplementationV1 = await tester.runTest(
+ `DharmaKeyRingImplementationV1 contract deployment`,
+ tester.DharmaKeyRingImplementationV1Deployer,
+ "",
+ "deploy"
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller cannot set null address as implementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [tester.DharmaUpgradeBeacon.options.address, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller cannot set non-contract as implementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [tester.DharmaUpgradeBeacon.options.address, tester.address],
+ false
+ );
+
+ await tester.runTest(
+ 'Dharma Upgrade Beacon Controller cannot support a "bad" beacon that throws',
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ BadBeacon.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller cannot upgrade a non-upgradeable beacon",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ BadBeaconTwo.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller is inaccessible from a non-owner",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaUpgradeBeacon.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller can set initial upgrade beacon implementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaUpgradeBeacon.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ],
+ true,
+ receipt => {
+ if (testingContext !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.upgradeBeacon,
+ tester.DharmaUpgradeBeacon.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.oldImplementation,
+ constants.NULL_ADDRESS
+ );
+ 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 tester.runTest(
+ "Dharma Upgrade Beacon Controller cannot clear upgrade beacon implementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [tester.DharmaUpgradeBeacon.options.address, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller can reset upgrade beacon implementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaUpgradeBeacon.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ],
+ true,
+ receipt => {
+ if (testingContext !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.upgradeBeacon,
+ tester.DharmaUpgradeBeacon.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.oldImplementation,
+ DharmaSmartWalletImplementationV6.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,
+ ...
+ )
+ */
+ }
+ }
+ );
- if (contract) {
- return [assertionsPassed, contract, gas]
- }
- return [assertionsPassed, instance, gas]
- }
+ const UpgradeBeaconImplementationCheck = await tester.runTest(
+ `UpgradeBeaconImplementationCheck deployment`,
+ tester.UpgradeBeaconImplementationCheckDeployer,
+ "",
+ "deploy",
+ [
+ tester.DharmaUpgradeBeacon.options.address,
+ DharmaSmartWalletImplementationV6.options.address
+ ]
+ );
+
+ await tester.runTest(
+ "DharmaUpgradeBeacon has the implementation set",
+ tester.DharmaUpgradeBeaconController,
+ "getImplementation",
+ "call",
+ [tester.DharmaUpgradeBeacon.options.address],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ DharmaSmartWalletImplementationV6.options.address
+ );
+ }
+ );
- async function runTest(
- title,
- instance,
- method,
- callOrSend,
- args,
- shouldSucceed,
- assertionCallback,
- from,
- value,
- gas
- ) {
- if (typeof(callOrSend) === 'undefined') {
- callOrSend = 'send'
- }
- if (typeof(args) === 'undefined') {
- args = []
- }
- if (typeof(shouldSucceed) === 'undefined') {
- shouldSucceed = true
- }
- if (typeof(assertionCallback) === 'undefined') {
- assertionCallback = (value) => {}
- }
- if (typeof(from) === 'undefined') {
- from = address
- }
- if (typeof(value) === 'undefined') {
- value = 0
- }
- if (typeof(gas) === 'undefined' && callOrSend !== 'deploy') {
- gas = 6009006
- if (testingContext === 'coverage') {
- gas = gasLimit - 1
- }
- }
- let ok = false
- let contract
- let deployGas
- if (callOrSend === 'send') {
- ok = await send(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'call') {
- ok = await call(
- title,
- instance,
- method,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- } else if (callOrSend === 'deploy') {
- const fields = await deploy(
- title,
- instance,
- args,
- from,
- value,
- gas,
- 1,
- shouldSucceed,
- assertionCallback
- )
- ok = fields[0]
- contract = fields[1]
- deployGas = fields[2]
- } else {
- console.error('must use call, send, or deploy!')
- process.exit(1)
- }
+ await tester.runTest(
+ "Dharma Key Ring Upgrade Beacon Controller can set initial key ring upgrade beacon implementation",
+ tester.DharmaKeyRingUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaKeyRingUpgradeBeacon.options.address,
+ DharmaKeyRingImplementationV1.options.address
+ ],
+ true,
+ receipt => {
+ if (testingContext !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.upgradeBeacon,
+ tester.DharmaKeyRingUpgradeBeacon.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.oldImplementation,
+ constants.NULL_ADDRESS
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues
+ .oldImplementationCodeHash,
+ constants.EMPTY_HASH
+ );
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.newImplementation,
+ DharmaKeyRingImplementationV1.options.address
+ );
+ /* TODO
+ assert.strictEqual(
+ receipt.events.Upgraded.returnValues.newImplementationCodeHash,
+ ...
+ )
+ */
+ }
+ }
+ );
- if (ok) {
- console.log(
- ` ✓ ${
- callOrSend === 'deploy' ? 'successful ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- passed++
- } else {
- console.log(
- ` ✘ ${
- callOrSend === 'deploy' ? 'failed ' : ''
- }${title}${
- callOrSend === 'deploy' ? ` (${deployGas} gas)` : ''
- }`
- )
- failed++
- }
+ const KeyRingUpgradeBeaconImplementationCheck = await tester.runTest(
+ `KeyRingUpgradeBeaconImplementationCheck deployment`,
+ tester.UpgradeBeaconImplementationCheckDeployer,
+ "",
+ "deploy",
+ [
+ tester.DharmaKeyRingUpgradeBeacon.options.address,
+ DharmaKeyRingImplementationV1.options.address
+ ]
+ );
+
+ await tester.runTest(
+ "DharmaKeyRingUpgradeBeacon has the implementation set",
+ tester.DharmaKeyRingUpgradeBeaconController,
+ "getImplementation",
+ "call",
+ [tester.DharmaKeyRingUpgradeBeacon.options.address],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ DharmaKeyRingImplementationV1.options.address
+ );
+ }
+ );
+
+ const DharmaSmartWalletNoFactoryNoConstructorDeployer = new web3.eth.Contract(
+ []
+ );
+ DharmaSmartWalletNoFactoryNoConstructorDeployer.options.data =
+ "0x600b5981380380925939f359595959365960205959596e" +
+ tester.DharmaUpgradeBeacon.options.address.slice(12).toLowerCase() +
+ "5afa1551368280375af43d3d93803e602e57fd5bf3";
+
+ const DharmaSmartWalletNoFactoryNoConstructor = await tester.runTest(
+ `DharmaSmartWallet minimal upgradeable proxy deployment - no factory or constructor`,
+ DharmaSmartWalletNoFactoryNoConstructorDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletImplementationTest = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ DharmaSmartWalletNoFactoryNoConstructor.options.address
+ );
+
+ await tester.runTest(
+ "test passes",
+ DharmaSmartWalletImplementationTest,
+ "getVersion",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.length > 0);
+ }
+ );
+
+ let currentSaiCode;
+ await tester.runTest(
+ "Checking for required external contracts...",
+ tester.MockCodeCheck,
+ "code",
+ "call",
+ [constants.SAI_MAINNET_ADDRESS],
+ true,
+ value => {
+ currentSaiCode = value;
+ }
+ );
+
+ if (!currentSaiCode) {
+ console.log(
+ `completed ${tester.passed + tester.failed} test${
+ tester.passed + tester.failed === 1 ? "" : "s"
+ } ` +
+ `with ${tester.failed} failure${
+ tester.failed === 1 ? "" : "s"
+ }.`
+ );
+
+ console.log(
+ "Note that the full test suite cannot be executed locally - instead, " +
+ "run against a fork of mainnet using `yarn forkStart` and `yarn test`."
+ );
+
+ if (tester.failed > 0) {
+ process.exit(1);
+ }
- if (contract) {
- return contract
+ // exit.
+ return 0;
+ }
+
+ const DharmaSmartWalletNoFactoryDeployer = new web3.eth.Contract([]);
+ DharmaSmartWalletNoFactoryDeployer.options.data =
+ "0x595959596076380359602059595973" +
+ tester.DharmaUpgradeBeacon.options.address.slice(2).toLowerCase() +
+ "5afa155182607683395af46038573d903d81803efd5b60356041819339f3595959593659602059595973" +
+ tester.DharmaUpgradeBeacon.options.address.slice(2).toLowerCase() +
+ "5afa1551368280375af43d3d93803e603357fd5bf3" +
+ "c4d66de80000000000000000000000009999999999999999999999999999999999999999";
+
+ const DharmaSmartWalletNoFactory = await tester.runTest(
+ `DharmaSmartWallet minimal upgradeable proxy deployment - no factory but with constructor`,
+ DharmaSmartWalletNoFactoryDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletImplementationTestWithConstructor = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ DharmaSmartWalletNoFactory.options.address
+ );
+
+ await tester.runTest(
+ "test passes",
+ DharmaSmartWalletImplementationTestWithConstructor,
+ "getVersion",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.length > 0);
+ }
+ );
+
+ await tester.runTest(
+ "new user smart wallet can be called and has the correct dharma key set",
+ DharmaSmartWalletImplementationTestWithConstructor,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ "0x9999999999999999999999999999999999999999"
+ );
+ }
+ );
+
+ const DharmaSmartWalletFactoryV1 = await tester.runTest(
+ `DharmaSmartWalletFactoryV1 contract deployment`,
+ tester.DharmaSmartWalletFactoryV1Deployer,
+ "",
+ "deploy",
+ []
+ );
+
+ let targetWalletAddress;
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time",
+ DharmaSmartWalletFactoryV1,
+ "getNextSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ // TODO: verify against expected value
+ targetWalletAddress = value;
+ }
+ );
+
+ const UserSmartWalletV6 = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ targetWalletAddress
+ );
+
+ const UserSmartWalletV7 = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV7Artifact.abi,
+ targetWalletAddress
+ );
+
+ await testPerformingUpgrade(
+ tester,
+ DharmaSmartWalletImplementationV6, // new implementation
+ UserSmartWalletV6,
+ tester.DharmaUpgradeBeaconController,
+ tester.DharmaUpgradeBeacon.options.address,
+ 6,
+ true
+ );
+
+ contractNames[DharmaSmartWalletFactoryV1.options.address] =
+ "Smart Wallet Factory";
+ contractNames[targetWalletAddress] = "Smart Wallet";
+
+ const ethWhaleBalance = await web3.eth.getBalance(
+ constants.ETH_WHALE_ADDRESS
+ );
+ const saiWhaleBalance = await web3.eth.getBalance(
+ constants.SAI_WHALE_ADDRESS
+ );
+ const daiWhaleBalance = await web3.eth.getBalance(
+ constants.DAI_WHALE_ADDRESS
+ );
+ const usdcWhaleBalance = await web3.eth.getBalance(
+ constants.USDC_WHALE_ADDRESS
+ );
+
+ if (ethWhaleBalance === "0") {
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.ETH_WHALE_ADDRESS,
+ value: web3.utils.toWei(".2", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+ console.log(" ✓ Eth Whale can receive eth if needed");
+ }
+
+ if (saiWhaleBalance === "0") {
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.SAI_WHALE_ADDRESS,
+ value: web3.utils.toWei(".1", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+ console.log(" ✓ Sai Whale can receive eth if needed");
+ }
+
+ if (daiWhaleBalance === "0") {
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.DAI_WHALE_ADDRESS,
+ value: web3.utils.toWei(".1", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+ console.log(" ✓ Dai Whale can receive eth if needed");
+ }
+
+ if (usdcWhaleBalance === "0") {
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.USDC_WHALE_ADDRESS,
+ value: web3.utils.toWei(".1", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+ console.log(" ✓ USDC Whale can receive eth if needed");
}
- }
-
- async function setupNewDefaultAddress(newPrivateKey) {
- const pubKey = await web3.eth.accounts.privateKeyToAccount(newPrivateKey)
- await web3.eth.accounts.wallet.add(pubKey)
await web3.eth.sendTransaction({
- from: originalAddress,
- to: pubKey.address,
- value: 2 * 10 ** 18,
- gas: '0x5208',
- gasPrice: '0x4A817C800'
- })
-
- return pubKey.address
- }
-
- async function raiseGasLimit(necessaryGas) {
- iterations = 9999
- if (necessaryGas > 8000000) {
- console.error('the gas needed is too high!')
- process.exit(1)
- } else if (typeof necessaryGas === 'undefined') {
- iterations = 20
- necessaryGas = 8000000
- }
+ from: constants.ETH_WHALE_ADDRESS,
+ to: targetWalletAddress,
+ value: web3.utils.toWei(".1", "ether"),
+ gas: testingContext !== "coverage" ? "0x5208" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+ console.log(
+ " ✓ Eth Whale can deposit eth into the yet-to-be-deployed smart wallet"
+ );
+
+ await tester.runTest(
+ "Dai Whale can deposit dai into the yet-to-be-deployed smart wallet",
+ tester.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 tester.runTest(
+ "USDC Whale can deposit usdc into the yet-to-be-deployed smart wallet",
+ tester.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 tester.runTest(
+ "DharmaSmartWalletFactoryV1 cannot deploy a new smart wallet with no key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy a new smart wallet using a Dharma Key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [tester.address],
+ 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]];
+ if (typeof log === "undefined") {
+ console.log(value);
+ }
+ 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, "Smart Wallet");
+ assert.strictEqual(events[0].eventName, "NewUserSigningKey");
+ assert.strictEqual(
+ events[0].returnValues.userSigningKey,
+ tester.address
+ );
+
+ assert.strictEqual(events[1].address, "DAI");
+ 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].eventName, "AccrueInterest");
+
+ assert.strictEqual(events[3].address, "DAI");
+ 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].eventName, "Mint");
+ assert.strictEqual(
+ events[4].returnValues.mintTokens,
+ web3.utils.toWei("100", "ether")
+ );
+
+ assert.strictEqual(events[5].address, "CDAI");
+ assert.strictEqual(events[5].eventName, "Transfer");
+
+ assert.strictEqual(events[6].address, "USDC");
+ assert.strictEqual(events[6].eventName, "Approval");
+ assert.strictEqual(
+ events[6].returnValues.value,
+ constants.FULL_APPROVAL
+ );
+
+ assert.strictEqual(events[7].address, "CUSDC");
+ assert.strictEqual(events[7].eventName, "AccrueInterest");
+
+ assert.strictEqual(events[8].address, "USDC");
+ assert.strictEqual(events[8].eventName, "Transfer");
+ assert.strictEqual(
+ events[8].returnValues.value,
+ web3.utils.toWei("100", "lovelace")
+ );
+
+ assert.strictEqual(events[9].address, "CUSDC");
+ assert.strictEqual(events[9].eventName, "Mint");
+ assert.strictEqual(
+ events[9].returnValues.mintTokens,
+ web3.utils.toWei("100", "lovelace")
+ );
+
+ assert.strictEqual(events[10].address, "CUSDC");
+ assert.strictEqual(events[10].eventName, "Transfer");
+ }
+ }
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 gets a new smart wallet address with same key",
+ DharmaSmartWalletFactoryV1,
+ "getNextSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ // TODO: verify against expected value
+ assert.ok(targetWalletAddress !== value);
+ }
+ );
+
+ let originalNonce = 0;
+ await tester.runTest(
+ "UserSmartWalletV6 nonce can be retrieved and starts at zero",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, originalNonce.toString());
+ }
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get balances",
+ UserSmartWalletV6,
+ "getBalances",
+ "call",
+ [],
+ true,
+ value => {
+ //console.log(value)
+ }
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet secondary can call to cancel",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ [0, "0x"]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet nonce is now set to original + 1",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, (parseInt(originalNonce) + 1).toString());
+ }
+ );
- // bring up gas limit if necessary by doing additional transactions
- var block = await web3.eth.getBlock("latest")
- while (iterations > 0 && block.gasLimit < necessaryGas) {
- await web3.eth.sendTransaction({
- from: originalAddress,
- to: originalAddress,
- value: '0x01',
- gas: '0x5208',
- gasPrice: '0x4A817C800'
- })
- var block = await web3.eth.getBlock("latest")
- iterations--
- }
+ await tester.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
+ tester.addressTwo,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can set a new user signing key with signatures",
+ UserSmartWalletV6,
+ "setUserSigningKey",
+ "send",
+ [tester.addressTwo, 0, "0x", setUserSigningKeyDharmaSignature]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet has the new user signing key set",
+ UserSmartWalletV6,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
+
+ await tester.runTest(
+ "cSai can be sent to V6 UserSmartWallet",
+ tester.CSAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV6.options.address, web3.utils.toWei("0.5", "mwei")]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get next custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // DAIWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
- console.log("raising gasLimit, currently at " + block.gasLimit)
- return block.gasLimit
- }
+ await tester.runTest(
+ "V6 UserSmartWallet can get custom action ID and it matches next action ID",
+ UserSmartWalletV6,
+ "getCustomActionID",
+ "call",
+ [
+ 0, // DAIWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ parseInt(originalNonce) + 2,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get next generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [tester.address, "0x", 0],
+ true,
+ value => {
+ genericActionID = value;
+ }
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get generic action ID and it matches next action ID",
+ UserSmartWalletV6,
+ "getGenericActionID",
+ "call",
+ [tester.address, "0x", parseInt(originalNonce) + 2, 0],
+ true,
+ value => {
+ assert.strictEqual(value, genericActionID);
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet calls to atomic methods revert",
+ UserSmartWalletV6,
+ "_withdrawDaiAtomic",
+ "send",
+ ["1", tester.address],
+ false
+ );
+
+ // Give the Dai Whale some ETH so it can make transactions
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.DAI_WHALE_ADDRESS,
+ value: web3.utils.toWei("1", "ether"),
+ gas: testingContext !== "coverage" ? "0xffff" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+
+ await tester.runTest(
+ "Dai Whale can deposit Dai into the V6 smart wallet",
+ tester.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 tester.runTest(
+ "USDC Whale can deposit usdc into the V6 smart wallet",
+ tester.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 tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.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 tester.runTest(
+ "Dai Whale can deposit dai into the V6 smart wallet",
+ tester.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 tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [constants.ESCAPE_HATCH_REGISTRY_ADDRESS, "0x", 0],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.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 tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.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
+ }
+ }
+ );
- async function getDeployGas(dataPayload) {
- await web3.eth.estimateGas({
- from: address,
- data: dataPayload
- }).catch(async error => {
- if (
- error.message === (
- 'Returned error: gas required exceeds allowance or always failing ' +
- 'transaction'
- )
- ) {
- await raiseGasLimit()
- await getDeployGas(dataPayload)
- }
- })
-
- deployGas = await web3.eth.estimateGas({
- from: address,
- data: dataPayload
- })
-
- return deployGas
- }
-
- function signHashedPrefixedHexString(hashedHexString, account) {
- const hashedPrefixedMessage = web3.utils.keccak256(
- // prefix => "\x19Ethereum Signed Message:\n32"
- "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
- hashedHexString.slice(2),
- {encoding: "hex"}
- )
-
- const sig = util.ecsign(
- util.toBuffer(hashedPrefixedMessage),
- util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
- )
-
- return (
- util.bufferToHex(sig.r) +
- util.bufferToHex(sig.s).slice(2) +
- web3.utils.toHex(sig.v).slice(2)
- )
- }
-
- function signHashedPrefixedHashedHexString(hexString, account) {
- const hashedPrefixedHashedMessage = web3.utils.keccak256(
- // prefix => "\x19Ethereum Signed Message:\n32"
- "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
- web3.utils.keccak256(hexString, {encoding: "hex"}).slice(2),
- {encoding: "hex"}
- )
-
- const sig = util.ecsign(
- util.toBuffer(hashedPrefixedHashedMessage),
- util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
- )
-
- return (
- util.bufferToHex(sig.r) +
- util.bufferToHex(sig.s).slice(2) +
- web3.utils.toHex(sig.v).slice(2)
- )
- }
-
- async function advanceTime(time) {
- await web3.currentProvider.send(
- {
- jsonrpc: '2.0',
- method: 'evm_increaseTime',
- params: [time],
- id: new Date().getTime()
- },
- (err, result) => {
- if (err) {
- console.error(err)
- } else {
- console.log(' ✓ advanced time by', time, 'seconds')
- }
- }
- )
- }
-
- // *************************** deploy contracts *************************** //
- let deployGas
- let selfAddress
-
- await runTest(
- `DharmaUpgradeBeaconController can transfer owner`,
- DharmaUpgradeBeaconController,
- 'transferOwnership',
- 'send',
- [address]
- )
-
- const MockCodeCheck = await runTest(
- `MockCodeCheck contract deployment`,
- MockCodeCheckDeployer,
- '',
- 'deploy'
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the initial global key correctly',
- DharmaKeyRegistryV1,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V1 attempt to get an unset specific key throws',
- DharmaKeyRegistryV1,
- 'getSpecificKey',
- 'call',
- [address],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the global key when requesting unset key',
- DharmaKeyRegistryV1,
- 'getKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V1 cannot set a new empty global key',
- DharmaKeyRegistryV1,
- 'setGlobalKey',
- 'send',
- [
- constants.NULL_ADDRESS,
- '0x'
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- const message = (
- DharmaKeyRegistryV1.options.address +
- address.slice(2) +
- web3.utils.asciiToHex(
- "This signature demonstrates that the supplied signing key is valid."
- ).slice(2)
- )
-
- const newKeySignature = signHashedPrefixedHashedHexString(message, address)
-
- const badNewKeySignature = signHashedPrefixedHashedHexString('0x12', address)
-
- await runTest(
- 'Dharma Key Registry V1 cannot set a new global key unless called by owner',
- DharmaKeyRegistryV1,
- 'setGlobalKey',
- 'send',
- [
- address,
- newKeySignature
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'Dharma Key Registry V1 cannot set a new global key with a bad signature',
- DharmaKeyRegistryV1,
- 'setGlobalKey',
- 'send',
- [
- address,
- badNewKeySignature
- ],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V1 can set a new global key correctly',
- DharmaKeyRegistryV1,
- 'setGlobalKey',
- 'send',
- [
- address,
- newKeySignature
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the new global key correctly',
- DharmaKeyRegistryV1,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V1 cannot set a new specific key unless called by owner',
- DharmaKeyRegistryV1,
- 'setSpecificKey',
- 'send',
- [
- address,
- DharmaKeyRegistryV1.options.address
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'Dharma Key Registry V1 can set a new specific key',
- DharmaKeyRegistryV1,
- 'setSpecificKey',
- 'send',
- [
- address,
- DharmaKeyRegistryV1.options.address
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the new specific key correctly',
- DharmaKeyRegistryV1,
- 'getSpecificKey',
- 'call',
- [address],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryV1.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the specific key when requesting set key',
- DharmaKeyRegistryV1,
- 'getKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryV1.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V1 can set a new owner',
- DharmaKeyRegistryV1,
- 'transferOwnership',
- 'send',
- [
- address
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V1 gets the new owner',
- DharmaKeyRegistryV1,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the new global key correctly',
- DharmaKeyRegistryV2,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- const messageV2 = (
- DharmaKeyRegistryV2.options.address +
- address.slice(2) +
- web3.utils.asciiToHex(
- "This signature demonstrates that the supplied signing key is valid."
- ).slice(2)
- )
-
- const v2KeySignature = signHashedPrefixedHashedHexString(messageV2, address)
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a previously used global key',
- DharmaKeyRegistryV2,
- 'setGlobalKey',
- 'send',
- [
- address,
- v2KeySignature
- ],
- false
- )
-
- const BadBeacon = await runTest(
- `Mock Bad Beacon contract deployment`,
- BadBeaconDeployer,
- '',
- 'deploy'
- )
-
- const BadBeaconTwo = await runTest(
- `Mock Bad Beacon Two contract deployment`,
- BadBeaconTwoDeployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationV0 = await runTest(
- `DharmaSmartWalletImplementationV0 contract deployment`,
- DharmaSmartWalletImplementationV0Deployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationV1 = await runTest(
- `DharmaSmartWalletImplementationV1 contract deployment`,
- DharmaSmartWalletImplementationV1Deployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationV2 = await runTest(
- `DharmaSmartWalletImplementationV2 contract deployment`,
- DharmaSmartWalletImplementationV2Deployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationV5 = await runTest(
- `DharmaSmartWalletImplementationV5 contract deployment`,
- DharmaSmartWalletImplementationV5Deployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationV6 = await runTest(
- `DharmaSmartWalletImplementationV6 contract deployment`,
- DharmaSmartWalletImplementationV6Deployer,
- '',
- 'deploy'
- )
-
- const DharmaKeyRingImplementationV1 = await runTest(
- `DharmaKeyRingImplementationV1 contract deployment`,
- DharmaKeyRingImplementationV1Deployer,
- '',
- 'deploy'
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller cannot set null address as implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- constants.NULL_ADDRESS
- ],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller cannot set non-contract as implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- address
- ],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller cannot support a "bad" beacon that throws',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- BadBeacon.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller cannot upgrade a non-upgradeable beacon',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- BadBeaconTwo.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller is inaccessible from a non-owner',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can set initial upgrade beacon implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- constants.NULL_ADDRESS
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaSmartWalletImplementationV0.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementationCodeHash,
- ...
- )
- */
- }
- }
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller cannot clear upgrade beacon implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- constants.NULL_ADDRESS
- ],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can reset upgrade beacon implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- DharmaSmartWalletImplementationV0.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- */
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaSmartWalletImplementationV0.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementationCodeHash,
- ...
- )
- */
- }
- }
- )
-
- const UpgradeBeaconImplementationCheck = await runTest(
- `UpgradeBeaconImplementationCheck deployment`,
- UpgradeBeaconImplementationCheckDeployer,
- '',
- 'deploy',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV0.options.address
- ]
- )
-
- await runTest(
- 'DharmaUpgradeBeacon has the implementation set',
- DharmaUpgradeBeaconController,
- 'getImplementation',
- 'call',
- [DharmaUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaSmartWalletImplementationV0.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Ring Upgrade Beacon Controller can set initial key ring upgrade beacon implementation',
- DharmaKeyRingUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaKeyRingUpgradeBeacon.options.address,
- DharmaKeyRingImplementationV1.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaKeyRingUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- constants.NULL_ADDRESS
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaKeyRingImplementationV1.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementationCodeHash,
- ...
- )
- */
- }
- }
- )
-
- const KeyRingUpgradeBeaconImplementationCheck = await runTest(
- `KeyRingUpgradeBeaconImplementationCheck deployment`,
- UpgradeBeaconImplementationCheckDeployer,
- '',
- 'deploy',
- [
- DharmaKeyRingUpgradeBeacon.options.address,
- DharmaKeyRingImplementationV1.options.address
- ]
- )
-
- await runTest(
- 'DharmaKeyRingUpgradeBeacon has the implementation set',
- DharmaKeyRingUpgradeBeaconController,
- 'getImplementation',
- 'call',
- [DharmaKeyRingUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRingImplementationV1.options.address)
- }
- )
-
- const DharmaSmartWalletNoFactoryNoConstructorDeployer = new web3.eth.Contract([])
- DharmaSmartWalletNoFactoryNoConstructorDeployer.options.data = (
- '0x600b5981380380925939f359595959365960205959596e' +
- DharmaUpgradeBeacon.options.address.slice(12).toLowerCase() +
- '5afa1551368280375af43d3d93803e602e57fd5bf3'
- )
-
- const DharmaSmartWalletNoFactoryNoConstructor = await runTest(
- `DharmaSmartWallet minimal upgradeable proxy deployment - no factory or constructor`,
- DharmaSmartWalletNoFactoryNoConstructorDeployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationTest = new web3.eth.Contract(
- DharmaSmartWalletImplementationV0Artifact.abi,
- DharmaSmartWalletNoFactoryNoConstructor.options.address
- )
-
- await runTest(
- 'test passes',
- DharmaSmartWalletImplementationTest,
- 'test',
- 'call',
- [],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- let currentSaiCode;
- await runTest(
- 'Checking for required external contracts...',
- MockCodeCheck,
- 'code',
- 'call',
- [constants.SAI_MAINNET_ADDRESS],
- true,
- value => {
- currentSaiCode = value;
- }
- )
-
- if (!currentSaiCode) {
- console.log(
- `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` +
- `with ${failed} failure${failed === 1 ? '' : 's'}.`
- )
-
- console.log(
- 'Note that the full test suite cannot be executed locally - instead, ' +
- 'run against a fork of mainnet using `yarn forkStart` and `yarn test`.'
- )
-
- if (failed > 0) {
- process.exit(1)
- }
-
- // exit.
- return 0
- }
-
- const DharmaSmartWalletNoFactoryDeployer = new web3.eth.Contract([])
- DharmaSmartWalletNoFactoryDeployer.options.data = (
- '0x595959596076380359602059595973' +
- DharmaUpgradeBeacon.options.address.slice(2).toLowerCase() +
- '5afa155182607683395af46038573d903d81803efd5b60356041819339f3595959593659602059595973' +
- DharmaUpgradeBeacon.options.address.slice(2).toLowerCase() +
- '5afa1551368280375af43d3d93803e603357fd5bf3' +
- 'c4d66de80000000000000000000000009999999999999999999999999999999999999999'
- )
-
- const DharmaSmartWalletNoFactory = await runTest(
- `DharmaSmartWallet minimal upgradeable proxy deployment - no factory but with constructor`,
- DharmaSmartWalletNoFactoryDeployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletImplementationTestWithConstructor = new web3.eth.Contract(
- DharmaSmartWalletImplementationV0Artifact.abi,
- DharmaSmartWalletNoFactory.options.address
- )
-
- await runTest(
- 'test passes',
- DharmaSmartWalletImplementationTestWithConstructor,
- 'test',
- 'call',
- [],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- 'new user smart wallet can be called and has the correct dharma key set',
- DharmaSmartWalletImplementationTestWithConstructor,
- 'getUserSigningKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0x9999999999999999999999999999999999999999')
- }
- )
-
- const DharmaSmartWalletFactoryV1 = await runTest(
- `DharmaSmartWalletFactoryV1 contract deployment`,
- DharmaSmartWalletFactoryV1Deployer,
- '',
- 'deploy',
- []
- )
-
- let targetWalletAddress;
- await runTest(
- 'DharmaSmartWalletFactoryV1 can get a new smart wallet address ahead of time',
- DharmaSmartWalletFactoryV1,
- 'getNextSmartWallet',
- 'call',
- [address],
- true,
- value => {
- // TODO: verify against expected value
- targetWalletAddress = value
- }
- )
-
- contractNames[DharmaSmartWalletFactoryV1.options.address] = 'Smart Wallet Factory'
- contractNames[targetWalletAddress] = 'Smart Wallet'
-
- const ethWhaleBalance = await web3.eth.getBalance(constants.ETH_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') {
- await web3.eth.sendTransaction({
- from: address,
- to: constants.ETH_WHALE_ADDRESS,
- value: web3.utils.toWei('.2', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
- console.log(' ✓ Eth Whale can receive eth if needed')
- }
-
- if (saiWhaleBalance === '0') {
- await web3.eth.sendTransaction({
- from: address,
- to: constants.SAI_WHALE_ADDRESS,
- value: web3.utils.toWei('.1', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
- console.log(' ✓ Sai Whale can receive eth if needed')
- }
-
- if (usdcWhaleBalance === '0') {
- await web3.eth.sendTransaction({
- from: address,
- to: constants.USDC_WHALE_ADDRESS,
- value: web3.utils.toWei('.1', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
- console.log(' ✓ USDC Whale can receive eth if needed')
- }
-
- await web3.eth.sendTransaction({
- from: constants.ETH_WHALE_ADDRESS,
- to: targetWalletAddress,
- value: web3.utils.toWei('.1', 'ether'),
- gas: (testingContext !== 'coverage') ? '0x5208' : gasLimit - 1,
- gasPrice: 1
- })
- console.log(' ✓ Eth Whale can deposit eth into the yet-to-be-deployed smart wallet')
-
- await runTest(
- 'Sai Whale can deposit sai into the yet-to-be-deployed 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(
- 'USDC Whale can deposit usdc into the yet-to-be-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(
- 'DharmaSmartWalletFactoryV1 cannot deploy a new smart wallet with no key',
- DharmaSmartWalletFactoryV1,
- 'newSmartWallet',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- 'DharmaSmartWalletFactoryV1 can deploy a new smart wallet using a Dharma Key',
- DharmaSmartWalletFactoryV1,
- 'newSmartWallet',
- 'send',
- [address],
- 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]]
- if (typeof log === 'undefined') {
- console.log(value)
- }
- 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, 'Smart Wallet')
- assert.strictEqual(events[0].eventName, 'NewUserSigningKey')
- assert.strictEqual(events[0].returnValues.userSigningKey, address)
-
- 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, 'CSAI')
- assert.strictEqual(events[2].eventName, 'AccrueInterest')
-
- 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, 'CSAI')
- assert.strictEqual(events[4].eventName, 'Mint')
- assert.strictEqual(events[4].returnValues.mintTokens, web3.utils.toWei('100', 'ether'))
-
- assert.strictEqual(events[5].address, 'CSAI')
- assert.strictEqual(events[5].eventName, 'Transfer')
-
- assert.strictEqual(events[6].address, 'USDC')
- assert.strictEqual(events[6].eventName, 'Approval')
- assert.strictEqual(events[6].returnValues.value, constants.FULL_APPROVAL)
-
- assert.strictEqual(events[7].address, 'CUSDC')
- assert.strictEqual(events[7].eventName, 'AccrueInterest')
-
- assert.strictEqual(events[8].address, 'USDC')
- assert.strictEqual(events[8].eventName, 'Transfer')
- assert.strictEqual(events[8].returnValues.value, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[9].address, 'CUSDC')
- assert.strictEqual(events[9].eventName, 'Mint')
- assert.strictEqual(events[9].returnValues.mintTokens, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[10].address, 'CUSDC')
- assert.strictEqual(events[10].eventName, 'Transfer')
- }
- }
- )
-
- const UserSmartWallet = new web3.eth.Contract(
- DharmaSmartWalletImplementationV0Artifact.abi,
- targetWalletAddress
- )
-
- const UserSmartWalletV5 = new web3.eth.Contract(
- DharmaSmartWalletImplementationV5Artifact.abi,
- targetWalletAddress
- )
-
- const UserSmartWalletV6 = new web3.eth.Contract(
- DharmaSmartWalletImplementationV6Artifact.abi,
- targetWalletAddress
- )
-
- await runTest(
- 'DharmaSmartWalletFactoryV1 gets a new smart wallet address with same key',
- DharmaSmartWalletFactoryV1,
- 'getNextSmartWallet',
- 'call',
- [address],
- true,
- value => {
- // TODO: verify against expected value
- assert.ok(targetWalletAddress !== value)
- }
- )
-
- await web3.eth.sendTransaction({
- from: constants.ETH_WHALE_ADDRESS,
- to: targetWalletAddress,
- value: web3.utils.toWei('100', 'ether'),
- gas: (testingContext !== 'coverage') ? '0xffff' : gasLimit - 1,
- gasPrice: 1
- }).catch(error => {
- console.log(' ✓ Eth Whale can no longer deposit eth into the deployed smart wallet')
- })
-
- await runTest(
- 'Sai Whale can deposit sai into the deployed 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(
- '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',
- UserSmartWallet,
- '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, 'CSAI')
- assert.strictEqual(events[0].eventName, 'AccrueInterest')
-
- 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, 'CSAI')
- assert.strictEqual(events[2].eventName, 'Mint')
- assert.strictEqual(events[2].returnValues.mintTokens, web3.utils.toWei('100', 'ether'))
-
- assert.strictEqual(events[3].address, 'CSAI')
- assert.strictEqual(events[3].eventName, 'Transfer')
-
- assert.strictEqual(events[4].address, 'CUSDC')
- assert.strictEqual(events[4].eventName, 'AccrueInterest')
-
- assert.strictEqual(events[5].address, 'USDC')
- assert.strictEqual(events[5].eventName, 'Transfer')
- assert.strictEqual(events[5].returnValues.value, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[6].address, 'CUSDC')
- assert.strictEqual(events[6].eventName, 'Mint')
- assert.strictEqual(events[6].returnValues.mintTokens, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[7].address, 'CUSDC')
- assert.strictEqual(events[7].eventName, 'Transfer')
- }
- }
- )
-
- await runTest(
- 'new user smart wallet can trigger repayAndDeposit even with no funds',
- UserSmartWallet,
- '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(
- 'test passes',
- UserSmartWallet,
- 'test',
- 'call',
- [],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- // TODO: wrap in a contract to validate revert reason
- await runTest(
- 'revert test with revert reason passes',
- UserSmartWallet,
- 'testRevert',
- 'call',
- [],
- false // set this to true to verify that the revert reason is displayed
- )
-
- await runTest(
- 'new user smart wallet can be called and has the correct dharma key set',
- UserSmartWallet,
- 'getUserSigningKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'UserSmartWallet can get the version (0)',
- UserSmartWallet,
- 'getVersion',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- 'UserSmartWallet nonce is initially set to 0',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- 'UserSmartWallet can get balances',
- UserSmartWallet,
- 'getBalances',
- 'call',
- [],
- true,
- value => {
- //console.log(value)
- }
- )
-
- await runTest(
- 'UserSmartWallet secondary can call to withdraw sai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- '1000000000000000000',
- address,
- 0,
- '0x',
- '0x'
- ],
- true,
- receipt => {
- // TODO: verify logs
- if (testingContext !== 'coverage') {
- //console.log(receipt.events)
- }
- //console.log(receipt.events.ExternalError.returnValues)
- //console.log(receipt.events.ExternalError)
- /*
- console.log(Object.values(receipt.events).map(value => {
- return (
- value.raw
- )
- }))
- */
- }
- )
-
- await runTest(
- 'UserSmartWallet nonce is now set to 1',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
-
- await runTest(
- 'UserSmartWallet secondary can call to withdraw usdc',
- UserSmartWallet,
- 'withdrawUSDC',
- 'send',
- [
- 1,
- address,
- 0,
- '0x',
- '0x'
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- }
- )
-
- await runTest(
- 'UserSmartWallet nonce is now set to 2',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '2')
- }
- )
-
- await runTest(
- 'UserSmartWallet secondary can call to cancel',
- UserSmartWallet,
- 'cancel',
- 'send',
- [
- 0,
- '0x'
- ]
- )
-
- await runTest(
- 'UserSmartWallet nonce is now set to 3',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '3')
- }
- )
-
- await runTest(
- 'UserSmartWallet secondary can call to set userSigningKey',
- UserSmartWallet,
- 'setUserSigningKey',
- 'send',
- [
- address,
- 0,
- '0x',
- '0x'
- ]
- )
-
- await runTest(
- 'UserSmartWallet nonce is now set to 4',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '4')
- }
- )
-
- let customActionId
- await runTest(
- 'UserSmartWallet can get next custom action ID',
- UserSmartWallet,
- 'getNextCustomActionID',
- 'call',
- [
- 4, // SAIWithdrawal,
- constants.FULL_APPROVAL,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- await runTest(
- 'UserSmartWallet can get custom action ID 4 and it matches next action ID',
- UserSmartWallet,
- 'getCustomActionID',
- 'call',
- [
- 4, // SAIWithdrawal,
- constants.FULL_APPROVAL,
- address,
- 4,
- 0
- ],
- true,
- value => {
- assert.strictEqual(value, customActionId)
- }
- )
-
- await runTest(
- 'UserSmartWallet can get a USDC withdrawal custom action ID',
- UserSmartWallet,
- 'getNextCustomActionID',
- 'call',
- [
- 5, // USDCWithdrawal,
- constants.FULL_APPROVAL,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- let usdcWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- await runTest(
- 'UserSmartWallet relay cannot call with bad signature to withdraw USDC',
- UserSmartWallet,
- 'withdrawUSDC',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- '0x',
- '0xffffffff' + usdcWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'UserSmartWallet relay can call with signature to withdraw USDC',
- UserSmartWallet,
- 'withdrawUSDC',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- '0x',
- usdcWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt.events)
- },
- 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(
- 'UserSmartWallet cannot withdraw too much sai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- '100000000000000000000000000000000000000',
- address,
- 0,
- '0x',
- '0x'
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- //console.log(receipt.events)
- }
- // TODO: verify logs
- //console.log(receipt.events.ExternalError.returnValues)
- //console.log(receipt.events.ExternalError)
- /*
- console.log(Object.values(receipt.events).map(value => {
- return (
- value.raw
- )
- }))
- */
- }
- )
-
- await runTest(
- 'UserSmartWallet cannot withdraw too much usdc',
- UserSmartWallet,
- 'withdrawUSDC',
- 'send',
- [
- '100000000000000000000000000000000',
- address,
- 0,
- '0x',
- '0x'
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- //console.log(receipt.events)
- }
- // TODO: verify logs
- //console.log(receipt.events.ExternalError.returnValues)
- //console.log(receipt.events.ExternalError)
- /*
- console.log(Object.values(receipt.events).map(value => {
- return (
- value.raw
- )
- }))
- */
- }
- )
-
- await runTest(
- 'UserSmartWallet cannot withdraw too little sai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- '1',
- address,
- 0,
- '0x',
- '0x'
- ],
- true,
- receipt => {
- //console.log(receipt.events.ExternalError)
- // TODO: verify logs
- //console.log(receipt.events.ExternalError.returnValues)
- //console.log(receipt.events.ExternalError)
- /*
- console.log(Object.values(receipt.events).map(value => {
- return (
- value.raw
- )
- }))
- */
- }
- )
-
- await runTest(
- 'UserSmartWallet can get a Sai withdrawal custom action ID',
- UserSmartWallet,
- 'getNextCustomActionID',
- 'call',
- [
- 10, // SaiWithdrawal,
- constants.FULL_APPROVAL,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- let saiWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- await runTest(
- 'UserSmartWallet relay cannot call with bad signature to withdraw sai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- '0x',
- '0xffffffff' + saiWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'UserSmartWallet relay can call with signature to withdraw sai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- '0x',
- saiWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'UserSmartWallet calls revert if insufficient action gas is supplied',
- UserSmartWallet,
- 'cancel',
- 'send',
- [
- constants.FULL_APPROVAL,
- '0x'
- ],
- false
- )
-
- await runTest(
- 'UserSmartWallet calls succeed if sufficient non-zero action gas supplied',
- UserSmartWallet,
- 'cancel',
- 'send',
- [
- '1',
- '0x'
- ]
- )
-
- await runTest(
- 'UserSmartWallet calls to atomic methods revert',
- UserSmartWallet,
- '_withdrawDaiAtomic',
- 'send',
- [
- '1',
- address
- ],
- false
- )
-
- let originalNonce
- await runTest(
- 'UserSmartWallet can get the nonce prior to upgrade',
- UserSmartWallet,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- originalNonce = value
- }
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can upgrade to V1 implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV1.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- DharmaSmartWalletImplementationV0.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- */
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaSmartWalletImplementationV1.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementationCodeHash,
- ...
- )
- */
- }
- }
- )
-
- const UpgradeBeaconImplementationCheckV1 = await runTest(
- `UpgradeBeaconImplementationCheck deployment`,
- UpgradeBeaconImplementationCheckDeployer,
- '',
- 'deploy',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV1.options.address
- ]
- )
-
- await runTest(
- 'DharmaUpgradeBeacon has the implementation set',
- DharmaUpgradeBeaconController,
- 'getImplementation',
- 'call',
- [DharmaUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaSmartWalletImplementationV1.options.address)
- }
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can upgrade to V2 implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV2.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- DharmaSmartWalletImplementationV1.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- */
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaSmartWalletImplementationV2.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementationCodeHash,
- ...
- )
- */
- }
- }
- )
-
- const UpgradeBeaconImplementationCheckV2 = await runTest(
- `UpgradeBeaconImplementationCheck deployment`,
- UpgradeBeaconImplementationCheckDeployer,
- '',
- 'deploy',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV2.options.address
- ]
- )
-
- await runTest(
- 'DharmaUpgradeBeacon has the implementation set',
- DharmaUpgradeBeaconController,
- 'getImplementation',
- 'call',
- [DharmaUpgradeBeacon.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaSmartWalletImplementationV2.options.address)
- }
- )
-
- await runTest(
- 'V2 user smart wallet can be called and still has original dharma key set',
- UserSmartWallet,
- 'getUserSigningKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'V2 UserSmartWallet can get the new version (2)',
- UserSmartWallet,
- 'getVersion',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '2')
- }
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can upgrade to V5 implementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV5.options.address
- ],
- true,
- receipt => {
- if (testingContext !== 'coverage') {
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.upgradeBeacon,
- DharmaUpgradeBeacon.options.address
- )
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementation,
- DharmaSmartWalletImplementationV2.options.address
- )
- /* TODO
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.oldImplementationCodeHash,
- constants.EMPTY_HASH
- )
- */
- assert.strictEqual(
- receipt.events.Upgraded.returnValues.newImplementation,
- DharmaSmartWalletImplementationV5.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, DharmaSmartWalletImplementationV5.options.address)
- }
- )
-
- const UpgradeBeaconImplementationCheckV5 = await runTest(
- `UpgradeBeaconImplementationCheck deployment`,
- UpgradeBeaconImplementationCheckDeployer,
- '',
- 'deploy',
- [
- DharmaUpgradeBeacon.options.address,
- DharmaSmartWalletImplementationV5.options.address
- ]
- )
-
- await runTest(
- 'V5 user smart wallet can be called and still has original dharma key set',
- UserSmartWalletV5,
- 'getUserSigningKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get the new version (5)',
- UserSmartWalletV5,
- 'getVersion',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '5')
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet nonce is still set to value from before upgrade',
- UserSmartWalletV5,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, originalNonce)
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get balances',
- UserSmartWalletV5,
- 'getBalances',
- 'call',
- [],
- true,
- value => {
- //console.log(value)
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary can call to cancel',
- UserSmartWalletV5,
- 'cancel',
- 'send',
- [
- 0,
- '0x'
- ]
- )
-
- await runTest(
- 'V5 UserSmartWallet nonce is now set to original + 1',
- UserSmartWalletV5,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, (parseInt(originalNonce) + 1).toString())
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get next custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 4, // SAIWithdrawal,
- constants.FULL_APPROVAL,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get custom action ID and it matches next action ID',
- UserSmartWalletV5,
- 'getCustomActionID',
- 'call',
- [
- 4, // SAIWithdrawal,
- constants.FULL_APPROVAL,
- address,
- parseInt(originalNonce) + 1,
- 0
- ],
- true,
- value => {
- assert.strictEqual(value, customActionId)
- }
- )
-
- let genericActionID
- await runTest(
- 'V5 UserSmartWallet can get next generic action ID',
- UserSmartWalletV5,
- 'getNextGenericActionID',
- 'call',
- [
- address,
- '0x',
- 0
- ],
- true,
- value => {
- genericActionID = value
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get generic action ID and it matches next action ID',
- UserSmartWalletV5,
- 'getGenericActionID',
- 'call',
- [
- address,
- '0x',
- parseInt(originalNonce) + 1,
- 0
- ],
- true,
- value => {
- assert.strictEqual(value, genericActionID)
- }
- )
-
- await runTest(
- 'UserSmartWallet calls to atomic methods revert',
- UserSmartWalletV5,
- '_withdrawSaiAtomic',
- 'send',
- [
- '1',
- address
- ],
- false
- )
-
- await runTest(
- 'Sai Whale can deposit sai into the V5 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(
- 'USDC Whale can deposit usdc into the V5 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(
- 'V5 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, 'CSAI')
- assert.strictEqual(events[0].eventName, 'AccrueInterest')
-
- 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, 'CSAI')
- assert.strictEqual(events[2].eventName, 'Mint')
- //assert.strictEqual(events[2].returnValues.mintTokens, web3.utils.toWei('100', 'ether'))
-
-
- assert.strictEqual(events[3].address, 'CSAI')
- assert.strictEqual(events[3].eventName, 'Transfer')
-
- assert.strictEqual(events[4].address, 'CUSDC')
- assert.strictEqual(events[4].eventName, 'AccrueInterest')
-
- assert.strictEqual(events[5].address, 'USDC')
- assert.strictEqual(events[5].eventName, 'Transfer')
- //assert.strictEqual(events[5].returnValues.value, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[6].address, 'CUSDC')
- assert.strictEqual(events[6].eventName, 'Mint')
- //assert.strictEqual(events[6].returnValues.mintTokens, web3.utils.toWei('100', 'lovelace'))
-
- assert.strictEqual(events[7].address, 'CUSDC')
- assert.strictEqual(events[7].eventName, 'Transfer')
- }
- }
- )
-
- await runTest(
- 'Sai Whale can deposit sai into the V5 smart wallet again',
- 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 get a generic action ID',
- UserSmartWalletV5,
- 'getNextGenericActionID',
- 'call',
- [
- constants.ESCAPE_HATCH_REGISTRY_ADDRESS,
- '0x',
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- let executeActionSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- let executeActionUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet cannot call executeAction and target Escape Hatch Registry',
- UserSmartWalletV5,
- 'executeAction',
- 'send',
- [
- constants.ESCAPE_HATCH_REGISTRY_ADDRESS,
- '0x',
- 0,
- executeActionUserSignature,
- executeActionSignature
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a generic action ID',
- UserSmartWalletV5,
- 'getNextGenericActionID',
- 'call',
- [
- SAI.options.address,
- SAI.methods.approve(CSAI.options.address, 0).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.approve(CSAI.options.address, 0).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ]
- )
-
- await runTest(
- 'V5 user smart wallet repayAndDeposit cannot deposit without approval',
- 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
- })
- })
-
- // TODO: verify
- }
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a generic action ID',
- UserSmartWalletV5,
- 'getNextGenericActionID',
- 'call',
- [
- SAI.options.address,
- SAI.methods.approve(CSAI.options.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.approve(CSAI.options.address, constants.FULL_APPROVAL).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ]
- )
-
- await runTest(
- 'V5 user smart wallet repayAndDeposit can deposit with approval added back',
- 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
- })
- })
-
- // TODO: verify
- }
- }
- )
-
- await runTest(
- 'V5 user smart wallet can trigger repayAndDeposit even with no 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.length, 0)
- }
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary cannot set an empty user userSigningKey',
- UserSmartWalletV5,
- 'setUserSigningKey',
- 'send',
- [
- constants.NULL_ADDRESS,
- 0,
- '0x',
- '0x'
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary can set a custom user userSigningKey',
- UserSmartWalletV5,
- 'setUserSigningKey',
- 'send',
- [
- addressTwo,
- 0,
- '0x',
- '0x'
- ]
- )
-
- await runTest(
- 'V5 UserSmartWallet can get next custom action ID to set a user signing key',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 1, // SetUserSigningKey,
- constants.FULL_APPROVAL, // This value shouldn't matter
- addressTwo,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- let currentNonce
- await runTest(
- 'UserSmartWallet can get the nonce',
- UserSmartWalletV5,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- currentNonce = value
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get custom action ID and it matches next action ID',
- UserSmartWalletV5,
- 'getCustomActionID',
- 'call',
- [
- 1, // SetUserSigningKey,
- 0, // Note that this value differs from above
- addressTwo,
- currentNonce,
- 0
- ],
- true,
- value => {
- assert.strictEqual(value, customActionId)
- }
- )
-
- let setUserSigningKeyUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- let setUserSigningKeyDharmaSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- await runTest(
- 'V5 UserSmartWallet can set a new user signing key with signatures',
- UserSmartWalletV5,
- 'setUserSigningKey',
- 'send',
- [
- addressTwo,
- 0,
- setUserSigningKeyUserSignature,
- setUserSigningKeyDharmaSignature
- ],
- true,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet can get next custom action ID to cancel',
- UserSmartWalletV5,
- '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',
- UserSmartWalletV5,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- currentNonce = value
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet can get custom action ID and it matches next action ID',
- UserSmartWalletV5,
- 'getCustomActionID',
- 'call',
- [
- 0, // Cancel
- 0, // Note that this value differs from above
- addressTwo, // This one too
- currentNonce,
- 0
- ],
- true,
- value => {
- assert.strictEqual(value, customActionId)
- }
- )
-
- let cancelUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary can cancel using a signature',
- UserSmartWalletV5,
- 'cancel',
- 'send',
- [
- 0,
- cancelUserSignature
- ],
- true,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'UserSmartWallet nonce is incremented after cancelling',
- UserSmartWalletV5,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(parseInt(value), parseInt(currentNonce) + 1)
- }
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary cannot call to withdraw sai without primary',
- UserSmartWalletV5,
- 'withdrawSai',
- 'send',
- [
- '1000000000000000000',
- address,
- 0,
- '0x',
- '0x'
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary cannot call to withdraw usdc without primary',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- 1,
- address,
- 0,
- '0x',
- '0x'
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet secondary can no longer call to set userSigningKey without primary',
- UserSmartWalletV5,
- 'setUserSigningKey',
- 'send',
- [
- address,
- 0,
- '0x',
- '0x'
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a USDC withdrawal custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 5, // USDCWithdrawal,
- '1', // dust
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- usdcWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- let usdcUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet relay cannot withdraw "dust" USDC',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- '1',
- address,
- 0,
- usdcUserWithdrawalSignature,
- usdcWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a USDC withdrawal custom action ID',
- UserSmartWalletV5,
- '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(
- 'V5 UserSmartWallet relay cannot withdraw USDC to null address',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- '100000',
- constants.NULL_ADDRESS,
- 0,
- usdcUserWithdrawalSignature,
- usdcWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a USDC withdrawal custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 5, // USDCWithdrawal,
- '100000',
- 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',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- '100000',
- address,
- 0,
- usdcUserWithdrawalSignature,
- usdcWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- 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 relay cannot call with bad signature to withdraw USDC',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- usdcUserWithdrawalSignature,
- '0xffffffff' + usdcWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet cannot call with bad user signature to withdraw USDC',
- UserSmartWalletV5,
- 'withdrawUSDC',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- '0xffffffff' + usdcUserWithdrawalSignature.slice(10),
- usdcWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet relay can call with two signatures to withdraw max USDC',
- UserSmartWalletV5,
- '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(
- 'V5 UserSmartWallet can get a Sai withdrawal custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 4, // SaiWithdrawal,
- '1',
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- saiWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- let saiUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet relay cannot withdraw "dust" sai',
- UserSmartWalletV5,
- 'withdrawDai',
- 'send',
- [
- '1',
- address,
- 0,
- saiUserWithdrawalSignature,
- saiWithdrawalSignature
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a Sai withdrawal custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 4, // SaiWithdrawal,
- '1000000000000000',
- constants.NULL_ADDRESS,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- saiWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- saiUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet relay cannot withdraw sai to null address',
- UserSmartWalletV5,
- 'withdrawDai',
- 'send',
- [
- '1000000000000000',
- constants.NULL_ADDRESS,
- 0,
- saiUserWithdrawalSignature,
- saiWithdrawalSignature
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet can get a Sai withdrawal custom action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 4, // SaiWithdrawal,
- '1000000000000000',
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- saiWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- saiUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V5 UserSmartWallet relay can call with signature to withdraw sai',
- UserSmartWalletV5,
- 'withdrawDai',
- 'send',
- [
- '1000000000000000',
- address,
- 0,
- saiUserWithdrawalSignature,
- saiWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt.events)
- },
- originalAddress
- )
-
- await runTest(
- 'V5 UserSmartWallet cannot get a non-custom "custom" next action ID',
- UserSmartWalletV5,
- 'getNextCustomActionID',
- 'call',
- [
- 2, // Generic,
- constants.FULL_APPROVAL,
- address,
- 0
- ],
- false
- )
-
- await runTest(
- 'V5 UserSmartWallet cannot get a non-custom "custom" action ID',
- UserSmartWalletV5,
- 'getCustomActionID',
- 'call',
- [
- 2, // Generic,
- constants.FULL_APPROVAL,
- address,
- 0,
- 0
- ],
- false
- )
-
- 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 call with bad signature to withdraw sai',
- UserSmartWalletV5,
- 'withdrawDai',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- saiUserWithdrawalSignature,
- '0xffffffff' + saiWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- '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.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,
- '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(
- '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,
- '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 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,
- '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 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,
- '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' + daiUserWithdrawalSignature.slice(10),
- daiWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can call with signature to withdraw sai',
- UserSmartWalletV6,
- 'withdrawDai',
- 'send',
- [
- constants.FULL_APPROVAL,
- address,
- 0,
- daiUserWithdrawalSignature,
- daiWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a Ether withdrawal custom action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 6, // ETHWithdrawal,
- '0', // no amount
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- ethWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- ethUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot to withdraw ether with no amount',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '0',
- address,
- 0,
- ethUserWithdrawalSignature,
- ethWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a Ether withdrawal custom action ID',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet relay cannot to withdraw ether with no recipient',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- constants.NULL_ADDRESS,
- 0,
- ethUserWithdrawalSignature,
- ethWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a Ether withdrawal custom action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 6, // ETHWithdrawal,
- '1',
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- ethWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- ethUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot call with bad signature to withdraw eth',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- ethUserWithdrawalSignature,
- '0xffffffff' + ethWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- '0xffffffff' + ethUserWithdrawalSignature.slice(10),
- ethWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can call with signature to withdraw ether',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- ethUserWithdrawalSignature,
- ethWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a Ether withdrawal custom action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 6, // ETHWithdrawal,
- '1',
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- ethWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- ethUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot call with bad signature to withdraw eth',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- ethUserWithdrawalSignature,
- '0xffffffff' + ethWithdrawalSignature.slice(10)
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- '0xffffffff' + ethUserWithdrawalSignature.slice(10),
- ethWithdrawalSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can call with signature to withdraw ether',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- address,
- 0,
- ethUserWithdrawalSignature,
- ethWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet cancel reverts with bad signature',
- UserSmartWalletV6,
- 'cancel',
- 'send',
- [
- 0,
- '0x'
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet calls revert if insufficient action gas is supplied',
- UserSmartWalletV6,
- 'cancel',
- 'send',
- [
- constants.FULL_APPROVAL,
- '0x'
- ],
- false
- )
-
- await runTest(
- 'V6 UserSmartWallet calls succeed if sufficient non-zero action gas supplied',
- UserSmartWalletV6,
- 'cancel',
- 'send',
- [
- '1',
- '0x'
- ]
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a cancel custom action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 0, // Cancel,
- '0',
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- cancelSignature = signHashedPrefixedHexString(customActionId, addressTwo)
-
- await runTest(
- 'V6 UserSmartWallet can cancel using a signature',
- UserSmartWalletV6,
- 'cancel',
- 'send',
- [
- '0',
- cancelSignature
- ],
- true,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet calls to atomic methods revert',
- UserSmartWalletV6,
- '_withdrawDaiAtomic',
- 'send',
- [
- '1',
- address
- ],
- false
- )
-
- await runTest(
- 'V6 UserSmartWallet calls to recover from random address revert',
- UserSmartWalletV6,
- 'recover',
- 'send',
- [
- address
- ],
- false
- )
-
- await runTest(
- 'DharmaSmartWalletFactoryV1 can deploy a V6 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(
- 'V6 UserSmartWallet can get a generic action ID',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet cannot call executeAction and target a non-contract',
- UserSmartWalletV6,
- 'executeAction',
- 'send',
- [
- address,
- USDC.methods.approve(CUSDC.options.address, 0).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ],
- false
- )
-
- await runTest(
- 'V6 UserSmartWallet cannot call executeAction and target itself',
- UserSmartWalletV6,
- 'executeAction',
- 'send',
- [
- UserSmartWalletV6.options.address,
- USDC.methods.approve(CUSDC.options.address, 0).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ],
- false
- )
-
- await runTest(
- 'V6 UserSmartWallet can call executeAction',
- UserSmartWalletV6,
- 'executeAction',
- 'send',
- [
- USDC.options.address,
- USDC.methods.approve(CUSDC.options.address, 0).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ]
- )
-
- await runTest(
- 'V6 UserSmartWallet can get the next generic batch action ID',
- UserSmartWalletV6,
- 'getNextGenericAtomicBatchActionID',
- 'call',
- [
- [{to: SAI.options.address, data: SAI.methods.totalSupply().encodeABI()}],
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- await runTest(
- 'UserSmartWallet can get the nonce',
- UserSmartWalletV6,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- currentNonce = value
- }
- )
-
- await runTest(
- 'V6 UserSmartWallet generic batch action ID with nonce matches next ID',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet can call executeActionWithAtomicBatchCalls',
- UserSmartWalletV6,
- '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',
- 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, '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')
- }
- }
- )
-
- await runTest(
- 'Check blacklister address',
- FIAT_TOKEN,
- 'blacklister',
- 'call',
- [],
- true,
- value => {
- blacklister = value
- }
- )
-
- 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
- )
-
- 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 BlacklistedUserSmartWalletV6 = new web3.eth.Contract(
- DharmaSmartWalletImplementationV6Artifact.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',
- BlacklistedUserSmartWalletV6,
- '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(
- '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 attempt to withdraw max USDC when paused causes ExternalError',
- UserSmartWalletV6,
- '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',
- BlacklistedUserSmartWalletV6,
- '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',
- BlacklistedUserSmartWalletV6,
- 'repayAndDeposit',
- 'send',
- [],
- true,
- receipt => {
- // TODO: verify
- //console.log(receipt.events)
- }
- )
-
- await runTest(
- 'V6 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(
- 'V6 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(
- 'V6 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(
- 'V6 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(
- 'V6 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(
- 'V6 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(
- 'V6 UserSmartWallet can get a Ether withdrawal custom action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 6, // ETHWithdrawal,
- '1',
- targetWalletAddress,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- ethWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- ethUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot withdraw eth to a non-payable account',
- UserSmartWalletV6,
- 'withdrawEther',
- 'send',
- [
- '1',
- targetWalletAddress,
- 0,
- ethUserWithdrawalSignature,
- ethWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt)
- },
- originalAddress
- )
-
- 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 V6 smart wallet using a contract key',
- DharmaSmartWalletFactoryV1,
- 'newSmartWallet',
- 'send',
- [targetWalletAddress]
- )
-
- const UserSmartWalletV6Two = new web3.eth.Contract(
- DharmaSmartWalletImplementationV6Artifact.abi,
- targetWalletAddressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet cancel reverts with bad contract signature',
- UserSmartWalletV6Two,
- 'cancel',
- 'send',
- [
- 0,
- '0x'
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a generic action ID',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet can call executeAction',
- UserSmartWalletV6,
- 'executeAction',
- 'send',
- [
- SAI.options.address,
- SAI.methods.transfer(address, constants.FULL_APPROVAL).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ]
- )
-
- 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,
- 'getNextCustomActionID',
- 'call',
- [
- 10, // DaiWithdrawal
- '100000000000000000000000000000000000000', // too much
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- daiWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- daiUserWithdrawalSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot withdraw too much dai',
- UserSmartWallet,
- 'withdrawDai',
- 'send',
- [
- '100000000000000000000000000000000000000', // too much
- address,
- 0,
- daiUserWithdrawalSignature,
- daiWithdrawalSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- //console.log(receipt.events)
- },
- originalAddress
- )
-
- await runTest(
- 'V6 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(
- 'V6 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(
- 'V6 UserSmartWallet can get next generic batch action ID',
- UserSmartWalletV6,
- 'getNextGenericAtomicBatchActionID',
- 'call',
- [
- [{
- to: DAI.options.address,
- data: DAI.methods.transfer(
- address, '100000000000000000000000000000'
- ).encodeABI()
- }],
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- executeActionSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- executeActionUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure',
- UserSmartWalletV6,
- 'executeActionWithAtomicBatchCalls',
- 'send',
- [
- [{
- to: DAI.options.address,
- data: DAI.methods.transfer(
- address, '100000000000000000000000000000'
- ).encodeABI()
- }],
- 0,
- executeActionUserSignature,
- executeActionSignature
- ],
- true,
- receipt => {
- //console.log(receipt)
- }
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a generic action ID',
- UserSmartWalletV6,
- 'getNextGenericActionID',
- 'call',
- [
- Comptroller.options.address,
- Comptroller.methods.enterMarkets(
- [constants.CDAI_MAINNET_ADDRESS]
- ).encodeABI(),
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- executeActionSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- executeActionUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet can call executeAction to enter dai market',
- UserSmartWalletV6,
- 'executeAction',
- 'send',
- [
- Comptroller.options.address,
- Comptroller.methods.enterMarkets(
- [constants.CDAI_MAINNET_ADDRESS]
- ).encodeABI(),
- 0,
- executeActionUserSignature,
- executeActionSignature
- ]
- )
-
- await runTest(
- 'Dai Whale can deposit dai into the 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 trigger repayAndDeposit to deposit all new funds',
- UserSmartWalletV6,
- 'repayAndDeposit'
- )
-
- await runTest(
- 'V6 UserSmartWallet can get a generic action ID',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet can call executeAction to perform a borrow',
- UserSmartWalletV6,
- '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(
- 'V6 UserSmartWallet can get an escape hatch action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 7, // SetEscapeHatch,
- 0,
- constants.NULL_ADDRESS, // no recipient
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- let escapeHatchSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- let escapeHatchUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot set an escape hatch with no account',
- UserSmartWalletV6,
- 'setEscapeHatch',
- 'send',
- [
- constants.NULL_ADDRESS,
- 0,
- escapeHatchUserSignature,
- escapeHatchSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get an escape hatch action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 7, // SetEscapeHatch,
- 0,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- escapeHatchSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- escapeHatchUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet cannot call escape before escape hatch is set',
- UserSmartWalletV6,
- 'escape',
- 'send',
- [],
- false,
- receipt => {
- // TODO: verify logs
- }
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can set an escape hatch',
- UserSmartWalletV6,
- 'setEscapeHatch',
- 'send',
- [
- address,
- 0,
- escapeHatchUserSignature,
- escapeHatchSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet non-escape hatch account cannot call escape',
- UserSmartWalletV6,
- 'escape',
- 'send',
- [],
- false,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet escape hatch account can call escape',
- UserSmartWalletV6,
- 'escape',
- 'send',
- [],
- true,
- receipt => {
- // TODO: verify logs
- },
- address
- )
-
- await runTest(
- 'V6 UserSmartWallet escape hatch account can call escape again',
- UserSmartWalletV6,
- 'escape',
- 'send',
- [],
- true,
- receipt => {
- // TODO: verify logs
- },
- address
- )
-
- await runTest(
- 'V6 UserSmartWallet can get an escape hatch action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 8, // RemoveEscapeHatch,
- 0,
- constants.NULL_ADDRESS,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- escapeHatchSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- escapeHatchUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can remove an escape hatch',
- UserSmartWalletV6,
- 'removeEscapeHatch',
- 'send',
- [
- 0,
- escapeHatchUserSignature,
- escapeHatchSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet cannot call escape once escape hatch is removed',
- UserSmartWalletV6,
- 'escape',
- 'send',
- [],
- false,
- receipt => {
- // TODO: verify logs
- }
- )
-
- await runTest(
- 'V6 UserSmartWallet can get an escape hatch action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 9, // DisableEscapeHatch,
- 0,
- constants.NULL_ADDRESS,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- escapeHatchSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- escapeHatchUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay can disable the escape hatch',
- UserSmartWalletV6,
- 'permanentlyDisableEscapeHatch',
- 'send',
- [
- 0,
- escapeHatchUserSignature,
- escapeHatchSignature
- ],
- true,
- receipt => {
- // TODO: verify logs
- },
- originalAddress
- )
-
- await runTest(
- 'V6 UserSmartWallet can get an escape hatch action ID',
- UserSmartWalletV6,
- 'getNextCustomActionID',
- 'call',
- [
- 7, // SetEscapeHatch,
- 0,
- address,
- 0
- ],
- true,
- value => {
- customActionId = value
- }
- )
-
- escapeHatchSignature = signHashedPrefixedHexString(
- customActionId,
- address
- )
-
- escapeHatchUserSignature = signHashedPrefixedHexString(
- customActionId,
- addressTwo
- )
-
- await runTest(
- 'V6 UserSmartWallet relay cannot set an escape hatch once disabled',
- UserSmartWalletV6,
- 'setEscapeHatch',
- 'send',
- [
- address,
- 0,
- escapeHatchUserSignature,
- escapeHatchSignature
- ],
- false,
- receipt => {
- // TODO: verify logs
- },
- 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('0.5', '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,
- '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',
- DharmaAccountRecoveryManagerV2,
- 'initiateAccountRecovery',
- 'send',
- [
- UserSmartWalletV6.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',
- [
- UserSmartWalletV6.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',
- [
- UserSmartWalletV6.options.address,
- originalAddress
- ],
- true,
- receipt => {
- // TODO: verify
- //console.log(receipt.events)
- }
- )
-
- // COVERAGE TESTING - deployments
- const DharmaUpgradeBeaconControllerManagerCoverage = await runTest(
- `DharmaUpgradeBeaconControllerManager contract deployment`,
- DharmaUpgradeBeaconControllerManagerDeployer,
- '',
- 'deploy'
- )
-
- const DharmaUpgradeBeaconControllerCoverage = await runTest(
- `DharmaUpgradeBeaconController contract deployment`,
- DharmaUpgradeBeaconControllerDeployer,
- '',
- 'deploy'
- )
-
- const DharmaAccountRecoveryManagerV2Coverage = await runTest(
- `DharmaAccountRecoveryManagerV2 contract deployment`,
- DharmaAccountRecoveryManagerV2Deployer,
- '',
- 'deploy'
- )
-
- const DharmaKeyRegistryV2Coverage = await runTest(
- `DharmaKeyRegistryV2 contract deployment`,
- DharmaKeyRegistryV2Deployer,
- '',
- 'deploy'
- )
-
- const DharmaUpgradeBeaconCoverage = await runTest(
- `DharmaUpgradeBeacon (smart wallet) contract deployment`,
- DharmaUpgradeBeaconDeployer,
- '',
- 'deploy'
- )
-
- const DharmaKeyRingUpgradeBeaconCoverage = await runTest(
- `DharmaKeyRingUpgradeBeacon contract deployment`,
- DharmaKeyRingUpgradeBeaconDeployer,
- '',
- 'deploy'
- )
-
- const DharmaUpgradeBeaconEnvoy = await runTest(
- `DharmaUpgradeBeaconEnvoy contract deployment`,
- DharmaUpgradeBeaconEnvoyDeployer,
- '',
- 'deploy'
- )
-
- const AdharmaSmartWalletImplementation = await runTest(
- `AdharmaSmartWalletImplementation contract deployment`,
- AdharmaSmartWalletImplementationDeployer,
- '',
- 'deploy'
- )
-
- const AdharmaKeyRingImplementation = await runTest(
- `AdharmaKeyRingImplementation contract deployment`,
- AdharmaKeyRingImplementationDeployer,
- '',
- 'deploy'
- )
-
- const DharmaSmartWalletFactoryV1Coverage = await runTest(
- `DharmaSmartWalletFactoryV1 contract deployment`,
- DharmaSmartWalletFactoryV1Deployer,
- '',
- 'deploy',
- []
- )
-
- const DharmaKeyRingFactoryV1 = await runTest(
- `DharmaKeyRingFactoryV1 contract deployment`,
- DharmaKeyRingFactoryV1Deployer,
- '',
- 'deploy',
- []
- )
-
- const DharmaKeyRingFactoryV2 = await runTest(
- `DharmaKeyRingFactoryV2 contract deployment`,
- DharmaKeyRingFactoryV2Deployer,
- '',
- 'deploy',
- []
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 cannot create a V1 key ring with no key`,
- DharmaKeyRingFactoryV1,
- 'newKeyRing',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 cannot create a V1 key ring and set a new null key`,
- DharmaKeyRingFactoryV1,
- 'newKeyRingAndAdditionalKey',
- 'send',
- [address, constants.NULL_ADDRESS, '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 cannot create a V1 key ring and set a duplicate key`,
- DharmaKeyRingFactoryV1,
- 'newKeyRingAndAdditionalKey',
- 'send',
- [address, address, '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 can get the address of the next key ring`,
- DharmaKeyRingFactoryV1,
- 'getNextKeyRing',
- 'call',
- [address],
- true,
- value => {
- nextKeyRing = value;
- }
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 can create a V1 key ring`,
- DharmaKeyRingFactoryV1,
- 'newKeyRing',
- 'send',
- [address]
- )
-
- const KeyRingInstance = new web3.eth.Contract(
- DharmaKeyRingImplementationV1Artifact.abi,
- nextKeyRing
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 gets new key ring after a deploy with same input`,
- DharmaKeyRingFactoryV1,
- 'getNextKeyRing',
- 'call',
- [address],
- true,
- value => {
- assert.ok(nextKeyRing !== value)
- }
- )
-
- await runTest(
- `KeyRingInstance can get the version of the key ring`,
- KeyRingInstance,
- 'getVersion',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
-
- await runTest(
- `KeyRingInstance can get the nonce of the key ring`,
- KeyRingInstance,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `KeyRingInstance can get the key count of the key ring`,
- KeyRingInstance,
- 'getKeyCount',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value.adminKeyCount, '1')
- assert.strictEqual(value.standardKeyCount, '1')
- }
- )
-
- await runTest(
- `KeyRingInstance can does not verify a bad signature`,
- KeyRingInstance,
- 'isValidSignature',
- 'call',
- [
- web3.eth.abi.encodeParameters(
- ['bytes32', 'uint8', 'bytes'],
- [constants.NULL_BYTES_32, 1, '0x']
- ),
- '0x'
- ],
- false
- )
-
- await runTest(
- `KeyRingInstance can get an adminActionID using getNextAdminActionID`,
- KeyRingInstance,
- 'getNextAdminActionID',
- 'call',
- [1, 1],
- true,
- value => {
- adminActionID = value
- }
- )
-
- await runTest(
- `KeyRingInstance getAdminActionID matches getNextAdminActionID`,
- KeyRingInstance,
- 'getAdminActionID',
- 'call',
- [1, 1, 0],
- true,
- value => {
- assert.strictEqual(value, adminActionID)
- }
- )
-
- await runTest(
- `KeyRingInstance cannot add a non-dual key in V1`,
- KeyRingInstance,
- 'takeAdminAction',
- 'send',
- [1, 1, '0x'],
- false
- )
-
- await runTest(
- `KeyRingInstance cannot add key that already exists`,
- KeyRingInstance,
- 'takeAdminAction',
- 'send',
- [6, address, '0x'],
- false
- )
-
- const takeAdminActionSignature = signHashedPrefixedHexString(
- adminActionID,
- address
- )
-
- await runTest(
- `KeyRingInstance can verify a valid signature`,
- KeyRingInstance,
- 'isValidSignature',
- 'call',
- [
- web3.eth.abi.encodeParameters(
- ['bytes32', 'uint8', 'bytes'],
- [
- web3.utils.keccak256(
- // prefix => "\x19Ethereum Signed Message:\n32"
- "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
- adminActionID.slice(2),
- {encoding: "hex"}
- ), 1, '0x']
- ),
- takeAdminActionSignature
- ],
- true,
- value => {
- assert.strictEqual(value, '0x20c13b0b')
- }
- )
-
- await runTest(
- `KeyRingInstance can add a new key with a valid signature`,
- KeyRingInstance,
- 'takeAdminAction',
- 'send',
- [6, 1, takeAdminActionSignature],
- true
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 cannot create a V1 key ring with no key`,
- DharmaKeyRingFactoryV2,
- 'newKeyRing',
- 'send',
- [constants.NULL_ADDRESS, constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 cannot create a V1 key ring and set a new null key`,
- DharmaKeyRingFactoryV2,
- 'newKeyRingAndAdditionalKey',
- 'send',
- [address, constants.NULL_ADDRESS, constants.NULL_ADDRESS, '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 cannot create a V1 key ring and set a duplicate key`,
- DharmaKeyRingFactoryV2,
- 'newKeyRingAndAdditionalKey',
- 'send',
- [address, constants.NULL_ADDRESS, address, '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 can get the address of the next key ring`,
- DharmaKeyRingFactoryV2,
- 'getNextKeyRing',
- 'call',
- [address],
- true,
- value => {
- nextKeyRing = value;
- }
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 can create a V1 key ring if the target address matches`,
- DharmaKeyRingFactoryV2,
- 'newKeyRing',
- 'send',
- [address, nextKeyRing]
- )
-
- const KeyRingInstanceFromV2Factory = new web3.eth.Contract(
- DharmaKeyRingImplementationV1Artifact.abi,
- nextKeyRing
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 won't deploy a V1 key ring if the target address has one`,
- DharmaKeyRingFactoryV2,
- 'newKeyRing',
- 'send',
- [address, KeyRingInstanceFromV2Factory.options.address]
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 can call getFirstKeyRingAdminActionID`,
- DharmaKeyRingFactoryV2,
- 'getFirstKeyRingAdminActionID',
- 'call',
- [address, address]
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 reverts when no new key ring supplied`,
- DharmaKeyRingFactoryV2,
- 'getNextKeyRing',
- 'call',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 gets new key ring after a deploy with same input`,
- DharmaKeyRingFactoryV2,
- 'getNextKeyRing',
- 'call',
- [address],
- true,
- value => {
- assert.ok(nextKeyRing !== value)
- }
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 can call newKeyRingAndDaiWithdrawal`,
- DharmaKeyRingFactoryV2,
- 'newKeyRingAndDaiWithdrawal',
- 'send',
- [address, address, address, 0, address, 0, '0x', '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV2 can call newKeyRingAndUSDCWithdrawal`,
- DharmaKeyRingFactoryV2,
- 'newKeyRingAndUSDCWithdrawal',
- 'send',
- [address, address, address, 0, address, 0, '0x', '0x'],
- false
- )
-
- await runTest(
- `AdharmaSmartWalletImplementation cannot be initialized directly post-deployment`,
- AdharmaSmartWalletImplementation,
- 'initialize',
- 'send',
- [address],
- false
- )
-
- await runTest(
- `AdharmaSmartWalletImplementation cannot be used to perform calls directly`,
- AdharmaSmartWalletImplementation,
- 'performCall',
- 'send',
- [address, 1, '0x'],
- false
- )
-
- await runTest(
- `AdharmaKeyRingImplementation cannot be initialized directly post-deployment`,
- AdharmaKeyRingImplementation,
- 'initialize',
- 'send',
- [1, 1, [address], [3]],
- false
- )
-
- await runTest(
- `AdharmaKeyRingImplementation cannot be used to take action directly`,
- AdharmaKeyRingImplementation,
- 'takeAction',
- 'send',
- [address, 1, '0x', '0x'],
- false
- )
-
- await runTest(
- `UpgradeBeaconProxyV1 contract deployment fails with no init data`,
- UpgradeBeaconProxyV1Deployer,
- '',
- 'deploy',
- ['0x'],
- false
- )
-
- await runTest(
- `KeyRingUpgradeBeaconProxyV1 contract deployment fails with no init data`,
- KeyRingUpgradeBeaconProxyV1Deployer,
- '',
- 'deploy',
- ['0x'],
- false
- )
-
- const UpgradeBeaconProxyV1 = await runTest(
- `UpgradeBeaconProxyV1 contract deployment (direct)`,
- UpgradeBeaconProxyV1Deployer,
- '',
- 'deploy',
- [web3.eth.abi.encodeFunctionCall({
- name: 'initialize',
- type: 'function',
- inputs: [{
- type: 'address',
- name: 'userSigningKey'
- }]
- }, [address])]
- )
-
- const UpgradeBeaconProxyV1Implementation = new web3.eth.Contract(
- DharmaSmartWalletImplementationV6Artifact.abi,
- UpgradeBeaconProxyV1.options.address
- )
-
- await runTest(
- `UpgradeBeaconProxyV1 can retrieve its user signing key`,
- UpgradeBeaconProxyV1Implementation,
- 'getUserSigningKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- const KeyRingUpgradeBeaconProxyV1 = await runTest(
- `KeyRingUpgradeBeaconProxyV1 contract deployment (direct)`,
- KeyRingUpgradeBeaconProxyV1Deployer,
- '',
- 'deploy',
- [web3.eth.abi.encodeFunctionCall({
- name: 'initialize',
- type: 'function',
- inputs: [{
- type: 'uint128',
- name: 'adminThreshold'
- },{
- type: 'uint128',
- name: 'executorThreshold'
- },{
- type: 'address[]',
- name: 'keys'
- },{
- type: 'uint8[]',
- name: 'keyTypes'
- }]
- }, [1, 1, [address], [3]])]
- )
-
- const KeyRingUpgradeBeaconProxyV1Implementation = new web3.eth.Contract(
- DharmaKeyRingImplementationV1Artifact.abi,
- KeyRingUpgradeBeaconProxyV1.options.address
- )
-
- await runTest(
- `KeyRingUpgradeBeaconProxyV1 can retrieve its user signing key`,
- KeyRingUpgradeBeaconProxyV1Implementation,
- 'getKeyType',
- 'call',
- [address],
- true,
- values => {
- assert.ok(values.standard)
- assert.ok(values.admin)
- }
- )
-
- // NOTE: these two either need to have the runtime requirement stripped out,
- // or to use coverage without instrumentation. Skip coverage for now, as they
- // are not yet in use.
- // (actually, they're not working yet, period... skip them for now)
- /*
- if (testingContext !== 'coverage') {
- const DharmaSmartWalletFactoryV2 = await runTest(
- `DharmaSmartWalletFactoryV2 contract deployment`,
- DharmaSmartWalletFactoryV2Deployer,
- '',
- 'deploy',
- []
- )
-
- const DharmaKeyRingFactoryV3 = await runTest(
- `DharmaKeyRingFactoryV3 contract deployment`,
- DharmaKeyRingFactoryV3Deployer,
- '',
- 'deploy',
- []
- )
- }
- */
-
- await runTest(
- 'Dharma Key Registry V2 gets the initial global key correctly',
- DharmaKeyRegistryV2Coverage,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 attempt to get an unset specific key throws',
- DharmaKeyRegistryV2Coverage,
- 'getSpecificKey',
- 'call',
- [address],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the global key when requesting unset key',
- DharmaKeyRegistryV2Coverage,
- 'getKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a new empty global key',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- constants.NULL_ADDRESS,
- '0x'
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- const messageCoverage = (
- DharmaKeyRegistryV2Coverage.options.address +
- addressTwo.slice(2) +
- web3.utils.asciiToHex(
- "This signature demonstrates that the supplied signing key is valid."
- ).slice(2)
- )
-
- const newKeySignatureCoverage = signHashedPrefixedHashedHexString(messageCoverage, addressTwo)
-
- const badNewKeySignatureCoverage = signHashedPrefixedHashedHexString('0x12', addressTwo)
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a new global key unless called by owner',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- addressTwo,
- newKeySignatureCoverage
- ],
- false,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot set an empty global key',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- constants.NULL_ADDRESS,
- newKeySignatureCoverage
- ],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a new global key with a bad signature',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- addressTwo,
- badNewKeySignatureCoverage
- ],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 can set a new global key correctly',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- addressTwo,
- newKeySignatureCoverage
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the new global key correctly',
- DharmaKeyRegistryV2Coverage,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, addressTwo)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a new specific key unless called by owner',
- DharmaKeyRegistryV2Coverage,
- 'setSpecificKey',
- 'send',
- [
- address,
- DharmaKeyRegistryV2.options.address
- ],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets global key for a user if no specific key set',
- DharmaKeyRegistryV2Coverage,
- 'getKeyForUser',
- 'call',
- [address],
- true,
- value => {
- assert.strictEqual(value, addressTwo)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 can set a new specific key',
- DharmaKeyRegistryV2Coverage,
- 'setSpecificKey',
- 'send',
- [
- address,
- DharmaKeyRegistryV2.options.address
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets specific key for user if one is set',
- DharmaKeyRegistryV2Coverage,
- 'getKeyForUser',
- 'call',
- [address],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryV2.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the new specific key correctly',
- DharmaKeyRegistryV2Coverage,
- 'getSpecificKey',
- 'call',
- [address],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryV2.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the specific key when requesting set key',
- DharmaKeyRegistryV2Coverage,
- 'getKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryV2.options.address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot reuse a specific key',
- DharmaKeyRegistryV2Coverage,
- 'setSpecificKey',
- 'send',
- [
- address,
- DharmaKeyRegistryV2.options.address
- ],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 new owner cannot accept ownership before added',
- DharmaKeyRegistryV2Coverage,
- 'acceptOwnership',
- 'send',
- [],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 cannot prepare to transfer to the null address',
- DharmaKeyRegistryV2Coverage,
- 'transferOwnership',
- 'send',
- [
- constants.NULL_ADDRESS
- ],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 can prepare to transfer to a new owner',
- DharmaKeyRegistryV2Coverage,
- 'transferOwnership',
- 'send',
- [
- address
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V2 can cancel an ownership transfer',
- DharmaKeyRegistryV2Coverage,
- 'cancelOwnershipTransfer'
- )
-
- await runTest(
- 'Dharma Key Registry V2 new owner cannot accept ownership after cancellation',
- DharmaKeyRegistryV2Coverage,
- 'acceptOwnership',
- 'send',
- [],
- false
- )
-
- await runTest(
- 'Dharma Key Registry V2 can prepare to transfer to a new owner again',
- DharmaKeyRegistryV2Coverage,
- 'transferOwnership',
- 'send',
- [
- address
- ]
- )
-
- await runTest(
- 'Dharma Key Registry V2 new owner can accept ownership',
- DharmaKeyRegistryV2Coverage,
- 'acceptOwnership'
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the new owner',
- DharmaKeyRegistryV2Coverage,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- 'Dharma Key Registry V2 gets the global key correctly',
- DharmaKeyRegistryV2Coverage,
- 'getGlobalKey',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, addressTwo)
- }
- )
-
- const messageV2Coverage = (
- DharmaKeyRegistryV2Coverage.options.address +
- address.slice(2) +
- web3.utils.asciiToHex(
- "This signature demonstrates that the supplied signing key is valid."
- ).slice(2)
- )
-
- const v2KeySignatureCoverage = signHashedPrefixedHashedHexString(messageV2Coverage, address)
-
- await runTest(
- 'Dharma Key Registry V2 cannot set a previously used global key',
- DharmaKeyRegistryV2Coverage,
- 'setGlobalKey',
- 'send',
- [
- address,
- v2KeySignatureCoverage
- ],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController initially gets zero for lastImplementation`,
- DharmaUpgradeBeaconControllerCoverage,
- 'getCodeHashAtLastUpgrade',
- 'call',
- [address],
- true,
- value => {
- assert.strictEqual(value, constants.NULL_BYTES_32)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot call upgrade from non-owner account`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [DharmaUpgradeBeaconCoverage.options.address, DharmaUpgradeBeaconController.options.address],
- false,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can set implementation on upgrade beacon contract`,
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [DharmaUpgradeBeaconCoverage.options.address, DharmaUpgradeBeaconController.options.address]
- )
-
- await runTest(
- `DharmaKeyRingUpgradeBeaconController can set implementation on key ring upgrade beacon contract`,
- DharmaKeyRingUpgradeBeaconController,
- 'upgrade',
- 'send',
- [DharmaKeyRingUpgradeBeaconCoverage.options.address, DharmaUpgradeBeaconController.options.address]
- )
-
- await runTest(
- `DharmaUpgradeBeaconEnvoy throws when given invalid beacon`,
- DharmaUpgradeBeaconEnvoy,
- 'getImplementation',
- 'call',
- [DharmaUpgradeBeaconEnvoy.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconEnvoy throws when given non-contract beacon`,
- DharmaUpgradeBeaconEnvoy,
- 'getImplementation',
- 'call',
- [address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconEnvoy can get the implementation of a valid beacon`,
- DharmaUpgradeBeaconEnvoy,
- 'getImplementation',
- 'call',
- [DharmaKeyRingUpgradeBeaconCoverage.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaUpgradeBeaconController.options.address)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set null implementation on an upgrade beacon contract`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [DharmaUpgradeBeaconCoverage.options.address, constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set non-contract implementation`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [DharmaUpgradeBeaconCoverage.options.address, address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set null address beacon`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [constants.NULL_ADDRESS, DharmaUpgradeBeaconControllerCoverage.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set non-contract address beacon`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [address, DharmaUpgradeBeaconControllerCoverage.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set unowned bad beacon`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [BadBeaconTwo.options.address, DharmaUpgradeBeaconControllerCoverage.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot set unowned beacon (Note that it still logs an event!)`,
- DharmaUpgradeBeaconControllerCoverage,
- 'upgrade',
- 'send',
- [DharmaUpgradeBeaconCoverage.options.address, DharmaUpgradeBeaconControllerCoverage.options.address]
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can get implementation of a beacon`,
- DharmaUpgradeBeaconControllerCoverage,
- 'getImplementation',
- 'call',
- [DharmaUpgradeBeaconCoverage.options.address],
- true,
- value => {
- assert.strictEqual(value, DharmaUpgradeBeaconController.options.address)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can get owner`,
- DharmaUpgradeBeaconControllerCoverage,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can call isOwner and value is ok`,
- DharmaUpgradeBeaconControllerCoverage,
- 'isOwner',
- 'call',
- [],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconController cannot transfer ownership to null address`,
- DharmaUpgradeBeaconControllerCoverage,
- 'transferOwnership',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can transfer ownership`,
- DharmaUpgradeBeaconControllerCoverage,
- 'transferOwnership',
- 'send',
- [address]
- )
-
- await runTest(
- `DharmaUpgradeBeaconController can renounce ownership`,
- DharmaUpgradeBeaconControllerCoverage,
- 'renounceOwnership'
- )
-
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot transfer ownership from a non-owner`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'transferOwnership',
- 'send',
- [addressTwo],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot initiate recovery with null smart wallet`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [constants.NULL_ADDRESS, addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot initiate recovery with null new key`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [address, constants.NULL_ADDRESS, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can initiate recovery timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS, addressTwo, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can initiate another recovery timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [UserSmartWalletV6.options.address, addressTwo, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can initiate a third recovery timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [address, addressTwo, 0]
- )
-
- await runTest(
- 'smart wallet account recovery cannot be cancelled with no smart wallet',
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecovery',
- 'send',
- [
- constants.NULL_ADDRESS,
- addressTwo
- ],
- false
- )
-
- await runTest(
- 'smart wallet account recovery cannot be cancelled with no user signing key',
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecovery',
- 'send',
- [
- address,
- constants.NULL_ADDRESS
- ],
- false
- )
-
- await runTest(
- 'smart wallet account recovery can be cancelled',
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecovery',
- 'send',
- [
- address,
- addressTwo
- ],
- true,
- receipt => {
- // TODO: verify
- //console.log(receipt.events)
- }
- )
-
- await runTest(
- 'smart wallet account recovery cannot be cancelled if it is already cancelled',
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecovery',
- 'send',
- [
- address,
- addressTwo
- ],
- false
- )
-
- await runTest(
- 'smart wallet account recovery cannot be cancelled if no timelock exists',
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecovery',
- 'send',
- [
- addressTwo,
- addressTwo
- ],
- false
- )
-
-
- await runTest(
- 'smart wallet account recovery can be reinitiated',
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [
- address,
- addressTwo,
- 1 // extraTime in seconds - add one to ensure that timelock is extended
- ],
- true,
- receipt => {
- // TODO: verify
- //console.log(receipt.events)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot initiate recovery disablement with null smart wallet`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecoveryDisablement',
- 'send',
- [constants.NULL_ADDRESS, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can initiate recovery disablement timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecoveryDisablement',
- 'send',
- [address, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call recover with null new key`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [constants.NULL_ADDRESS, addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call recover with null new key`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [address, constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call recover prior to timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS, addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery prior to timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'disableAccountRecovery',
- 'send',
- [address],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if account recovery is disabled`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'accountRecoveryDisabled',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- // advance time by 3 days
- await advanceTime((60 * 60 * 24 * 3) + 5)
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call recover after timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS, addressTwo]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot recover an unowned smart wallet`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [UserSmartWalletV6.options.address, addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot recover an EOA`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [address, addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery with null smart wallet`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'disableAccountRecovery',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call disableAccountRecovery after timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'disableAccountRecovery',
- 'send',
- [address]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if account recovery is disabled`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'accountRecoveryDisabled',
- 'call',
- [address],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot recover an account that has disabled recovery`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'recover',
- 'send',
- [address, addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10000, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock on another function`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xaaaaaaaa', 10000, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockInterval',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval before timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockInterval',
- 'send',
- ['0xe950c085', 1000],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to with expiration over one month`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 30, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one hour`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 3000, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 30000, 0],
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock on another function`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xaaaaaaaa', 300000, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration before timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can initiate recovery disablement timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecoveryDisablement',
- 'send',
- [addressTwo, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot cancel disablement with null address`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecoveryDisablement',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can cancel recovery disablement timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'cancelAccountRecoveryDisablement',
- 'send',
- [addressTwo]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can re-initiate recovery disablement timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecoveryDisablement',
- 'send',
- [addressTwo, 1]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot shorten a timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecoveryDisablement',
- 'send',
- [addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot initiate recovery with massive extraTime`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateAccountRecovery',
- 'send',
- [address, addressTwo, constants.FULL_APPROVAL],
- false
- )
-
- // advance time by 2 weeks
- await advanceTime((60 * 60 * 24 * 7 * 2) + 5)
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call disableAccountRecovery after timelock expiration`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'disableAccountRecovery',
- 'send',
- [addressTwo],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot set a role to the null address`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'setRole',
- 'send',
- [0, constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can set a role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'setRole',
- 'send',
- [0, address]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can set a role that is already set`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'setRole',
- 'send',
- [0, address]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if the caller has a role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'isRole',
- 'call',
- [0],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check for an operator role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getOperator',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check for a recoverer role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getRecoverer',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.NULL_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check for a canceller role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getCanceller',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.NULL_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check for a disabler role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getDisabler',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.NULL_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check for a pauser role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getPauser',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.NULL_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can remove a role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'removeRole',
- 'send',
- [0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if the caller has a role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'isRole',
- 'call',
- [0],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if a role is paused`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'isPaused',
- 'call',
- [0],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot pause a role if not owner or pauser`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'pause',
- 'send',
- [0],
- false,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can set a role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'setRole',
- 'send',
- [4, addressTwo]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot unpause an unpaused role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'unpause',
- 'send',
- [0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can pause an unpaused role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'pause',
- 'send',
- [0],
- true,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot pause a paused role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'pause',
- 'send',
- [0],
- false,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can pause the pauser role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'pause',
- 'send',
- [4]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 pauser cannot call a paused role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'pause',
- 'send',
- [4],
- false,
- receipt => {},
- addressTwo
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can check if a role is paused`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'isPaused',
- 'call',
- [0],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can unpause a paused role`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'unpause',
- 'send',
- [0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can get an empty timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getTimelock',
- 'call',
- ['0x01020304', '0x'],
- true,
- value => {
- assert.ok(!value.exists)
- assert.ok(!value.completed)
- assert.ok(!value.expired)
- assert.strictEqual(value.completionTime, '0')
- assert.strictEqual(value.expirationTime, '0')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can get an empty default timelock interval`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getDefaultTimelockInterval',
- 'call',
- ['0x01020304'],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can get an empty default timelock expiration`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'getDefaultTimelockExpiration',
- 'call',
- ['0x01020304'],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot create timelock with excessive duration`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', constants.FULL_APPROVAL, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10000, 5]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot shorten existing initiateModifyTimelockInterval timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10000, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to change a duration`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10001, 5]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockInterval to set a timelock on another function`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xaaaaaaaa', 10000, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockInterval',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockInterval before timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockInterval',
- 'send',
- ['0xe950c085', 1000],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to with expiration over one month`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 30, 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300000, 0],
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call initiateModifyTimelockExpiration to set a timelock on another function`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xe950c085', 30, 0]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration with no selector`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration before timelock completion`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300],
- false
- )
-
- // advance time by 2 weeks
- await advanceTime((60 * 60 * 24 * 7 * 2) + 5)
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call modifyTimelockInterval`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockInterval',
- 'send',
- ['0xaaaaaaaa', 10000]
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 can call modifyTimelockExpiration`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300000],
- )
-
- await runTest(
- `DharmaAccountRecoveryManagerV2 cannot call modifyTimelockExpiration if expiration is too short`,
- DharmaAccountRecoveryManagerV2Coverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xe950c085', 30],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot transfer ownership from a non-owner`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'transferOwnership',
- 'send',
- [addressTwo],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null controller`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [constants.NULL_ADDRESS, address, addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null beacon`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [address, constants.NULL_ADDRESS, addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with null implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [address, addressTwo, constants.NULL_ADDRESS, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with non-contract implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [address, addressTwo, address, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate an upgrade with massive extraTime`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [address, addressTwo, DharmaUpgradeBeaconControllerManager.options.address, constants.FULL_APPROVAL],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can initiate upgrade timelock`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateUpgrade',
- 'send',
- [address, addressTwo, DharmaUpgradeBeaconControllerManager.options.address, 0]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get an empty timelock`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getTimelock',
- 'call',
- ['0x01020304', '0x'],
- true,
- value => {
- assert.ok(!value.exists)
- assert.ok(!value.completed)
- assert.ok(!value.expired)
- assert.strictEqual(value.completionTime, '0')
- assert.strictEqual(value.expirationTime, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get an empty default timelock interval`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getDefaultTimelockInterval',
- 'call',
- ['0x01020304'],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get an empty default timelock expiration`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getDefaultTimelockExpiration',
- 'call',
- ['0x01020304'],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot upgrade before timelock is complete`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'upgrade',
- 'send',
- [address, addressTwo, DharmaUpgradeBeaconControllerManager.options.address],
- false
- )
-
- // advance time by 7 days
- await advanceTime((60 * 60 * 24 * 7) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot upgrade an unowned controller`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'upgrade',
- 'send',
- [address, addressTwo, DharmaUpgradeBeaconControllerManager.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot transfer controller ownership before accepting ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'transferControllerOwnership',
- 'send',
- [address, address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot agree to accept ownership of null controller`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'agreeToAcceptControllerOwnership',
- 'send',
- [constants.NULL_ADDRESS, true],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can agree to accept ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'agreeToAcceptControllerOwnership',
- 'send',
- [address, true]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer with null controller`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateTransferControllerOwnership',
- 'send',
- [constants.NULL_ADDRESS, addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer with null new owner`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateTransferControllerOwnership',
- 'send',
- [address, constants.NULL_ADDRESS, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot initiate controller ownership transfer if new owner has not accepted`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateTransferControllerOwnership',
- 'send',
- [address, addressTwo, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can initiate controller ownership transfer if new owner has accepted`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateTransferControllerOwnership',
- 'send',
- [address, address, 0]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot transfer controller ownership prior to timelock completion`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'transferControllerOwnership',
- 'send',
- [address, address],
- false
- )
-
- // advance time by 4 weeks
- await advanceTime((60 * 60 * 24 * 7 * 4) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot transfer unowned controller ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'transferControllerOwnership',
- 'send',
- [address, address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot heartbeat from non-heartbeater`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'heartbeat',
- 'send',
- [],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can heartbeat`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'heartbeat'
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot set new heartbeater to null address`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'newHeartbeater',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can set new heartbeater`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'newHeartbeater',
- 'send',
- [address]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot arm Adharma Contingency from non-owner when not expired`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when not armed`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can arm an Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can disarm Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [false]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can re-arm Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency from non-owner when not expired`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when it doesn't own controllers`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot roll back prior to first upgrade`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [address, address, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot exit Adharma Contingency when not active`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [address, address],
- false
- )
-
- /*
- await runTest(
- `DharmaUpgradeBeaconControllerManager can activate Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- []
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner cannot arm Adharma Contingency while active`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Contingency when activated`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can disarm Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [false]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot exit Contingency before 48 hours`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- DharmaSmartWalletImplementationV6.options.address,
- DharmaKeyRingImplementationV1.options.address
- ],
- false
- )
-
- // advance time by 2 days
- await advanceTime((60 * 60 * 24 * 2) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot exit Contingency to null address`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [constants.NULL_ADDRESS, DharmaKeyRingImplementationV1.options.address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot exit Contingency to non-contract address`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [address, address],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can exit Contingency after 48 hours`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- DharmaSmartWalletImplementationV6.options.address,
- DharmaKeyRingImplementationV1.options.address
- ]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can arm Adharma Contingency again`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can activate fake Adharma Contingency again`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- []
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can roll back from fake Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [constants.UPGRADE_BEACON_CONTROLLER_ADDRESS, constants.UPGRADE_BEACON_ADDRESS, 0]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can "roll forward" after roll back`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [constants.UPGRADE_BEACON_ADDRESS, constants.UPGRADE_BEACON_ADDRESS]
- )
- */
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get heartbeat status`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'heartbeatStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.expired)
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager get contingency status when armed but not activated`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'contingencyStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(value.armed)
- assert.ok(!value.activated)
- assert.strictEqual(value.activationTime, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager gets 0 for non-existent total implementations`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getTotalPriorImplementations',
- 'call',
- [address, address],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot get a prior implementation with no index`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getPriorImplementation',
- 'call',
- [address, address, 100],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot rollback to implementation with no index`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [address, address, 100],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot block rollback to implementation with no index`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'blockRollback',
- 'send',
- [address, address, 100],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockInterval with no selector`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockInterval to modify interval over 8 weeks`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot create timelock with excessive duration`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', constants.FULL_APPROVAL, 0],
- false // TODO: move this outside of Controller manager
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to set a timelock`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10000, 5]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot shorten existing initiateModifyTimelockInterval timelock`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10000, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to change a duration`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xe950c085', 10001, 5]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockInterval to set a timelock on another function`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockInterval',
- 'send',
- ['0xaaaaaaaa', 10000, 0]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockInterval with no selector`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockInterval',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockInterval before timelock completion`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockInterval',
- 'send',
- ['0xe950c085', 1000],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration with no selector`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0x00000000', 0, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration to with expiration over one month`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xe950c085', 5443200, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call initiateModifyTimelockExpiration to modify expiration under one minute`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 30, 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockExpiration to set a timelock`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300000, 0],
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call initiateModifyTimelockExpiration to set a timelock on another function`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateModifyTimelockExpiration',
- 'send',
- ['0xe950c085', 30, 0]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration with no selector`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0x00000000', 0],
- false
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration before timelock completion`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300],
- false
- )
-
- // advance time by 4 weeks
- await advanceTime((60 * 60 * 24 * 7 * 4) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call modifyTimelockInterval`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockInterval',
- 'send',
- ['0xaaaaaaaa', 10000]
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call modifyTimelockExpiration`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xd7ce3c6f', 300000],
- )
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call modifyTimelockExpiration if expiration is too short`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'modifyTimelockExpiration',
- 'send',
- ['0xe950c085', 30],
- false
- )
-
- const MockDharmaKeyRingFactory = await runTest(
- `MockDharmaKeyRingFactory contract deployment`,
- MockDharmaKeyRingFactoryDeployer,
- '',
- 'deploy',
- []
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with no keys`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [], []],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with null address as key`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [constants.NULL_ADDRESS], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with non-dual key`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [address], [1]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with admin threshold > 1`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [2, 1, [address], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with executor threshold > 1`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 2, [address], [3]],
- false
- )
-
- await runTest(
- 'Dharma Upgrade Beacon Controller can upgrade to AdharmaSmartWalletImplementation',
- DharmaUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaUpgradeBeacon.options.address,
- AdharmaSmartWalletImplementation.options.address
- ]
- )
-
- await runTest(
- 'Dharma Key Ring Upgrade Beacon Controller can upgrade to AdharmaKeyRingImplementation',
- DharmaKeyRingUpgradeBeaconController,
- 'upgrade',
- 'send',
- [
- DharmaKeyRingUpgradeBeacon.options.address,
- AdharmaKeyRingImplementation.options.address
- ]
- )
-
- await runTest(
- 'DharmaSmartWalletFactoryV1 cannot deploy an Adharma smart wallet with no key',
- DharmaSmartWalletFactoryV1,
- 'newSmartWallet',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- 'DharmaSmartWalletFactoryV1 can deploy an Adharma smart wallet',
- DharmaSmartWalletFactoryV1,
- 'newSmartWallet',
- 'send',
- [address]
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 cannot create a V1 key ring with no key`,
- DharmaKeyRingFactoryV1,
- 'newKeyRing',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 cannot create an Adharma key ring and set a new null key`,
- DharmaKeyRingFactoryV1,
- 'newKeyRingAndAdditionalKey',
- 'send',
- [address, constants.NULL_ADDRESS, '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 reverts when no new key ring supplied`,
- DharmaKeyRingFactoryV1,
- 'getNextKeyRing',
- 'call',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 can call newKeyRingAndDaiWithdrawal`,
- DharmaKeyRingFactoryV1,
- 'newKeyRingAndDaiWithdrawal',
- 'send',
- [address, address, 0, address, 0, '0x', '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 can call newKeyRingAndUSDCWithdrawal`,
- DharmaKeyRingFactoryV1,
- 'newKeyRingAndUSDCWithdrawal',
- 'send',
- [address, address, 0, address, 0, '0x', '0x'],
- false
- )
-
- await runTest(
- `DharmaKeyRingFactoryV1 can create an Adharma key ring`,
- DharmaKeyRingFactoryV1,
- 'newKeyRing',
- 'send',
- [address]
- )
-
- const UserSmartWalletAdharma = new web3.eth.Contract(
- AdharmaSmartWalletImplementationArtifact.abi,
- UserSmartWalletV6.options.address
- )
-
- await runTest(
- `Adharma Smart Wallet can be used to perform calls`,
- UserSmartWalletAdharma,
- 'performCall',
- 'send',
- [UserSmartWalletAdharma.options.address, 0, '0x'],
- true,
- receipt => {},
- originalAddress
- )
-
- await runTest(
- `Adharma Smart Wallet can be used to perform failing calls`,
- UserSmartWalletAdharma,
- 'performCall',
- 'send',
- [BadBeacon.options.address, 0, '0x'],
- false,
- receipt => {},
- originalAddress
- )
-
- const KeyRingAdharma = new web3.eth.Contract(
- AdharmaKeyRingImplementationArtifact.abi,
- KeyRingInstance.options.address
- )
-
- await runTest(
- `Adharma Key Ring can be used to take an action`,
- KeyRingAdharma,
- 'takeAction',
- 'send',
- [address, 0, '0x', '0x']
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no keys`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [0, 0, [], []],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with admin threshold of 0`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [0, 1, [address], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with executor threshold of 0`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 0, [address], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring where length of keys and types are not equal`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [address, addressTwo], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with duplicate keys`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [address, address], [3, 3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no admin key`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [address], [1]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with less admin keys than threshold`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [2, 1, [address], [3]],
- false
- )
-
- await runTest(
- `MockDharmaKeyRingFactory can deploy an Adharma key ring with multiple keys`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [2, 2, [address, addressTwo], [3, 3]]
- )
-
- await runTest(
- `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no standard key`,
- MockDharmaKeyRingFactory,
- 'newKeyRing',
- 'send',
- [1, 1, [address], [2]],
- false
- )
-
- await runTest(
- `TimelockEdgecaseTester contract deployment edge case 1`,
- TimelockEdgecaseTesterDeployer,
- '',
- 'deploy',
- [0],
- false
- )
-
- await runTest(
- `TimelockEdgecaseTester contract deployment edge case 2`,
- TimelockEdgecaseTesterDeployer,
- '',
- 'deploy',
- [1],
- false
- )
-
- await runTest(
- `TimelockEdgecaseTester contract deployment edge case 3`,
- TimelockEdgecaseTesterDeployer,
- '',
- 'deploy',
- [2],
- false
- )
-
- const DharmaUpgradeMultisig = await runTest(
- `DharmaUpgradeMultisig contract deployment`,
- DharmaUpgradeMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]]
- )
-
- const DharmaAccountRecoveryMultisig = await runTest(
- `DharmaAccountRecoveryMultisig contract deployment`,
- DharmaAccountRecoveryMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour]]
- )
-
- const DharmaAccountRecoveryOperatorMultisig = await runTest(
- `DharmaAccountRecoveryOperatorMultisig contract deployment`,
- DharmaAccountRecoveryOperatorMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour]]
- )
-
- const DharmaKeyRegistryMultisig = await runTest(
- `DharmaKeyRegistryMultisig contract deployment`,
- DharmaKeyRegistryMultisigDeployer,
- '',
- 'deploy',
- [[ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]]
- )
-
- rawData = '0x'
- executorGasLimit = 100000000000
-
- const bizarreSigs = (
- '0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0' +
- '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A11b' +
- '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0' +
- '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A01a'
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get the initial nonce`,
- DharmaUpgradeMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get the owners`,
- DharmaUpgradeMultisig,
- 'getOwners',
- 'call',
- [],
- true,
- value => {
- assert.deepEqual(
- value, [ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]
- )
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get an owner`,
- DharmaUpgradeMultisig,
- 'isOwner',
- 'call',
- [ownerOne],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig returns false for a non-owner`,
- DharmaUpgradeMultisig,
- 'isOwner',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get the threshold`,
- DharmaUpgradeMultisig,
- 'getThreshold',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '3')
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get the destination`,
- DharmaUpgradeMultisig,
- 'getDestination',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS)
- }
- )
-
- // Generate the messsage hash based on the supplied parameters.
- hashInputs = (
- DharmaUpgradeMultisig.options.address +
- '0'.padStart(64, '0') +
- address.slice(2) +
- executorGasLimit.toString(16).padStart(64, '0') +
- rawData.slice(2)
- )
-
- hash = util.bufferToHex(util.keccak256(hashInputs))
-
- await runTest(
- `DharmaUpgradeMultisig can get a hash`,
- DharmaUpgradeMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- await runTest(
- `DharmaUpgradeMultisig can get a hash with a specific nonce`,
- DharmaUpgradeMultisig,
- 'getHash',
- 'call',
- [rawData, address, executorGasLimit, 0],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute from non-executor`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, addressTwo, executorGasLimit, ownerSigs],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute with oddly-sized signatures`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs + '1234'],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute with non-compliant signatures`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, bizarreSigs],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute without enough signatures`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs.slice(0, -130)],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute without owner signatures`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, unownedSigs],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig cannot call execute with out-of-order signatures`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigsOutOfOrder],
- false
- )
-
- await runTest(
- `DharmaUpgradeMultisig can call execute`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
-
- await runTest(
- `DharmaUpgradeMultisig nonce is incremented`,
- DharmaUpgradeMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get the initial nonce`,
- DharmaKeyRegistryMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get the owners`,
- DharmaKeyRegistryMultisig,
- 'getOwners',
- 'call',
- [],
- true,
- value => {
- assert.deepEqual(
- value, [ownerOne, ownerTwo, ownerThree, ownerFour, ownerFive]
- )
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get an owner`,
- DharmaKeyRegistryMultisig,
- 'isOwner',
- 'call',
- [ownerOne],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig returns false for a non-owner`,
- DharmaKeyRegistryMultisig,
- 'isOwner',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get the threshold`,
- DharmaKeyRegistryMultisig,
- 'getThreshold',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '3')
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get the destination`,
- DharmaKeyRegistryMultisig,
- 'getDestination',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.KEY_REGISTRY_V2_ADDRESS)
- }
- )
-
- // Generate the messsage hash based on the supplied parameters.
- hashInputs = (
- DharmaKeyRegistryMultisig.options.address +
- '0'.padStart(64, '0') +
- address.slice(2) +
- executorGasLimit.toString(16).padStart(64, '0') +
- rawData.slice(2)
- )
-
- hash = util.bufferToHex(util.keccak256(hashInputs))
-
- await runTest(
- `DharmaKeyRegistryMultisig can get a hash`,
- DharmaKeyRegistryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can get a hash with a specific nonce`,
- DharmaKeyRegistryMultisig,
- 'getHash',
- 'call',
- [rawData, address, executorGasLimit, 0],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute from non-executor`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, addressTwo, executorGasLimit, ownerSigs],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute with oddly-sized signatures`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs + '1234'],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute with non-compliant signatures`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, bizarreSigs],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute without enough signatures`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs.slice(0, -130)],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute without owner signatures`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, unownedSigs],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig cannot call execute with out-of-order signatures`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigsOutOfOrder],
- false
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig can call execute`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
-
- await runTest(
- `DharmaKeyRegistryMultisig nonce is incremented`,
- DharmaKeyRegistryMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get the initial nonce`,
- DharmaAccountRecoveryMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '0')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get the owners`,
- DharmaAccountRecoveryMultisig,
- 'getOwners',
- 'call',
- [],
- true,
- value => {
- assert.deepEqual(
- value, [ownerOne, ownerTwo, ownerThree, ownerFour]
- )
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get an owner`,
- DharmaAccountRecoveryMultisig,
- 'isOwner',
- 'call',
- [ownerOne],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig returns false for a non-owner`,
- DharmaAccountRecoveryMultisig,
- 'isOwner',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get the threshold`,
- DharmaAccountRecoveryMultisig,
- 'getThreshold',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '3')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get the destination`,
- DharmaAccountRecoveryMultisig,
- 'getDestination',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS)
- }
- )
-
- // Generate the messsage hash based on the supplied parameters.
- hashInputs = (
- DharmaAccountRecoveryMultisig.options.address +
- '0'.padStart(64, '0') +
- address.slice(2) +
- executorGasLimit.toString(16).padStart(64, '0') +
- rawData.slice(2)
- )
-
- hash = util.bufferToHex(util.keccak256(hashInputs))
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get a hash`,
- DharmaAccountRecoveryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can get a hash with a specific nonce`,
- DharmaAccountRecoveryMultisig,
- 'getHash',
- 'call',
- [rawData, address, executorGasLimit, 0],
- true,
- value => {
- assert.strictEqual(value, hash)
- }
- )
-
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
-
- /*
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2)
- */
-
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute from non-executor`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, addressTwo, executorGasLimit, ownerSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute with oddly-sized signatures`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs + '1234'],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute with non-compliant signatures`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, bizarreSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute without enough signatures`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerOneSig],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute without owner signatures`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, unownedSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig cannot call execute with out-of-order signatures`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigsOutOfOrder],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig can call execute`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
-
- await runTest(
- `DharmaAccountRecoveryMultisig nonce is incremented`,
- DharmaAccountRecoveryMultisig,
- 'getNonce',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can get the owners`,
- DharmaAccountRecoveryOperatorMultisig,
- 'getOwners',
- 'call',
- [],
- true,
- value => {
- assert.deepEqual(
- value, [ownerOne, ownerTwo, ownerThree, ownerFour]
- )
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can get an owner`,
- DharmaAccountRecoveryOperatorMultisig,
- 'isOwner',
- 'call',
- [ownerOne],
- true,
- value => {
- assert.ok(value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig returns false for a non-owner`,
- DharmaAccountRecoveryOperatorMultisig,
- 'isOwner',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can get the threshold`,
- DharmaAccountRecoveryOperatorMultisig,
- 'getThreshold',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, '2')
- }
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can get the destination`,
- DharmaAccountRecoveryOperatorMultisig,
- 'getDestination',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS)
- }
- )
-
- // Generate the messsage hash based on the supplied parameters.
- hashInputs = (
- DharmaAccountRecoveryOperatorMultisig.options.address +
- '0'.padStart(64, '0') +
- address.slice(2) +
- executorGasLimit.toString(16).padStart(64, '0') +
- rawData.slice(2)
- )
-
- hash = util.bufferToHex(util.keccak256(hashInputs))
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can get a hash`,
- DharmaAccountRecoveryOperatorMultisig,
- 'getHash',
- 'call',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32],
- true,
- values => {
- assert.strictEqual(values.hash, hash)
- }
- )
-
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
-
- /*
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2)
- */
-
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2)
- ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2)
- unownedSig = signHashedPrefixedHexString(hash, address)
- unownedSigs = unownedSig + ownerTwoSig.slice(2)
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute from non-executor`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, addressTwo, executorGasLimit, constants.NULL_BYTES_32, ownerSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute with oddly-sized signatures`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, ownerSigs + '1234'],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute with non-compliant signatures`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, bizarreSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute without enough signatures`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, ownerOneSig],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute without owner signatures`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, unownedSigs],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot call execute with out-of-order signatures`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, ownerSigsOutOfOrder],
- false
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig can call execute`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, ownerSigs]
- )
-
- await runTest(
- `DharmaAccountRecoveryOperatorMultisig cannot replay a call to execute`,
- DharmaAccountRecoveryOperatorMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, constants.NULL_BYTES_32, ownerSigs],
- false
- )
-
- const DharmaEscapeHatchRegistry = await runTest(
- `DharmaEscapeHatchRegistry contract deployment`,
- DharmaEscapeHatchRegistryDeployer,
- '',
- 'deploy'
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms that an escape hatch does not exist until set`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatch',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.exists)
- assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS)
- }
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can set the null address as an escape hatch account`,
- DharmaEscapeHatchRegistry,
- 'setEscapeHatch',
- 'send',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can set an escape hatch account`,
- DharmaEscapeHatchRegistry,
- 'setEscapeHatch',
- 'send',
- [addressTwo]
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can get an escape hatch account once set`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatch',
- 'call',
- [],
- true,
- value => {
- assert.ok(value.exists)
- assert.strictEqual(value.escapeHatch, addressTwo)
- }
- )
-
- fallbackEscapeHatch = await web3.eth.call({
- to: DharmaEscapeHatchRegistry.options.address,
- from: address,
- data: "0x"
- })
-
- console.log(
- ' ✓ DharmaEscapeHatchRegistry can get an escape hatch account using the fallback'
- )
- assert.strictEqual(
- web3.eth.abi.decodeParameter('address', fallbackEscapeHatch),
- addressTwo
- )
- passed++
-
- await runTest(
- `DharmaEscapeHatchRegistry can get an escape hatch for a specific smart wallet`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatchForSmartWallet',
- 'call',
- [address],
- true,
- value => {
- assert.ok(value.exists)
- assert.strictEqual(value.escapeHatch, addressTwo)
- },
- originalAddress
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry cannot get an escape hatch the null address`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatchForSmartWallet',
- 'call',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can remove an escape hatch account`,
- DharmaEscapeHatchRegistry,
- 'removeEscapeHatch'
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms that an escape hatch is successfully removed`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatch',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.exists)
- assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS)
- }
- )
-
- fallbackEscapeHatch = await web3.eth.call({
- to: DharmaEscapeHatchRegistry.options.address,
- from: address,
- data: "0x"
- })
-
- console.log(
- ' ✓ DharmaEscapeHatchRegistry can gets null address for removed escape hatch account using the fallback'
- )
- assert.strictEqual(
- web3.eth.abi.decodeParameter('address', fallbackEscapeHatch),
- constants.NULL_ADDRESS
- )
- passed++
-
- await runTest(
- `DharmaEscapeHatchRegistry will not fire an event when removing an unset escape hatch account`,
- DharmaEscapeHatchRegistry,
- 'removeEscapeHatch'
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms that escape hatch functionality is not initially disabled`,
- DharmaEscapeHatchRegistry,
- 'hasDisabledEscapeHatchForSmartWallet',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value)
- },
- originalAddress
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry cannot get disabled status for null address`,
- DharmaEscapeHatchRegistry,
- 'hasDisabledEscapeHatchForSmartWallet',
- 'call',
- [constants.NULL_ADDRESS],
- false
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can reset an escape hatch account`,
- DharmaEscapeHatchRegistry,
- 'setEscapeHatch',
- 'send',
- [ownerOne]
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can get an escape hatch account once reset`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatch',
- 'call',
- [],
- true,
- value => {
- assert.ok(value.exists)
- assert.strictEqual(value.escapeHatch, ownerOne)
- }
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry setting an existing escape hatch account is a no-op`,
- DharmaEscapeHatchRegistry,
- 'setEscapeHatch',
- 'send',
- [ownerOne]
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry can disable the escape hatch mechanism`,
- DharmaEscapeHatchRegistry,
- 'permanentlyDisableEscapeHatch'
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms that escape hatch functionality is disabled`,
- DharmaEscapeHatchRegistry,
- 'hasDisabledEscapeHatchForSmartWallet',
- 'call',
- [address],
- true,
- value => {
- assert.ok(value)
- },
- originalAddress
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms that an escape hatch is successfully removed when disabling`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatch',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.exists)
- assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS)
- }
- )
-
- fallbackEscapeHatch = await web3.eth.call({
- to: DharmaEscapeHatchRegistry.options.address,
- from: address,
- data: "0x"
- })
-
- console.log(
- ' ✓ DharmaEscapeHatchRegistry can gets null address for removed escape hatch account after disabling using the fallback'
- )
- assert.strictEqual(
- web3.eth.abi.decodeParameter('address', fallbackEscapeHatch),
- constants.NULL_ADDRESS
- )
- passed++
-
- await runTest(
- `DharmaEscapeHatchRegistry confirms escape hatch is removed after disabling for for a specific smart wallet`,
- DharmaEscapeHatchRegistry,
- 'getEscapeHatchForSmartWallet',
- 'call',
- [address],
- true,
- value => {
- assert.ok(!value.exists)
- assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS)
- },
- originalAddress
- )
-
- await runTest(
- `DharmaEscapeHatchRegistry cannot set an escape hatch account once disabled`,
- DharmaEscapeHatchRegistry,
- 'setEscapeHatch',
- 'send',
- [ownerTwo],
- false
- )
+ await tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.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 tester.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(
- `DharmaEscapeHatchRegistry cannot remove an escape hatch account once disabled`,
- DharmaEscapeHatchRegistry,
- 'removeEscapeHatch',
- 'send',
- [],
- false
- )
+ await tester.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 = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.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 => {},
+ tester.originalAddress
+ );
+
+ await tester.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
+ tester.addressTwo,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- await runTest(
- `DharmaEscapeHatchRegistry cannot re-disable an escape hatch account once disabled`,
- DharmaEscapeHatchRegistry,
- 'permanentlyDisableEscapeHatch',
- 'send',
- [],
- false
- )
+ await tester.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
+ tester.addressTwo,
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ setUserSigningKeyUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can set a new user signing key with signatures",
+ UserSmartWalletV6,
+ "setUserSigningKey",
+ "send",
+ [
+ tester.addressTwo,
+ 0,
+ setUserSigningKeyUserSignature,
+ setUserSigningKeyDharmaSignature
+ ],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get next custom action ID to cancel",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // Cancel
+ constants.FULL_APPROVAL, // This value shouldn't matter
+ tester.originalAddress, // This value shouldn't matter either
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- await runTest(
- `DharmaAccountRecoveryManagerV2 owner can start ownership transfer to multisig`,
- DharmaAccountRecoveryManagerV2,
- 'transferOwnership',
- 'send',
- [DharmaAccountRecoveryMultisig.options.address]
+ await tester.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
+ tester.addressTwo, // This one too
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ cancelUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet secondary can cancel using a signature",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ [0, cancelUserSignature],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "UserSmartWallet nonce is incremented after cancelling",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(parseInt(value), parseInt(currentNonce) + 1);
+ }
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet secondary cannot call to withdraw dai without primary",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ ["1000000000000000000", tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet secondary cannot call to withdraw usdc without primary",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [1, tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet secondary can no longer call to set userSigningKey without primary",
+ UserSmartWalletV6,
+ "setUserSigningKey",
+ "send",
+ [tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "1", // dust
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ 'V6 UserSmartWallet relay cannot withdraw "dust" USDC',
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.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 = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.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)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "100000",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with two signatures to withdraw USDC",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ "100000",
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad signature to withdraw USDC",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ "0xffffffff" + usdcWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet cannot call with bad user signature to withdraw USDC",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ "0xffffffff" + usdcUserWithdrawalSignature.slice(10),
+ usdcWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with two signatures to withdraw max USDC",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.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
)
- rawData = DharmaAccountRecoveryManagerV2.methods.acceptOwnership().encodeABI()
- await runTest(
- `DharmaAccountRecoveryMultisig can get a hash`,
- DharmaAccountRecoveryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
+ const saiWithdrawalSignature = tester.signHashedPrefixedHashedHexString(
+ withdrawalMessage,
+ address
)
+ */
- // accept ownership
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaAccountRecoveryMultisig can call execute to accept ownership`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ let daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ let daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ 'V6 UserSmartWallet relay cannot withdraw "dust" dai',
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.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 = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot withdraw dai to null address",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000",
+ constants.NULL_ADDRESS,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1000000000000000",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with signature to withdraw dai",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000",
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ 'V6 UserSmartWallet cannot get a non-custom "custom" next action ID',
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 2, // Generic,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ false
+ );
+
+ await tester.runTest(
+ 'V6 UserSmartWallet cannot get a non-custom "custom" action ID',
+ UserSmartWalletV6,
+ "getCustomActionID",
+ "call",
+ [
+ 2, // Generic,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ 0
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad signature to withdraw dai",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ "0xffffffff" + daiWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad user signature to withdraw dai",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ "0xffffffff" + daiUserWithdrawalSignature.slice(10),
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with signature to withdraw sai",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "0", // no amount
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot to withdraw ether with no amount",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "0",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ constants.NULL_ADDRESS, // no recipient
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot to withdraw ether with no recipient",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ constants.NULL_ADDRESS,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad signature to withdraw eth",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ "0xffffffff" + ethWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ "0xffffffff" + ethUserWithdrawalSignature.slice(10),
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with signature to withdraw ether",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad signature to withdraw eth",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ "0xffffffff" + ethWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot call with bad user signature to withdraw eth",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ "0xffffffff" + ethUserWithdrawalSignature.slice(10),
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with signature to withdraw ether",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet cancel reverts with bad signature",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ [0, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet calls revert if insufficient action gas is supplied",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ [constants.FULL_APPROVAL, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet calls succeed if sufficient non-zero action gas supplied",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ ["1", "0x"]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a cancel custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // Cancel,
+ "0",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ cancelSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can cancel using a signature",
+ UserSmartWalletV6,
+ "cancel",
+ "send",
+ ["0", cancelSignature],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet calls to atomic methods revert",
+ UserSmartWalletV6,
+ "_withdrawDaiAtomic",
+ "send",
+ ["1", tester.address],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet calls to recover from random address revert",
+ UserSmartWalletV6,
+ "recover",
+ "send",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy a V6 smart wallet using a Dharma Key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [tester.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,
+ tester.addressTwo
+ );
+ //console.log(events)
+
+ // TODO: test more events
+ }
+ }
+ );
- await runTest(
- `DharmaAccountRecoveryManagerV2 owner is now set to multisig`,
- DharmaAccountRecoveryManagerV2,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, DharmaAccountRecoveryMultisig.options.address)
- }
- )
+ await tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.USDC.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet cannot call executeAction and target a non-contract",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet cannot call executeAction and target itself",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ UserSmartWalletV6.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.USDC.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get the next generic batch action ID",
+ UserSmartWalletV6,
+ "getNextGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- // TODO: test account recovery using the multisig?
-
- // transfer ownership back
- rawData = DharmaAccountRecoveryManagerV2.methods.transferOwnership(address).encodeABI()
- await runTest(
- `DharmaAccountRecoveryMultisig can get a hash`,
- DharmaAccountRecoveryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
- )
+ await tester.runTest(
+ "V6 UserSmartWallet generic batch action ID with nonce matches next ID",
+ UserSmartWalletV6,
+ "getGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeActionWithAtomicBatchCalls",
+ UserSmartWalletV6,
+ "executeActionWithAtomicBatchCalls",
+ "send",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "USDC Whale can deposit usdc into the deployed smart wallet",
+ tester.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 tester.runTest(
+ "new 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, "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");
+ }
+ }
+ );
+
+ await tester.runTest(
+ "Check blacklister address",
+ tester.FIAT_TOKEN,
+ "blacklister",
+ "call",
+ [],
+ true,
+ value => {
+ blacklister = value;
+ }
+ );
+
+ await tester.runTest(
+ "Check pauser address",
+ tester.FIAT_TOKEN,
+ "pauser",
+ "call",
+ [],
+ true,
+ value => {
+ pauser = value;
+ }
+ );
+
+ await tester.runTest(
+ "blacklist mock address",
+ tester.FIAT_TOKEN,
+ "blacklist",
+ "send",
+ [constants.MOCK_USDC_BLACKLISTED_ADDRESS],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.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 BlacklistedUserSmartWalletV6 = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ targetBlacklistAddress
+ );
+
+ await tester.runTest(
+ "USDC Whale can deposit usdc into the yet-to-be-blacklisted smart wallet",
+ tester.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 tester.runTest(
+ "blacklist counterfactual deployment address",
+ tester.FIAT_TOKEN,
+ "blacklist",
+ "send",
+ [targetBlacklistAddress],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.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 tester.runTest(
+ "blacklisted smart wallet will not approve USDC during repayAndDeposit",
+ BlacklistedUserSmartWalletV6,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "un-blacklist counterfactual deployment address",
+ tester.FIAT_TOKEN,
+ "unBlacklist",
+ "send",
+ [targetBlacklistAddress],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.runTest(
+ "pause USDC",
+ tester.FIAT_TOKEN,
+ "pause",
+ "send",
+ [],
+ true,
+ receipt => {},
+ pauser
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet attempt to withdraw max USDC when paused causes ExternalError",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "smart wallet will not approve USDC when paused during repayAndDeposit",
+ BlacklistedUserSmartWalletV6,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "unpause USDC",
+ tester.FIAT_TOKEN,
+ "unpause",
+ "send",
+ [],
+ true,
+ receipt => {},
+ pauser
+ );
+
+ await tester.runTest(
+ "unblacklisted, unpaused smart wallet approves USDC during repayAndDeposit",
+ BlacklistedUserSmartWalletV6,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaAccountRecoveryMultisig can call execute to transfer ownership back`,
- DharmaAccountRecoveryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ await tester.runTest(
+ "V6 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ web3.utils.toWei("50", "lovelace"),
+ constants.MOCK_USDC_BLACKLISTED_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay call to withdraw USDC to blacklisted address",
+ UserSmartWalletV6,
+ "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)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ UserSmartWalletV6.options.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay call to withdraw USDC to itself",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ UserSmartWalletV6.options.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ constants.MOCK_USDC_BLACKLISTED_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay call to withdraw USDC to blacklisted address",
+ UserSmartWalletV6,
+ "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)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ targetWalletAddress,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot withdraw eth to a non-payable account",
+ UserSmartWalletV6,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ targetWalletAddress,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.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 tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy a V6 smart wallet using a contract key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [targetWalletAddress]
+ );
+
+ const UserSmartWalletV6Two = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ targetWalletAddressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet cancel reverts with bad contract signature",
+ UserSmartWalletV6Two,
+ "cancel",
+ "send",
+ [0, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.SAI.options.address,
+ tester.SAI.methods
+ .transfer(tester.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.SAI.options.address,
+ tester.SAI.methods
+ .transfer(tester.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1000000000000000000",
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot withdraw to the null address",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000000",
+ constants.NULL_ADDRESS,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay cannot withdraw too much dai",
+ UserSmartWalletV6,
+ "withdrawDai",
+ "send",
+ [
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet relay can call with two signatures to withdraw USDC",
+ UserSmartWalletV6,
+ "withdrawUSDC",
+ "send",
+ [
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get next generic batch action ID",
+ UserSmartWalletV6,
+ "getNextGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.DAI.options.address,
+ data: tester.DAI.methods
+ .transfer(
+ tester.address,
+ "100000000000000000000000000000"
+ )
+ .encodeABI()
+ }
+ ],
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure",
+ UserSmartWalletV6,
+ "executeActionWithAtomicBatchCalls",
+ "send",
+ [
+ [
+ {
+ to: tester.DAI.options.address,
+ data: tester.DAI.methods
+ .transfer(
+ tester.address,
+ "100000000000000000000000000000"
+ )
+ .encodeABI()
+ }
+ ],
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ true,
+ receipt => {
+ //console.log(receipt)
+ }
+ );
- await runTest(
- `DharmaAccountRecoveryManagerV2 EOA can accept ownership transfer from multisig`,
- DharmaAccountRecoveryManagerV2,
- 'acceptOwnership'
- )
+ await tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.Comptroller.options.address,
+ tester.Comptroller.methods
+ .enterMarkets([constants.CDAI_MAINNET_ADDRESS])
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction to enter dai market",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.Comptroller.options.address,
+ tester.Comptroller.methods
+ .enterMarkets([constants.CDAI_MAINNET_ADDRESS])
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "Dai Whale can deposit dai into the smart wallet",
+ tester.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 tester.runTest(
+ "V6 UserSmartWallet can trigger repayAndDeposit to deposit all new funds",
+ UserSmartWalletV6,
+ "repayAndDeposit"
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV6,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.CSAI_BORROW.options.address,
+ tester.CSAI_BORROW.methods
+ .borrow(web3.utils.toWei(".01", "ether"))
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can call executeAction to perform a borrow",
+ UserSmartWalletV6,
+ "executeAction",
+ "send",
+ [
+ tester.CSAI_BORROW.options.address,
+ tester.CSAI_BORROW.methods
+ .borrow(web3.utils.toWei(".01", "ether"))
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ true,
+ receipt => {
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V6 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV6,
+ "getNextCustomActionID",
+ "call",
+ [
+ 7, // SetEscapeHatch,
+ 0,
+ constants.NULL_ADDRESS, // no recipient
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ let escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ let escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "UserSmartWalletV6 can check the user signing key prior to upgrade",
+ UserSmartWalletV6,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWalletV6 nonce can be retrieved",
+ UserSmartWalletV6,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ originalNonce = value;
+ }
+ );
+
+ await testPerformingUpgrade(
+ tester,
+ DharmaSmartWalletImplementationV7, // new implementation
+ UserSmartWalletV7,
+ tester.DharmaUpgradeBeaconController,
+ tester.DharmaUpgradeBeacon.options.address,
+ 7
+ );
+
+ const startingBalance = {
+ dDai: 0,
+ dUSDC: 0,
+ dai: 0,
+ usdc: 0,
+ dDaiUnderlying: 0,
+ dUSDCUnderlying: 0,
+ etherRaw: "99999999999999998"
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ startingBalance,
+ startingBalance,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet can get balances",
+ UserSmartWalletV7,
+ "getBalances",
+ "call",
+ [],
+ true,
+ values => {
+ assert.strictEqual(
+ values.daiBalance,
+ startingBalance.dai.toString()
+ );
+ assert.strictEqual(
+ values.usdcBalance,
+ startingBalance.usdc.toString()
+ );
+ assert.strictEqual(
+ values.etherBalance,
+ startingBalance.etherRaw
+ );
+ assert.strictEqual(
+ values.dDaiUnderlyingDaiBalance,
+ startingBalance.dDaiUnderlying.toString()
+ );
+ assert.strictEqual(
+ values.dUsdcUnderlyingUsdcBalance,
+ startingBalance.dUSDCUnderlying.toString()
+ );
+ assert.strictEqual(values.dEtherUnderlyingEtherBalance, "0");
+ }
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet secondary can call to cancel",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ [0, "0x"]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet nonce is now set to original + 1",
+ UserSmartWalletV7,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, (parseInt(originalNonce) + 1).toString());
+ }
+ );
- await runTest(
- `DharmaAccountRecoveryManagerV2 owner is now set to EOA`,
- DharmaAccountRecoveryManagerV2,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get next custom action ID to set a user signing key",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 1, // SetUserSigningKey,
+ constants.FULL_APPROVAL, // This value shouldn't matter
+ tester.addressTwo,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can set a new user signing key with signatures",
+ UserSmartWalletV7,
+ "setUserSigningKey",
+ "send",
+ [tester.addressTwo, 0, "0x", setUserSigningKeyDharmaSignature],
+ true,
+ receipt => {},
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet has the new user signing key set",
+ UserSmartWalletV7,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.addressTwo);
+ }
+ );
- await runTest(
- `DharmaKeyRegistryV2 owner can start ownership transfer to multisig`,
- DharmaKeyRegistryV2,
- 'transferOwnership',
- 'send',
- [DharmaKeyRegistryMultisig.options.address]
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get next custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // DAIWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
- rawData = DharmaKeyRegistryV2.methods.acceptOwnership().encodeABI()
- await runTest(
- `DharmaKeyRegistryMultisig can get a hash`,
- DharmaKeyRegistryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get custom action ID and it matches next action ID",
+ UserSmartWalletV7,
+ "getCustomActionID",
+ "call",
+ [
+ 0, // DAIWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ parseInt(originalNonce) + 2,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get next generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [tester.address, "0x", 0],
+ true,
+ value => {
+ genericActionID = value;
+ }
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get generic action ID and it matches next action ID",
+ UserSmartWalletV7,
+ "getGenericActionID",
+ "call",
+ [tester.address, "0x", parseInt(originalNonce) + 2, 0],
+ true,
+ value => {
+ assert.strictEqual(value, genericActionID);
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet calls to atomic methods revert",
+ UserSmartWalletV7,
+ "_withdrawDaiAtomic",
+ "send",
+ ["1", tester.address],
+ false
+ );
+
+ // Give the Dai Whale some ETH so it can make transactions
+ await web3.eth.sendTransaction({
+ from: tester.address,
+ to: constants.DAI_WHALE_ADDRESS,
+ value: web3.utils.toWei("1", "ether"),
+ gas: testingContext !== "coverage" ? "0xffff" : tester.gasLimit - 1,
+ gasPrice: 1
+ });
+
+ await tester.runTest(
+ "Dai Whale can deposit Dai into the V7 smart wallet",
+ tester.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 tester.runTest(
+ "USDC Whale can deposit usdc into the V7 smart wallet",
+ tester.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
+ );
+
+ const preDepositBalance = {
+ dai: 100,
+ usdc: 100,
+ dDaiUnderlying: 0,
+ dUSDCUnderlying: 0
+ };
+
+ const postDepositBalance = {
+ dai: 0,
+ usdc: 0,
+ dDaiUnderlying: 100,
+ dUSDCUnderlying: 100
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preDepositBalance,
+ postDepositBalance,
+ tester.runTest,
+ [
+ "V7 user smart wallet can trigger repayAndDeposit to deposit all new funds",
+ UserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ ]
+ );
+
+ await tester.runTest(
+ "Dai Whale can deposit dai into the V7 smart wallet again",
+ tester.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 tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [constants.ESCAPE_HATCH_REGISTRY_ADDRESS, "0x", 0],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call executeAction and target Escape Hatch Registry",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ constants.ESCAPE_HATCH_REGISTRY_ADDRESS,
+ "0x",
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V7 user smart wallet repayAndDeposit can still deposit without approval",
+ UserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ );
- // accept ownership
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaKeyRegistryMultisig can call execute to accept ownership`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.CDAI.options.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V7 user smart wallet repayAndDeposit can deposit with approval added back",
+ UserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ );
+
+ await tester.runTest(
+ "V7 user smart wallet can trigger repayAndDeposit even with no funds",
+ UserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ );
- await runTest(
- `DharmaKeyRegistryV2 owner is now set to multisig`,
- DharmaKeyRegistryV2,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, DharmaKeyRegistryMultisig.options.address)
- }
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get custom action ID and it matches next action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 1, // SetUserSigningKey,
+ 0,
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ setUserSigningKeyUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot set the null address as a new user signing key",
+ UserSmartWalletV7,
+ "setUserSigningKey",
+ "send",
+ [
+ constants.NULL_ADDRESS,
+ 0,
+ setUserSigningKeyUserSignature,
+ setUserSigningKeyDharmaSignature
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get next custom action ID to set a user signing key",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 1, // SetUserSigningKey,
+ constants.FULL_APPROVAL, // This value shouldn't matter
+ tester.addressTwo,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV7,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- // TODO: test setting a new key using the multisig?
-
- // transfer ownership back
- rawData = DharmaKeyRegistryV2.methods.transferOwnership(address).encodeABI()
- await runTest(
- `DharmaKeyRegistryMultisig can get a hash`,
- DharmaKeyRegistryMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get custom action ID and it matches next action ID",
+ UserSmartWalletV7,
+ "getCustomActionID",
+ "call",
+ [
+ 1, // SetUserSigningKey,
+ 0, // Note that this value differs from above
+ tester.addressTwo,
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ setUserSigningKeyUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ setUserSigningKeyDharmaSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can set a new user signing key with signatures",
+ UserSmartWalletV7,
+ "setUserSigningKey",
+ "send",
+ [
+ tester.addressTwo,
+ 0,
+ setUserSigningKeyUserSignature,
+ setUserSigningKeyDharmaSignature
+ ],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get next custom action ID to cancel",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // Cancel
+ constants.FULL_APPROVAL, // This value shouldn't matter
+ tester.originalAddress, // This value shouldn't matter either
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV7,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaKeyRegistryMultisig can call execute to transfer ownership back`,
- DharmaKeyRegistryMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get custom action ID and it matches next action ID",
+ UserSmartWalletV7,
+ "getCustomActionID",
+ "call",
+ [
+ 0, // Cancel
+ 0, // Note that this value differs from above
+ tester.addressTwo, // This one too
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ cancelUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet secondary can cancel using a signature",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ [0, cancelUserSignature],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "UserSmartWallet nonce is incremented after cancelling",
+ UserSmartWalletV7,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(parseInt(value), parseInt(currentNonce) + 1);
+ }
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet secondary cannot call to withdraw dai without primary",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ ["1000000000000000000", tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet secondary cannot call to withdraw usdc without primary",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [1, tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet secondary can no longer call to set userSigningKey without primary",
+ UserSmartWalletV7,
+ "setUserSigningKey",
+ "send",
+ [tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "1", // dust
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ 'V7 UserSmartWallet relay cannot withdraw "dust" USDC',
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "100000",
+ constants.NULL_ADDRESS, // bad recipient
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot withdraw USDC to null address",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ "100000",
+ constants.NULL_ADDRESS,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "1000000",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ const preUSDCWithdrawalBalance = {
+ dUSDCUnderlying: 100
+ };
+
+ const postUSDCWithdrawalBalance = {
+ dUSDCUnderlying: 99
+ };
+
+ const recipientUSDCBalance = (await tester.getBalances(tester.address))
+ .usdc;
+
+ const preUSDCWithdrawalRecipientBalance = {
+ usdc: recipientUSDCBalance
+ };
+
+ const postUSDCWithdrawalRecipientBalance = {
+ usdc: recipientUSDCBalance + 1
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preUSDCWithdrawalBalance,
+ postUSDCWithdrawalBalance,
+ tester.withBalanceCheck,
+ [
+ tester.address,
+ preUSDCWithdrawalRecipientBalance,
+ postUSDCWithdrawalRecipientBalance,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can call with two signatures to withdraw USDC",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ "1000000",
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ ]
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad signature to withdraw USDC",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ "0xffffffff" + usdcWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call with bad user signature to withdraw USDC",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ "0xffffffff" + usdcUserWithdrawalSignature.slice(10),
+ usdcWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can call with two signatures to withdraw max USDC",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ 'V7 UserSmartWallet relay cannot withdraw "dust" dai',
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1000000000000000",
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot withdraw dai to null address",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000",
+ constants.NULL_ADDRESS,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1000000000000000000",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
- await runTest(
- `DharmaKeyRegistryV2 EOA can accept ownership transfer from multisig`,
- DharmaKeyRegistryV2,
- 'acceptOwnership'
- )
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
- await runTest(
- `DharmaKeyRegistryV2 owner is now set to EOA`,
- DharmaKeyRegistryV2,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner is initially set to an EOA`,
- DharmaUpgradeBeaconControllerManager,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
+ const preDAIWithdrawalBalance = {
+ dDaiUnderlying: 200
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can start ownership transfer to multisig`,
- DharmaUpgradeBeaconControllerManager,
- 'transferOwnership',
- 'send',
- [DharmaUpgradeMultisig.options.address]
- )
+ const postDAIWithdrawalBalance = {
+ dDaiUnderlying: 199
+ };
- rawData = DharmaUpgradeBeaconControllerManager.methods.acceptOwnership().encodeABI()
- await runTest(
- `DharmaUpgradeMultisig can get a hash`,
- DharmaUpgradeMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
- )
+ const recipientDAIBalance = (await tester.getBalances(tester.address)).dai;
- // accept ownership
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaUpgradeMultisig can call execute to accept ownership`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ const preDAIWithdrawalRecipientBalance = {
+ dai: recipientDAIBalance
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner is now set to multisig`,
- DharmaUpgradeBeaconControllerManager,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, DharmaUpgradeMultisig.options.address)
- }
- )
+ const postDAIWithdrawalRecipientBalance = {
+ dai: recipientDAIBalance + 1
+ };
- // TODO: test an upgrade, rollback, etc with the multisig?
-
- // transfer ownership back
- rawData = DharmaUpgradeBeaconControllerManager.methods.transferOwnership(address).encodeABI()
- await runTest(
- `DharmaUpgradeMultisig can get a hash`,
- DharmaUpgradeMultisig,
- 'getNextHash',
- 'call',
- [rawData, address, executorGasLimit],
- true,
- value => {
- hash = value
- }
- )
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preDAIWithdrawalBalance,
+ postDAIWithdrawalBalance,
+ tester.withBalanceCheck,
+ [
+ tester.address,
+ preDAIWithdrawalRecipientBalance,
+ postDAIWithdrawalRecipientBalance,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can call with two signatures to withdraw DAI",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000000",
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ ]
+ ]
+ );
+
+ await tester.runTest(
+ 'V7 UserSmartWallet cannot get a non-custom "custom" next action ID',
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 2, // Generic,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ false
+ );
+
+ await tester.runTest(
+ 'V7 UserSmartWallet cannot get a non-custom "custom" action ID',
+ UserSmartWalletV7,
+ "getCustomActionID",
+ "call",
+ [
+ 2, // Generic,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ 0
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad signature to withdraw dai",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ "0xffffffff" + daiWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad user signature to withdraw dai",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ "0xffffffff" + daiUserWithdrawalSignature.slice(10),
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can call with signature to withdraw sai",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "0", // no amount
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot to withdraw ether with no amount",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "0",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ constants.NULL_ADDRESS, // no recipient
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot to withdraw ether with no recipient",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ constants.NULL_ADDRESS,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad signature to withdraw eth",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ "0xffffffff" + ethWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad user signature to withdraw eth",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ "0xffffffff" + ethUserWithdrawalSignature.slice(10),
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can call with signature to withdraw ether",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad signature to withdraw eth",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ "0xffffffff" + ethWithdrawalSignature.slice(10)
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot call with bad user signature to withdraw eth",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ "0xffffffff" + ethUserWithdrawalSignature.slice(10),
+ ethWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can call with signature to withdraw ether",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cancel reverts with bad signature",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ [0, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet calls revert if insufficient action gas is supplied",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ [constants.FULL_APPROVAL, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet calls succeed if sufficient non-zero action gas supplied",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ ["1", "0x"]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a cancel custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 0, // Cancel,
+ "0",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ cancelSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can cancel using a signature",
+ UserSmartWalletV7,
+ "cancel",
+ "send",
+ ["0", cancelSignature],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet calls to atomic methods revert",
+ UserSmartWalletV7,
+ "_withdrawDaiAtomic",
+ "send",
+ ["1", tester.address],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet calls to recover from random address revert",
+ UserSmartWalletV7,
+ "recover",
+ "send",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy a V7 smart wallet using a Dharma Key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [tester.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,
+ tester.addressTwo
+ );
+ //console.log(events)
+
+ // TODO: test more events
+ }
+ }
+ );
- ownerOneSig = signHashedPrefixedHexString(hash, ownerOne)
- ownerTwoSig = signHashedPrefixedHexString(hash, ownerTwo)
- ownerThreeSig = signHashedPrefixedHexString(hash, ownerThree)
- ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2)
-
- await runTest(
- `DharmaUpgradeMultisig can call execute to transfer ownership back`,
- DharmaUpgradeMultisig,
- 'execute',
- 'send',
- [rawData, address, executorGasLimit, ownerSigs]
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.USDC.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call executeAction and target a non-contract",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call executeAction and target itself",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ false
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.USDC.options.address,
+ tester.USDC.methods
+ .approve(tester.CUSDC.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get the next generic batch action ID",
+ UserSmartWalletV7,
+ "getNextGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ await tester.runTest(
+ "UserSmartWallet can get the nonce",
+ UserSmartWalletV7,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ currentNonce = value;
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager EOA can accept ownership transfer from multisig`,
- DharmaUpgradeBeaconControllerManager,
- 'acceptOwnership'
- )
+ await tester.runTest(
+ "V7 UserSmartWallet generic batch action ID with nonce matches next ID",
+ UserSmartWalletV7,
+ "getGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ currentNonce,
+ 0
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, customActionId);
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeActionWithAtomicBatchCalls",
+ UserSmartWalletV7,
+ "executeActionWithAtomicBatchCalls",
+ "send",
+ [
+ [
+ {
+ to: tester.SAI.options.address,
+ data: tester.SAI.methods.totalSupply().encodeABI()
+ }
+ ],
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "USDC Whale can deposit usdc into the deployed smart wallet",
+ tester.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 tester.runTest(
+ "new user smart wallet can trigger repayAndDeposit to deposit all new funds",
+ UserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ );
+
+ await tester.runTest(
+ "Check blacklister address",
+ tester.FIAT_TOKEN,
+ "blacklister",
+ "call",
+ [],
+ true,
+ value => {
+ blacklister = value;
+ }
+ );
+
+ await tester.runTest(
+ "Check pauser address",
+ tester.FIAT_TOKEN,
+ "pauser",
+ "call",
+ [],
+ true,
+ value => {
+ pauser = value;
+ }
+ );
+
+ await tester.runTest(
+ "blacklist mock address",
+ tester.FIAT_TOKEN,
+ "blacklist",
+ "send",
+ [constants.MOCK_USDC_BLACKLISTED_ADDRESS],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.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 BlacklistedUserSmartWalletV7 = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV7Artifact.abi,
+ targetBlacklistAddress
+ );
+
+ await tester.runTest(
+ "USDC Whale can deposit usdc into the yet-to-be-blacklisted smart wallet",
+ tester.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 tester.runTest(
+ "blacklist counterfactual deployment address",
+ tester.FIAT_TOKEN,
+ "blacklist",
+ "send",
+ [targetBlacklistAddress],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.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 tester.runTest(
+ "blacklisted smart wallet will not approve USDC during repayAndDeposit",
+ BlacklistedUserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "un-blacklist counterfactual deployment address",
+ tester.FIAT_TOKEN,
+ "unBlacklist",
+ "send",
+ [targetBlacklistAddress],
+ true,
+ receipt => {},
+ blacklister
+ );
+
+ await tester.runTest(
+ "pause USDC",
+ tester.FIAT_TOKEN,
+ "pause",
+ "send",
+ [],
+ true,
+ receipt => {},
+ pauser
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet attempt to withdraw max USDC when paused causes ExternalError",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "smart wallet will not approve USDC when paused during repayAndDeposit",
+ BlacklistedUserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "unpause USDC",
+ tester.FIAT_TOKEN,
+ "unpause",
+ "send",
+ [],
+ true,
+ receipt => {},
+ pauser
+ );
+
+ await tester.runTest(
+ "unblacklisted, unpaused smart wallet approves USDC during repayAndDeposit",
+ BlacklistedUserSmartWalletV7,
+ "repayAndDeposit",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner is now set to EOA`,
- DharmaUpgradeBeaconControllerManager,
- 'owner',
- 'call',
- [],
- true,
- value => {
- assert.strictEqual(value, address)
- }
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ web3.utils.toWei("50", "lovelace"),
+ constants.MOCK_USDC_BLACKLISTED_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay call to withdraw USDC to blacklisted address",
+ UserSmartWalletV7,
+ "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)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ UserSmartWalletV7.options.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay call to withdraw USDC to itself",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ constants.FULL_APPROVAL,
+ UserSmartWalletV7.options.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a blacklisted USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ constants.FULL_APPROVAL,
+ constants.MOCK_USDC_BLACKLISTED_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay call to withdraw USDC to blacklisted address",
+ UserSmartWalletV7,
+ "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)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Ether withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 6, // ETHWithdrawal,
+ "1",
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
- // Transfer smart wallet controller ownership to coverage manager
- await runTest(
- `DharmaUpgradeBeaconController can transfer ownership to manager`,
- DharmaUpgradeBeaconController,
- 'transferOwnership',
- 'send',
- [DharmaUpgradeBeaconControllerManagerCoverage.options.address]
- )
+ ethWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when it doesn't own keyring controller`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false
- )
+ ethUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
- await runTest(
- `DharmaKeyRingUpgradeBeaconController can transfer ownership to manager`,
- DharmaKeyRingUpgradeBeaconController,
- 'transferOwnership',
- 'send',
- [DharmaUpgradeBeaconControllerManagerCoverage.options.address]
- )
+ const preETHwithdrawalBalance = {
+ etherRaw: "99999999999999996"
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager can activate Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency'
- )
+ const postETHWithdrawalBalance = {
+ etherRaw: "99999999999999995"
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get contingency status when activated`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'contingencyStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.armed)
- assert.ok(value.activated)
- //assert.strictEqual(value.activationTime, '?')
- }
- )
+ const recipientETHBalance = (await tester.getBalances(tester.address))
+ .etherRaw;
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can re-arm an active Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
+ const preETHWithdrawalRecipientBalance = {
+ etherRaw: recipientETHBalance
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot activate Adharma Contingency when already active`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- false
- )
+ const recipientBalance = web3.utils.toBN(recipientETHBalance).add(ONE);
- await runTest(
- `DharmaUpgradeBeaconControllerManager now gets a prior implementation count`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getTotalPriorImplementations',
- 'call',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address
- ],
- true,
- value => {
- assert.strictEqual(value, '1')
- }
- )
+ const postETHWithdrawalRecipientBalance = {
+ etherRaw: recipientBalance.toString()
+ };
- await runTest(
- `DharmaUpgradeBeaconControllerManager can get the initial prior implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'getPriorImplementation',
- 'call',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ],
- true,
- value => {
- assert.strictEqual(
- value.priorImplementation,
- AdharmaSmartWalletImplementation.options.address
- )
- assert.ok(value.rollbackAllowed)
- }
- )
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preETHwithdrawalBalance,
+ postETHWithdrawalBalance,
+ tester.withBalanceCheck,
+ [
+ tester.address,
+ preETHWithdrawalRecipientBalance,
+ postETHWithdrawalRecipientBalance,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can call with two signatures to withdraw ETH",
+ UserSmartWalletV7,
+ "withdrawEther",
+ "send",
+ [
+ "1",
+ tester.address,
+ 0,
+ ethUserWithdrawalSignature,
+ ethWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ ]
+ ]
+ );
+
+ await tester.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 tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy a V7 smart wallet using a contract key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [targetWalletAddress]
+ );
+
+ const UserSmartWalletV7Two = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV7Artifact.abi,
+ targetWalletAddressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cancel reverts with bad contract signature",
+ UserSmartWalletV7Two,
+ "cancel",
+ "send",
+ [0, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.SAI.options.address,
+ tester.SAI.methods
+ .transfer(tester.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.SAI.options.address,
+ tester.SAI.methods
+ .transfer(tester.address, constants.FULL_APPROVAL)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "1000000000000000000",
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot withdraw to the null address",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ "1000000000000000000",
+ constants.NULL_ADDRESS,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a Dai withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 10, // DaiWithdrawal
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ daiWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ daiUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot withdraw too much dai",
+ UserSmartWalletV7,
+ "withdrawDai",
+ "send",
+ [
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0,
+ daiUserWithdrawalSignature,
+ daiWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a USDC withdrawal custom action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 5, // USDCWithdrawal,
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ usdcWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ usdcUserWithdrawalSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can call with two signatures to withdraw USDC",
+ UserSmartWalletV7,
+ "withdrawUSDC",
+ "send",
+ [
+ "100000000000000000000000000000000000000", // too much
+ tester.address,
+ 0,
+ usdcUserWithdrawalSignature,
+ usdcWithdrawalSignature
+ ],
+ true,
+ receipt => {
+ // TODO: verify logs
+ //console.log(receipt)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get next generic batch action ID",
+ UserSmartWalletV7,
+ "getNextGenericAtomicBatchActionID",
+ "call",
+ [
+ [
+ {
+ to: tester.DAI.options.address,
+ data: tester.DAI.methods
+ .transfer(
+ tester.address,
+ "100000000000000000000000000000"
+ )
+ .encodeABI()
+ }
+ ],
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet bad executeActionWithAtomicBatchCalls emits CallFailure",
+ UserSmartWalletV7,
+ "executeActionWithAtomicBatchCalls",
+ "send",
+ [
+ [
+ {
+ to: tester.DAI.options.address,
+ data: tester.DAI.methods
+ .transfer(
+ tester.address,
+ "100000000000000000000000000000"
+ )
+ .encodeABI()
+ }
+ ],
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ true,
+ receipt => {
+ //console.log(receipt)
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call "exitAdharmaContingency" before 48 hours has elapsed`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- address,
- address
- ],
- false
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.Comptroller.options.address,
+ tester.Comptroller.methods
+ .enterMarkets([constants.CDAI_MAINNET_ADDRESS])
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction to enter dai market",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.Comptroller.options.address,
+ tester.Comptroller.methods
+ .enterMarkets([constants.CDAI_MAINNET_ADDRESS])
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "Dai Whale can deposit dai into the smart wallet",
+ tester.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 tester.runTest(
+ "V7 UserSmartWallet can trigger repayAndDeposit to deposit all new funds",
+ UserSmartWalletV7,
+ "repayAndDeposit"
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.CSAI_BORROW.options.address,
+ tester.CSAI_BORROW.methods
+ .borrow(web3.utils.toWei(".01", "ether"))
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction to perform a borrow",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.CSAI_BORROW.options.address,
+ tester.CSAI_BORROW.methods
+ .borrow(web3.utils.toWei(".01", "ether"))
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ],
+ true,
+ receipt => {
+ //console.log(receipt.events)
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 7, // SetEscapeHatch,
+ 0,
+ constants.NULL_ADDRESS, // no recipient
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot set an escape hatch with no account",
+ UserSmartWalletV7,
+ "setEscapeHatch",
+ "send",
+ [
+ constants.NULL_ADDRESS,
+ 0,
+ escapeHatchUserSignature,
+ escapeHatchSignature
+ ],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 7, // SetEscapeHatch,
+ 0,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call escape before escape hatch is set",
+ UserSmartWalletV7,
+ "escape",
+ "send",
+ [],
+ false,
+ receipt => {
+ // TODO: verify logs
+ }
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can set an escape hatch",
+ UserSmartWalletV7,
+ "setEscapeHatch",
+ "send",
+ [tester.address, 0, escapeHatchUserSignature, escapeHatchSignature],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet non-escape hatch account cannot call escape",
+ UserSmartWalletV7,
+ "escape",
+ "send",
+ [],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ const allPreEscapeBalances = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+ const preEscapeBalances = {
+ dDai: allPreEscapeBalances.dDai,
+ dUSDC: allPreEscapeBalances.dUSDC,
+ dai: allPreEscapeBalances.dai,
+ usdc: allPreEscapeBalances.usdc,
+ sai: allPreEscapeBalances.sai,
+ cDai: allPreEscapeBalances.cDai,
+ cUSDC: allPreEscapeBalances.cUSDC,
+ cSai: allPreEscapeBalances.cSai
+ // TODO: test raw balances
+ };
+
+ const postEscapeBalances = {
+ dDai: 0,
+ dUSDC: 0,
+ dai: 0,
+ usdc: 0,
+ sai: 0,
+ cDai: 0,
+ cUSDC: 0,
+ cSai: 0
+ };
+
+ const allRecipientPreEscapeBalances = await tester.getBalances(
+ tester.address
+ );
+ const recipientPreEscapeBalances = {
+ dDai: allRecipientPreEscapeBalances.dDai,
+ dUSDC: allRecipientPreEscapeBalances.dUSDC,
+ dai: allRecipientPreEscapeBalances.dai,
+ usdc: allRecipientPreEscapeBalances.usdc,
+ sai: allRecipientPreEscapeBalances.sai,
+ cDai: allRecipientPreEscapeBalances.cDai,
+ cUSDC: allRecipientPreEscapeBalances.cUSDC,
+ cSai: allRecipientPreEscapeBalances.cSai
+ // TODO: test raw balances
+ };
+ let recipientPostEscapeBalances = {};
+
+ // Add all pre-escape balances, to recipient current balances
+ for (let token of Object.keys(preEscapeBalances)) {
+ recipientPostEscapeBalances[token] =
+ preEscapeBalances[token] + recipientPreEscapeBalances[token];
+ }
+
+ // Correct dToken and underlying values since dTokens get converted to underlying.
+ recipientPostEscapeBalances["dai"] =
+ recipientPostEscapeBalances["dai"] + preEscapeBalances["dDai"];
+ recipientPostEscapeBalances["usdc"] =
+ recipientPostEscapeBalances["usdc"] + preEscapeBalances["dUSDC"];
+ recipientPostEscapeBalances["dDai"] = 0;
+ recipientPostEscapeBalances["dUSDC"] = 0;
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preEscapeBalances,
+ postEscapeBalances,
+ tester.withBalanceCheck,
+ [
+ tester.address,
+ recipientPreEscapeBalances,
+ recipientPostEscapeBalances,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet escape hatch account can call escape",
+ UserSmartWalletV7,
+ "escape",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.address
+ ]
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet escape hatch account can call escape again",
+ UserSmartWalletV7,
+ "escape",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.address
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 8, // RemoveEscapeHatch,
+ 0,
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can remove an escape hatch",
+ UserSmartWalletV7,
+ "removeEscapeHatch",
+ "send",
+ [0, escapeHatchUserSignature, escapeHatchSignature],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cannot call escape once escape hatch is removed",
+ UserSmartWalletV7,
+ "escape",
+ "send",
+ [],
+ false,
+ receipt => {
+ // TODO: verify logs
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager can rollback to initial prior implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ]
- )
+ await tester.runTest(
+ "V7 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 9, // DisableEscapeHatch,
+ 0,
+ constants.NULL_ADDRESS,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can disable the escape hatch",
+ UserSmartWalletV7,
+ "permanentlyDisableEscapeHatch",
+ "send",
+ [0, escapeHatchUserSignature, escapeHatchSignature],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get an escape hatch action ID",
+ UserSmartWalletV7,
+ "getNextCustomActionID",
+ "call",
+ [
+ 7, // SetEscapeHatch,
+ 0,
+ tester.address,
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ escapeHatchSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ escapeHatchUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay cannot set an escape hatch once disabled",
+ UserSmartWalletV7,
+ "setEscapeHatch",
+ "send",
+ [tester.address, 0, escapeHatchUserSignature, escapeHatchSignature],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "grant allowance in order to mint cSai",
+ tester.SAI,
+ "approve",
+ "send",
+ [tester.CSAI.options.address, web3.utils.toWei("100", "ether")]
+ );
+
+ await tester.runTest("mint cSai", tester.CSAI_MINT, "mint", "send", [
+ web3.utils.toWei("100", "ether")
+ ]);
+
+ // console.log(await tester.getBalances(tester.address));
+
+ await tester.runTest(
+ "cSai can be sent to V7 UserSmartWallet",
+ tester.CSAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "gwei")]
+ );
+
+ const walletBalance = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+ assert.strictEqual(walletBalance.cSai, 10.0);
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get next generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [tester.address, "0x", 0],
+ true,
+ value => {
+ genericActionID = value;
+ }
+ );
+
+ let allPreMigrationBalances = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+
+ let dDaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.dDaiUnderlyingRaw
+ );
+ let cSaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.cSaiUnderlyingRaw
+ );
+ let preMigrationBalances = {
+ dDaiUnderlyingRaw: dDaiUnderlyingRaw.toString(),
+ cSaiUnderlyingRaw: cSaiUnderlyingRaw.toString()
+ };
+
+ let postDDaiUnderlyingRaw = dDaiUnderlyingRaw.add(cSaiUnderlyingRaw);
+ let postMigrationBalances = {
+ dDaiUnderlyingRaw: postDDaiUnderlyingRaw.toString(),
+ cSaiUnderlyingRaw: ZERO.toString()
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preMigrationBalances,
+ postMigrationBalances,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can trigger cSai to dDai migration",
+ UserSmartWalletV7,
+ "migrateCSaiToDDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can trigger cSai to dDai migration again (no-op)",
+ UserSmartWalletV7,
+ "migrateCSaiToDDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "cDai can be sent to V7 UserSmartWallet",
+ tester.CDAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "mwei")]
+ );
+
+ allPreMigrationBalances = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+
+ dDaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.dDaiUnderlyingRaw
+ );
+ let cDaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.cDaiUnderlyingRaw
+ );
+ preMigrationBalances = {
+ dDaiUnderlyingRaw: dDaiUnderlyingRaw.toString(),
+ cDaiUnderlyingRaw: cDaiUnderlyingRaw.toString()
+ };
+
+ postDDaiUnderlyingRaw = dDaiUnderlyingRaw.add(cDaiUnderlyingRaw);
+ postMigrationBalances = {
+ dDaiUnderlyingRaw: postDDaiUnderlyingRaw.toString(),
+ cDaiUnderlyingRaw: ZERO.toString()
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preMigrationBalances,
+ postMigrationBalances,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can trigger cDai to dDai migration",
+ UserSmartWalletV7,
+ "migrateCDaiToDDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can get a generic action ID",
+ UserSmartWalletV7,
+ "getNextGenericActionID",
+ "call",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.DDAI.options.address, 0)
+ .encodeABI(),
+ 0
+ ],
+ true,
+ value => {
+ customActionId = value;
+ }
+ );
+
+ executeActionSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.address
+ );
+
+ executeActionUserSignature = tester.signHashedPrefixedHexString(
+ customActionId,
+ tester.addressTwo
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet can call executeAction",
+ UserSmartWalletV7,
+ "executeAction",
+ "send",
+ [
+ tester.DAI.options.address,
+ tester.DAI.methods
+ .approve(tester.DDAI.options.address, 0)
+ .encodeABI(),
+ 0,
+ executeActionUserSignature,
+ executeActionSignature
+ ]
+ );
+
+ await tester.runTest(
+ "Check DAI allowance from DDAI is 0",
+ tester.DAI,
+ "allowance",
+ "call",
+ [UserSmartWalletV7.options.address, tester.DDAI.options.address],
+ true,
+ value => {
+ assert.strictEqual(value, ZERO.toString());
+ }
+ );
+
+ await tester.runTest(
+ "cSai can be sent to V7 UserSmartWallet",
+ tester.CSAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "mwei")]
+ );
+
+ allPreMigrationBalances = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+
+ dDaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.dDaiUnderlyingRaw
+ );
+ cSaiUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.cSaiUnderlyingRaw
+ );
+ preMigrationBalances = {
+ dDaiUnderlyingRaw: dDaiUnderlyingRaw.toString(),
+ cSaiUnderlyingRaw: cSaiUnderlyingRaw.toString()
+ };
+
+ postDDaiUnderlyingRaw = dDaiUnderlyingRaw.add(cSaiUnderlyingRaw);
+ postMigrationBalances = {
+ dDaiUnderlyingRaw: postDDaiUnderlyingRaw.toString(),
+ cSaiUnderlyingRaw: ZERO.toString()
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preMigrationBalances,
+ postMigrationBalances,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can trigger cSai to dDai migration",
+ UserSmartWalletV7,
+ "migrateCSaiToDDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ ]
+ );
+
+ await tester.runTest(
+ "Small amount of cDai can be sent to V7 UserSmartWallet",
+ tester.CDAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "wei")]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet cDai to dDai migration fails with a small amount of cDai",
+ UserSmartWalletV7,
+ "migrateCDaiToDDai",
+ "send",
+ [],
+ false,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "cDai can be sent to V7 UserSmartWallet again",
+ tester.CDAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "mwei")]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can trigger cDai to dDai migration again",
+ UserSmartWalletV7,
+ "migrateCDaiToDDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "cUSDC can be sent to V7 UserSmartWallet",
+ tester.CUSDC,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "lovelace")]
+ );
+
+ allPreMigrationBalances = await tester.getBalances(
+ UserSmartWalletV7.options.address
+ );
+
+ const dUSDCUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.dUSDCUnderlyingRaw
+ );
+ const cUSDCUnderlyingRaw = web3.utils.toBN(
+ allPreMigrationBalances.cUSDCUnderlyingRaw
+ );
+ preMigrationBalances = {
+ dUSDCUnderlyingRaw: dUSDCUnderlyingRaw.toString(),
+ cUSDCUnderlyingRaw: cUSDCUnderlyingRaw.toString()
+ };
+
+ const postDUSDCUnderlyingRaw = dUSDCUnderlyingRaw.add(cUSDCUnderlyingRaw);
+ postMigrationBalances = {
+ dUSDCUnderlyingRaw: postDUSDCUnderlyingRaw.toString(),
+ cUSDCUnderlyingRaw: ZERO.toString()
+ };
+
+ await tester.withBalanceCheck(
+ UserSmartWalletV7.options.address,
+ preMigrationBalances,
+ postMigrationBalances,
+ tester.runTest,
+ [
+ "V7 UserSmartWallet relay can trigger cDai to dDai migration",
+ UserSmartWalletV7,
+ "migrateCUSDCToDUSDC",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ ]
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can trigger cUSDC to dUSDC migration again (no-op)",
+ UserSmartWalletV7,
+ "migrateCUSDCToDUSDC",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "Sai Whale can deposit sai into the V7 user smart wallet",
+ tester.SAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.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,
+ UserSmartWalletV7.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.value,
+ web3.utils.toWei("1", "ether")
+ );
+ }
+ },
+ constants.SAI_WHALE_ADDRESS
+ );
+
+ await tester.runTest(
+ "Dai Whale can deposit dai into the V7 user smart wallet",
+ tester.DAI,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "ether")],
+ true,
+ receipt => {
+ if (testingContext !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.from,
+ constants.DAI_WHALE_ADDRESS
+ );
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.to,
+ UserSmartWalletV7.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.value,
+ web3.utils.toWei("1", "ether")
+ );
+ }
+ },
+ constants.DAI_WHALE_ADDRESS
+ );
+
+ await tester.runTest(
+ "USDC Whale can deposit usdc into the V7 user smart wallet",
+ tester.USDC,
+ "transfer",
+ "send",
+ [UserSmartWalletV7.options.address, web3.utils.toWei("1", "lovelace")],
+ true,
+ receipt => {
+ if (testingContext !== "coverage") {
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.from,
+ constants.USDC_WHALE_ADDRESS
+ );
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.to,
+ UserSmartWalletV7.options.address
+ );
+ assert.strictEqual(
+ receipt.events.Transfer.returnValues.value,
+ web3.utils.toWei("1", "lovelace")
+ );
+ }
+ },
+ constants.USDC_WHALE_ADDRESS
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can trigger sai to dai migration",
+ UserSmartWalletV7,
+ "migrateSaiToDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ "V7 UserSmartWallet relay can trigger sai to dai migration again (no-op)",
+ UserSmartWalletV7,
+ "migrateSaiToDai",
+ "send",
+ [],
+ true,
+ receipt => {
+ // TODO: verify logs
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `Call to isValidSignature with insufficient data fails`,
+ UserSmartWalletV7,
+ "isValidSignature",
+ "call",
+ ["0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `Call to isValidSignature with 32-bytes of data has no context`,
+ UserSmartWalletV7,
+ "isValidSignature",
+ "call",
+ [
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0x"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `Check allowance is not set before meta-tx`,
+ tester.DUSDC,
+ "allowance",
+ "call",
+ [UserSmartWalletV7.options.address, tester.addressTwo],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ let messageHash;
+ await tester.runTest(
+ `Get message hash for meta-transaction approval`,
+ tester.DUSDC_META,
+ "getMetaTransactionMessageHash",
+ "call",
+ [
+ "0x2d657fa5", // `modifyAllowanceViaMetaTransaction`
+ web3.eth.abi.encodeParameters(
+ ["address", "address", "uint256", "bool"],
+ [
+ UserSmartWalletV7.options.address,
+ tester.addressTwo,
+ "1",
+ true
+ ]
+ ),
+ 0, // No expiration
+ constants.NULL_BYTES_32 // no salt
+ ],
+ true,
+ values => {
+ assert.ok(values.valid);
+ messageHash = values.messageHash;
+ }
+ );
+
+ const messageHashSignature = tester.signHashedPrefixedHexString(
+ messageHash,
+ tester.address
+ );
+
+ const messageHashUserSignature = tester.signHashedPrefixedHexString(
+ messageHash,
+ tester.addressTwo
+ );
+
+ const messageHashBadSignature =
+ "0xaaaaaaaa" + messageHashSignature.slice(10);
+ const messageHashBadUserSignature =
+ "0xaaaaaaaa" + messageHashUserSignature.slice(10);
+
+ await tester.runTest(
+ `dUSDC allowance is not modifiable via meta-transaction with bad signature length`,
+ tester.DUSDC_META,
+ "modifyAllowanceViaMetaTransaction",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.addressTwo,
+ "1",
+ true,
+ 0,
+ constants.NULL_BYTES_32,
+ messageHashSignature + messageHashUserSignature.slice(2) + "aa"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `dUSDC allowance is not modifiable via meta-transaction with bad Dharma signature`,
+ tester.DUSDC_META,
+ "modifyAllowanceViaMetaTransaction",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.addressTwo,
+ "1",
+ true,
+ 0,
+ constants.NULL_BYTES_32,
+ messageHashBadSignature + messageHashUserSignature.slice(2)
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `dUSDC allowance is not modifiable via meta-transaction with bad user signature`,
+ tester.DUSDC_META,
+ "modifyAllowanceViaMetaTransaction",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.addressTwo,
+ "1",
+ true,
+ 0,
+ constants.NULL_BYTES_32,
+ messageHashSignature + messageHashBadUserSignature.slice(2)
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `dUSDC allowance is modifiable via meta-transaction`,
+ tester.DUSDC_META,
+ "modifyAllowanceViaMetaTransaction",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.addressTwo,
+ "1",
+ true,
+ 0,
+ constants.NULL_BYTES_32,
+ messageHashSignature + messageHashUserSignature.slice(2)
+ ],
+ true,
+ receipt => {
+ // TODO: validate
+ }
+ );
+
+ await tester.runTest(
+ `Check allowance is set after meta-tx`,
+ tester.DUSDC,
+ "allowance",
+ "call",
+ [UserSmartWalletV7.options.address, tester.addressTwo],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ // Initiate account recovery
+ await tester.runTest(
+ "smart wallet account recovery can be initiated",
+ tester.DharmaAccountRecoveryManagerV2,
+ "initiateAccountRecovery",
+ "send",
+ [
+ UserSmartWalletV7.options.address,
+ tester.originalAddress,
+ 0 // extraTime in seconds
+ ],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ await tester.runTest(
+ "smart wallet account recovery cannot be performed right away",
+ tester.DharmaAccountRecoveryManagerV2,
+ "recover",
+ "send",
+ [UserSmartWalletV7.options.address, tester.originalAddress],
+ false
+ );
+
+ // advance time by 3 days
+ await tester.advanceTime(60 * 60 * 24 * 3 + 5);
+
+ // recover account
+ await tester.runTest(
+ "smart wallet account recovery can be performed after three days",
+ tester.DharmaAccountRecoveryManagerV2,
+ "recover",
+ "send",
+ [UserSmartWalletV7.options.address, tester.originalAddress],
+ true,
+ receipt => {
+ // TODO: verify
+ //console.log(receipt.events)
+ }
+ );
+
+ // ZZZZZ
+
+ // COVERAGE TESTING - deployments
+ const DharmaUpgradeBeaconControllerManagerCoverage = await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager contract deployment`,
+ tester.DharmaUpgradeBeaconControllerManagerDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaUpgradeBeaconControllerCoverage = await tester.runTest(
+ `DharmaUpgradeBeaconController contract deployment`,
+ tester.DharmaUpgradeBeaconControllerDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaUpgradeBeaconCoverage = await tester.runTest(
+ `DharmaUpgradeBeacon (smart wallet) contract deployment`,
+ tester.DharmaUpgradeBeaconDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaKeyRingUpgradeBeaconCoverage = await tester.runTest(
+ `DharmaKeyRingUpgradeBeacon contract deployment`,
+ tester.DharmaKeyRingUpgradeBeaconDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaUpgradeBeaconEnvoy = await tester.runTest(
+ `DharmaUpgradeBeaconEnvoy contract deployment`,
+ tester.DharmaUpgradeBeaconEnvoyDeployer,
+ "",
+ "deploy"
+ );
+
+ await testUpgradeBeaconController(
+ tester,
+ DharmaUpgradeBeaconControllerCoverage, // controller manager
+ tester.DharmaUpgradeBeaconController, // smart wallet controller contract
+ tester.DharmaKeyRingUpgradeBeaconController, // key ring controller contract
+ DharmaUpgradeBeaconEnvoy, // envoy contract
+ DharmaUpgradeBeaconCoverage.options.address, // owned smart wallet beacon
+ DharmaKeyRingUpgradeBeaconCoverage.options.address, // owned key ring beacon
+ BadBeaconTwo.options.address // "bad" beacon
+ );
+
+ const DharmaKeyRegistryV2Coverage = await tester.runTest(
+ `DharmaKeyRegistryV2 contract deployment`,
+ tester.DharmaKeyRegistryV2Deployer,
+ "",
+ "deploy"
+ );
+
+ const AdharmaSmartWalletImplementation = await tester.runTest(
+ `AdharmaSmartWalletImplementation contract deployment`,
+ tester.AdharmaSmartWalletImplementationDeployer,
+ "",
+ "deploy"
+ );
+
+ const AdharmaKeyRingImplementation = await tester.runTest(
+ `AdharmaKeyRingImplementation contract deployment`,
+ tester.AdharmaKeyRingImplementationDeployer,
+ "",
+ "deploy"
+ );
+
+ const DharmaSmartWalletFactoryV1Coverage = await tester.runTest(
+ `DharmaSmartWalletFactoryV1 contract deployment`,
+ tester.DharmaSmartWalletFactoryV1Deployer,
+ "",
+ "deploy",
+ []
+ );
+
+ const DharmaKeyRingFactoryV1 = await tester.runTest(
+ `DharmaKeyRingFactoryV1 contract deployment`,
+ tester.DharmaKeyRingFactoryV1Deployer,
+ "",
+ "deploy",
+ []
+ );
+
+ const DharmaKeyRingFactoryV2 = await tester.runTest(
+ `DharmaKeyRingFactoryV2 contract deployment`,
+ tester.DharmaKeyRingFactoryV2Deployer,
+ "",
+ "deploy",
+ []
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 cannot create a V1 key ring with no key`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRing",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 cannot create a V1 key ring and set a new null key`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRingAndAdditionalKey",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 cannot create a V1 key ring and set a duplicate key`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRingAndAdditionalKey",
+ "send",
+ [tester.address, tester.address, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 can get the address of the next key ring`,
+ DharmaKeyRingFactoryV1,
+ "getNextKeyRing",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ nextKeyRing = value;
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 can create a V1 key ring`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRing",
+ "send",
+ [tester.address]
+ );
+
+ const KeyRingInstance = new web3.eth.Contract(
+ DharmaKeyRingImplementationV1Artifact.abi,
+ nextKeyRing
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 gets new key ring after a deploy with same input`,
+ DharmaKeyRingFactoryV1,
+ "getNextKeyRing",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(nextKeyRing !== value);
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can get the version of the key ring`,
+ KeyRingInstance,
+ "getVersion",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can get the nonce of the key ring`,
+ KeyRingInstance,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can get the key count of the key ring`,
+ KeyRingInstance,
+ "getKeyCount",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value.adminKeyCount, "1");
+ assert.strictEqual(value.standardKeyCount, "1");
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contingency status is exited after rollback`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'contingencyStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.armed)
- assert.ok(!value.activated)
- assert.strictEqual(value.activationTime, '0')
- }
- )
+ await tester.runTest(
+ `KeyRingInstance does not verify a bad signature`,
+ KeyRingInstance,
+ "isValidSignature",
+ "call",
+ [
+ web3.eth.abi.encodeParameters(
+ ["bytes32", "uint8", "bytes"],
+ [constants.NULL_BYTES_32, 1, "0x"]
+ ),
+ "0x"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can get an adminActionID using getNextAdminActionID`,
+ KeyRingInstance,
+ "getNextAdminActionID",
+ "call",
+ [1, 1],
+ true,
+ value => {
+ adminActionID = value;
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance getAdminActionID matches getNextAdminActionID`,
+ KeyRingInstance,
+ "getAdminActionID",
+ "call",
+ [1, 1, 0],
+ true,
+ value => {
+ assert.strictEqual(value, adminActionID);
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance cannot add a non-dual key in V1`,
+ KeyRingInstance,
+ "takeAdminAction",
+ "send",
+ [1, 1, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `KeyRingInstance cannot add key that already exists`,
+ KeyRingInstance,
+ "takeAdminAction",
+ "send",
+ [6, tester.address, "0x"],
+ false
+ );
+
+ const takeAdminActionSignature = tester.signHashedPrefixedHexString(
+ adminActionID,
+ tester.address
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can verify a valid signature`,
+ KeyRingInstance,
+ "isValidSignature",
+ "call",
+ [
+ web3.eth.abi.encodeParameters(
+ ["bytes32", "uint8", "bytes"],
+ [
+ web3.utils.keccak256(
+ // prefix => "\x19Ethereum Signed Message:\n32"
+ "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
+ adminActionID.slice(2),
+ { encoding: "hex" }
+ ),
+ 1,
+ "0x"
+ ]
+ ),
+ takeAdminActionSignature
+ ],
+ true,
+ value => {
+ assert.strictEqual(value, "0x20c13b0b");
+ }
+ );
+
+ await tester.runTest(
+ `KeyRingInstance can add a new key with a valid signature`,
+ KeyRingInstance,
+ "takeAdminAction",
+ "send",
+ [6, 1, takeAdminActionSignature],
+ true
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 cannot create a V1 key ring with no key`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRing",
+ "send",
+ [constants.NULL_ADDRESS, constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 cannot create a V1 key ring and set a new null key`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRingAndAdditionalKey",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, constants.NULL_ADDRESS, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 cannot create a V1 key ring and set a duplicate key`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRingAndAdditionalKey",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, tester.address, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 can get the address of the next key ring`,
+ DharmaKeyRingFactoryV2,
+ "getNextKeyRing",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ nextKeyRing = value;
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 can create a V1 key ring if the target address matches`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRing",
+ "send",
+ [tester.address, nextKeyRing]
+ );
+
+ const KeyRingInstanceFromV2Factory = new web3.eth.Contract(
+ DharmaKeyRingImplementationV1Artifact.abi,
+ nextKeyRing
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 won't deploy a V1 key ring if the target address has one`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRing",
+ "send",
+ [tester.address, KeyRingInstanceFromV2Factory.options.address]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 can call getFirstKeyRingAdminActionID`,
+ DharmaKeyRingFactoryV2,
+ "getFirstKeyRingAdminActionID",
+ "call",
+ [tester.address, tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 reverts when no new key ring supplied`,
+ DharmaKeyRingFactoryV2,
+ "getNextKeyRing",
+ "call",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 gets new key ring after a deploy with same input`,
+ DharmaKeyRingFactoryV2,
+ "getNextKeyRing",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(nextKeyRing !== value);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot rollback to implementation with no index`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [address, address, 100],
- false
- )
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 can call newKeyRingAndDaiWithdrawal`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRingAndDaiWithdrawal",
+ "send",
+ [
+ tester.address,
+ tester.address,
+ tester.address,
+ 0,
+ tester.address,
+ 0,
+ "0x",
+ "0x"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV2 can call newKeyRingAndUSDCWithdrawal`,
+ DharmaKeyRingFactoryV2,
+ "newKeyRingAndUSDCWithdrawal",
+ "send",
+ [
+ tester.address,
+ tester.address,
+ tester.address,
+ 0,
+ tester.address,
+ 0,
+ "0x",
+ "0x"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `AdharmaSmartWalletImplementation cannot be initialized directly post-deployment`,
+ AdharmaSmartWalletImplementation,
+ "initialize",
+ "send",
+ [tester.address],
+ false
+ );
+
+ await tester.runTest(
+ `AdharmaSmartWalletImplementation cannot be used to perform calls directly`,
+ AdharmaSmartWalletImplementation,
+ "performCall",
+ "send",
+ [tester.address, 1, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `AdharmaKeyRingImplementation cannot be initialized directly post-deployment`,
+ AdharmaKeyRingImplementation,
+ "initialize",
+ "send",
+ [1, 1, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `AdharmaKeyRingImplementation cannot be used to take action directly`,
+ AdharmaKeyRingImplementation,
+ "takeAction",
+ "send",
+ [tester.address, 1, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `UpgradeBeaconProxyV1 contract deployment fails with no init data`,
+ tester.UpgradeBeaconProxyV1Deployer,
+ "",
+ "deploy",
+ ["0x"],
+ false
+ );
+
+ await tester.runTest(
+ `KeyRingUpgradeBeaconProxyV1 contract deployment fails with no init data`,
+ tester.KeyRingUpgradeBeaconProxyV1Deployer,
+ "",
+ "deploy",
+ ["0x"],
+ false
+ );
+
+ const UpgradeBeaconProxyV1 = await tester.runTest(
+ `UpgradeBeaconProxyV1 contract deployment (direct)`,
+ tester.UpgradeBeaconProxyV1Deployer,
+ "",
+ "deploy",
+ [
+ web3.eth.abi.encodeFunctionCall(
+ {
+ name: "initialize",
+ type: "function",
+ inputs: [
+ {
+ type: "address",
+ name: "userSigningKey"
+ }
+ ]
+ },
+ [tester.address]
+ )
+ ]
+ );
+
+ const UpgradeBeaconProxyV1Implementation = new web3.eth.Contract(
+ DharmaSmartWalletImplementationV6Artifact.abi,
+ UpgradeBeaconProxyV1.options.address
+ );
+
+ await tester.runTest(
+ `UpgradeBeaconProxyV1 can retrieve its user signing key`,
+ UpgradeBeaconProxyV1Implementation,
+ "getUserSigningKey",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager owner can re-arm an Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true]
- )
+ const KeyRingUpgradeBeaconProxyV1 = await tester.runTest(
+ `KeyRingUpgradeBeaconProxyV1 contract deployment (direct)`,
+ tester.KeyRingUpgradeBeaconProxyV1Deployer,
+ "",
+ "deploy",
+ [
+ web3.eth.abi.encodeFunctionCall(
+ {
+ name: "initialize",
+ type: "function",
+ inputs: [
+ {
+ type: "uint128",
+ name: "adminThreshold"
+ },
+ {
+ type: "uint128",
+ name: "executorThreshold"
+ },
+ {
+ type: "address[]",
+ name: "keys"
+ },
+ {
+ type: "uint8[]",
+ name: "keyTypes"
+ }
+ ]
+ },
+ [1, 1, [tester.address], [3]]
+ )
+ ]
+ );
+
+ const KeyRingUpgradeBeaconProxyV1Implementation = new web3.eth.Contract(
+ DharmaKeyRingImplementationV1Artifact.abi,
+ KeyRingUpgradeBeaconProxyV1.options.address
+ );
+
+ await tester.runTest(
+ `KeyRingUpgradeBeaconProxyV1 can retrieve its user signing key`,
+ KeyRingUpgradeBeaconProxyV1Implementation,
+ "getKeyType",
+ "call",
+ [tester.address],
+ true,
+ values => {
+ assert.ok(values.standard);
+ assert.ok(values.admin);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager contingency status shows armed`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'contingencyStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(value.armed)
- assert.ok(!value.activated)
- assert.strictEqual(value.activationTime, '0')
- }
- )
+ // NOTE: these two either need to have the runtime requirement stripped out,
+ // or to use coverage without instrumentation. Skip coverage for now, as they
+ // are not yet in use.
+ // (actually, they're not working yet, period... skip them for now)
+ /*
+ if (testingContext !== 'coverage') {
+ const DharmaSmartWalletFactoryV2 = await tester.runTest(
+ `DharmaSmartWalletFactoryV2 contract deployment`,
+ DharmaSmartWalletFactoryV2Deployer,
+ '',
+ 'deploy',
+ []
+ )
- await runTest(
- `DharmaUpgradeBeaconControllerManager can rollback to initial prior implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ]
- )
+ const DharmaKeyRingFactoryV3 = await tester.runTest(
+ `DharmaKeyRingFactoryV3 contract deployment`,
+ DharmaKeyRingFactoryV3Deployer,
+ '',
+ 'deploy',
+ []
+ )
+ }
+ */
- await runTest(
- `DharmaUpgradeBeaconControllerManager contingency status shows no longer armed`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'contingencyStatus',
- 'call',
- [],
- true,
- value => {
- assert.ok(!value.armed)
- assert.ok(!value.activated)
- assert.strictEqual(value.activationTime, '0')
- }
- )
+ await testKeyRegistryV2(
+ tester,
+ DharmaKeyRegistryV2Coverage,
+ tester.DharmaKeyRegistryV2.options.address
+ );
+
+ const DharmaAccountRecoveryManagerV2Coverage = await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 contract deployment`,
+ tester.DharmaAccountRecoveryManagerV2Deployer,
+ "",
+ "deploy"
+ );
+
+ await testAccountRecoveryManager(
+ tester,
+ DharmaAccountRecoveryManagerV2Coverage,
+ UserSmartWalletV6.options.address
+ );
+
+ await testUpgradeBeaconControllerManagerPartOne(
+ tester,
+ DharmaUpgradeBeaconControllerManagerCoverage
+ );
+
+ const MockDharmaKeyRingFactory = await tester.runTest(
+ `MockDharmaKeyRingFactory contract deployment`,
+ tester.MockDharmaKeyRingFactoryDeployer,
+ "",
+ "deploy",
+ []
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with no keys`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [], []],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with null address as key`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [constants.NULL_ADDRESS], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with non-dual key`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [tester.address], [1]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with admin threshold > 1`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [2, 1, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy a DharmaV1 key ring with executor threshold > 1`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 2, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ "Dharma Upgrade Beacon Controller can upgrade to AdharmaSmartWalletImplementation",
+ tester.DharmaUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaUpgradeBeacon.options.address,
+ AdharmaSmartWalletImplementation.options.address
+ ]
+ );
+
+ await tester.runTest(
+ "Dharma Key Ring Upgrade Beacon Controller can upgrade to AdharmaKeyRingImplementation",
+ tester.DharmaKeyRingUpgradeBeaconController,
+ "upgrade",
+ "send",
+ [
+ tester.DharmaKeyRingUpgradeBeacon.options.address,
+ AdharmaKeyRingImplementation.options.address
+ ]
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 cannot deploy an Adharma smart wallet with no key",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ "DharmaSmartWalletFactoryV1 can deploy an Adharma smart wallet",
+ DharmaSmartWalletFactoryV1,
+ "newSmartWallet",
+ "send",
+ [tester.address]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 cannot create a V1 key ring with no key`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRing",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 cannot create an Adharma key ring and set a new null key`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRingAndAdditionalKey",
+ "send",
+ [tester.address, constants.NULL_ADDRESS, "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 reverts when no new key ring supplied`,
+ DharmaKeyRingFactoryV1,
+ "getNextKeyRing",
+ "call",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 can call newKeyRingAndDaiWithdrawal`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRingAndDaiWithdrawal",
+ "send",
+ [tester.address, tester.address, 0, tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 can call newKeyRingAndUSDCWithdrawal`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRingAndUSDCWithdrawal",
+ "send",
+ [tester.address, tester.address, 0, tester.address, 0, "0x", "0x"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRingFactoryV1 can create an Adharma key ring`,
+ DharmaKeyRingFactoryV1,
+ "newKeyRing",
+ "send",
+ [tester.address]
+ );
+
+ const UserSmartWalletAdharma = new web3.eth.Contract(
+ AdharmaSmartWalletImplementationArtifact.abi,
+ UserSmartWalletV6.options.address
+ );
+
+ await tester.runTest(
+ `Adharma Smart Wallet can be used to perform calls`,
+ UserSmartWalletAdharma,
+ "performCall",
+ "send",
+ [UserSmartWalletAdharma.options.address, 0, "0x"],
+ true,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `Adharma Smart Wallet can be used to perform failing calls`,
+ UserSmartWalletAdharma,
+ "performCall",
+ "send",
+ [BadBeacon.options.address, 0, "0x"],
+ false,
+ receipt => {},
+ tester.originalAddress
+ );
+
+ const KeyRingAdharma = new web3.eth.Contract(
+ AdharmaKeyRingImplementationArtifact.abi,
+ KeyRingInstance.options.address
+ );
+
+ await tester.runTest(
+ `Adharma Key Ring can be used to take an action`,
+ KeyRingAdharma,
+ "takeAction",
+ "send",
+ [tester.address, 0, "0x", "0x"]
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no keys`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [0, 0, [], []],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with admin threshold of 0`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [0, 1, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with executor threshold of 0`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 0, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring where length of keys and types are not equal`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [tester.address, tester.addressTwo], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with duplicate keys`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [tester.address, tester.address], [3, 3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no admin key`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [tester.address], [1]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with less admin keys than threshold`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [2, 1, [tester.address], [3]],
+ false
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory can deploy an Adharma key ring with multiple keys`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [2, 2, [tester.address, tester.addressTwo], [3, 3]]
+ );
+
+ await tester.runTest(
+ `MockDharmaKeyRingFactory cannot deploy an Adharma key ring with no standard key`,
+ MockDharmaKeyRingFactory,
+ "newKeyRing",
+ "send",
+ [1, 1, [tester.address], [2]],
+ false
+ );
+
+ await tester.runTest(
+ `TimelockEdgecaseTester contract deployment edge case 1`,
+ tester.TimelockEdgecaseTesterDeployer,
+ "",
+ "deploy",
+ [0],
+ false
+ );
+
+ await tester.runTest(
+ `TimelockEdgecaseTester contract deployment edge case 2`,
+ tester.TimelockEdgecaseTesterDeployer,
+ "",
+ "deploy",
+ [1],
+ false
+ );
+
+ await tester.runTest(
+ `TimelockEdgecaseTester contract deployment edge case 3`,
+ tester.TimelockEdgecaseTesterDeployer,
+ "",
+ "deploy",
+ [2],
+ false
+ );
+
+ const DharmaUpgradeMultisig = await tester.runTest(
+ `DharmaUpgradeMultisig contract deployment`,
+ tester.DharmaUpgradeMultisigDeployer,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]
+ ]
+ );
+
+ const DharmaAccountRecoveryMultisig = await tester.runTest(
+ `DharmaAccountRecoveryMultisig contract deployment`,
+ tester.DharmaAccountRecoveryMultisigDeployer,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour
+ ]
+ ]
+ );
+
+ const DharmaAccountRecoveryOperatorMultisig = await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig contract deployment`,
+ tester.DharmaAccountRecoveryOperatorMultisigDeployer,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour
+ ]
+ ]
+ );
+
+ const DharmaKeyRegistryMultisig = await tester.runTest(
+ `DharmaKeyRegistryMultisig contract deployment`,
+ tester.DharmaKeyRegistryMultisigDeployer,
+ "",
+ "deploy",
+ [
+ [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]
+ ]
+ );
+
+ rawData = "0x";
+ executorGasLimit = 100000000000;
+
+ const bizarreSigs =
+ "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0" +
+ "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A11b" +
+ "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0" +
+ "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A01a";
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get the initial nonce`,
+ DharmaUpgradeMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get the owners`,
+ DharmaUpgradeMultisig,
+ "getOwners",
+ "call",
+ [],
+ true,
+ value => {
+ assert.deepEqual(value, [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get an owner`,
+ DharmaUpgradeMultisig,
+ "isOwner",
+ "call",
+ [tester.ownerOne],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig returns false for a non-owner`,
+ DharmaUpgradeMultisig,
+ "isOwner",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get the threshold`,
+ DharmaUpgradeMultisig,
+ "getThreshold",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "3");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get the destination`,
+ DharmaUpgradeMultisig,
+ "getDestination",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS
+ );
+ }
+ );
+
+ // Generate the messsage hash based on the supplied parameters.
+ hashInputs =
+ DharmaUpgradeMultisig.options.address +
+ "0".padStart(64, "0") +
+ tester.address.slice(2) +
+ executorGasLimit.toString(16).padStart(64, "0") +
+ rawData.slice(2);
+
+ hash = util.bufferToHex(util.keccak256(hashInputs));
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get a hash`,
+ DharmaUpgradeMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get a hash with a specific nonce`,
+ DharmaUpgradeMultisig,
+ "getHash",
+ "call",
+ [rawData, tester.address, executorGasLimit, 0],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
+
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+ ownerSigsOutOfOrder =
+ ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2);
+ unownedSig = tester.signHashedPrefixedHexString(hash, tester.address);
+ unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute from non-executor`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.addressTwo, executorGasLimit, ownerSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute with oddly-sized signatures`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs + "1234"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute with non-compliant signatures`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, bizarreSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute without enough signatures`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs.slice(0, -130)],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute without owner signatures`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, unownedSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig cannot call execute with out-of-order signatures`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigsOutOfOrder],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can call execute`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig nonce is incremented`,
+ DharmaUpgradeMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get the initial nonce`,
+ DharmaKeyRegistryMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get the owners`,
+ DharmaKeyRegistryMultisig,
+ "getOwners",
+ "call",
+ [],
+ true,
+ value => {
+ assert.deepEqual(value, [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour,
+ tester.ownerFive
+ ]);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get an owner`,
+ DharmaKeyRegistryMultisig,
+ "isOwner",
+ "call",
+ [tester.ownerOne],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig returns false for a non-owner`,
+ DharmaKeyRegistryMultisig,
+ "isOwner",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get the threshold`,
+ DharmaKeyRegistryMultisig,
+ "getThreshold",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "3");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get the destination`,
+ DharmaKeyRegistryMultisig,
+ "getDestination",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, constants.KEY_REGISTRY_V2_ADDRESS);
+ }
+ );
+
+ // Generate the messsage hash based on the supplied parameters.
+ hashInputs =
+ DharmaKeyRegistryMultisig.options.address +
+ "0".padStart(64, "0") +
+ tester.address.slice(2) +
+ executorGasLimit.toString(16).padStart(64, "0") +
+ rawData.slice(2);
+
+ hash = util.bufferToHex(util.keccak256(hashInputs));
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get a hash`,
+ DharmaKeyRegistryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get a hash with a specific nonce`,
+ DharmaKeyRegistryMultisig,
+ "getHash",
+ "call",
+ [rawData, tester.address, executorGasLimit, 0],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
+
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+ ownerSigsOutOfOrder =
+ ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2);
+ unownedSig = tester.signHashedPrefixedHexString(hash, tester.address);
+ unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute from non-executor`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.addressTwo, executorGasLimit, ownerSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute with oddly-sized signatures`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs + "1234"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute with non-compliant signatures`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, bizarreSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute without enough signatures`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs.slice(0, -130)],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute without owner signatures`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, unownedSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig cannot call execute with out-of-order signatures`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigsOutOfOrder],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can call execute`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig nonce is incremented`,
+ DharmaKeyRegistryMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get the initial nonce`,
+ DharmaAccountRecoveryMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "0");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get the owners`,
+ DharmaAccountRecoveryMultisig,
+ "getOwners",
+ "call",
+ [],
+ true,
+ value => {
+ assert.deepEqual(value, [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour
+ ]);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get an owner`,
+ DharmaAccountRecoveryMultisig,
+ "isOwner",
+ "call",
+ [tester.ownerOne],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig returns false for a non-owner`,
+ DharmaAccountRecoveryMultisig,
+ "isOwner",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get the threshold`,
+ DharmaAccountRecoveryMultisig,
+ "getThreshold",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "3");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get the destination`,
+ DharmaAccountRecoveryMultisig,
+ "getDestination",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
+ );
+ }
+ );
+
+ // Generate the messsage hash based on the supplied parameters.
+ hashInputs =
+ DharmaAccountRecoveryMultisig.options.address +
+ "0".padStart(64, "0") +
+ tester.address.slice(2) +
+ executorGasLimit.toString(16).padStart(64, "0") +
+ rawData.slice(2);
+
+ hash = util.bufferToHex(util.keccak256(hashInputs));
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get a hash`,
+ DharmaAccountRecoveryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get a hash with a specific nonce`,
+ DharmaAccountRecoveryMultisig,
+ "getHash",
+ "call",
+ [rawData, tester.address, executorGasLimit, 0],
+ true,
+ value => {
+ assert.strictEqual(value, hash);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager can block rollback to prior implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'blockRollback',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ]
- )
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot block a blocked rollback`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'blockRollback',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ],
- false
- )
+ /*
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2)
+ ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2)
+ unownedSig = tester.signHashedPrefixedHexString(hash, address)
+ unownedSigs = unownedSig + ownerTwoSig.slice(2)
+ */
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot rollback to a blocked rollback`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'rollback',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- DharmaUpgradeBeacon.options.address,
- 0
- ],
- false
- )
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+ ownerSigsOutOfOrder =
+ ownerTwoSig + ownerOneSig.slice(2) + ownerThreeSig.slice(2);
+ unownedSig = tester.signHashedPrefixedHexString(hash, tester.address);
+ unownedSigs = unownedSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute from non-executor`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.addressTwo, executorGasLimit, ownerSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute with oddly-sized signatures`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs + "1234"],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute with non-compliant signatures`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, bizarreSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute without enough signatures`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerOneSig],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute without owner signatures`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, unownedSigs],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig cannot call execute with out-of-order signatures`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigsOutOfOrder],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can call execute`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig nonce is incremented`,
+ DharmaAccountRecoveryMultisig,
+ "getNonce",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "1");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can get the owners`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "getOwners",
+ "call",
+ [],
+ true,
+ value => {
+ assert.deepEqual(value, [
+ tester.ownerOne,
+ tester.ownerTwo,
+ tester.ownerThree,
+ tester.ownerFour
+ ]);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can get an owner`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "isOwner",
+ "call",
+ [tester.ownerOne],
+ true,
+ value => {
+ assert.ok(value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig returns false for a non-owner`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "isOwner",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can get the threshold`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "getThreshold",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, "2");
+ }
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can get the destination`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "getDestination",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
+ );
+ }
+ );
+
+ // Generate the messsage hash based on the supplied parameters.
+ hashInputs =
+ DharmaAccountRecoveryOperatorMultisig.options.address +
+ "0".padStart(64, "0") +
+ tester.address.slice(2) +
+ executorGasLimit.toString(16).padStart(64, "0") +
+ rawData.slice(2);
+
+ hash = util.bufferToHex(util.keccak256(hashInputs));
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can get a hash`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "getHash",
+ "call",
+ [rawData, tester.address, executorGasLimit, constants.NULL_BYTES_32],
+ true,
+ values => {
+ assert.strictEqual(values.hash, hash);
+ }
+ );
- // advance time by 90 days
- await advanceTime((60 * 60 * 24 * 90) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager deadman switch can arm an Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'armAdharmaContingency',
- 'send',
- [true],
- true,
- receipt => {},
- originalAddress
- )
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
- await runTest(
- `DharmaUpgradeBeaconControllerManager deadman switch can activate an Adharma Contingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'activateAdharmaContingency',
- 'send',
- [],
- true,
- receipt => {},
- originalAddress
- )
+ /*
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2)
+ ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2)
+ unownedSig = tester.signHashedPrefixedHexString(hash, address)
+ unownedSigs = unownedSig + ownerTwoSig.slice(2)
+ */
- // advance time by 2 days
- await advanceTime((60 * 60 * 24 * 2) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call exitAdharmaContingency with null implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- constants.NULL_ADDRESS,
- address
- ],
- false
- )
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2);
+ ownerSigsOutOfOrder = ownerTwoSig + ownerOneSig.slice(2);
+ unownedSig = tester.signHashedPrefixedHexString(hash, tester.address);
+ unownedSigs = unownedSig + ownerTwoSig.slice(2);
- await runTest(
- `DharmaUpgradeBeaconControllerManager cannot call exitAdharmaContingency with non-contract implementation`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- address,
- address
- ],
- false
- )
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute from non-executor`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.addressTwo,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerSigs
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute with oddly-sized signatures`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerSigs + "1234"
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute with non-compliant signatures`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ bizarreSigs
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute without enough signatures`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerOneSig
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute without owner signatures`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ unownedSigs
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot call execute with out-of-order signatures`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerSigsOutOfOrder
+ ],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig can call execute`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerSigs
+ ]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryOperatorMultisig cannot replay a call to execute`,
+ DharmaAccountRecoveryOperatorMultisig,
+ "execute",
+ "send",
+ [
+ rawData,
+ tester.address,
+ executorGasLimit,
+ constants.NULL_BYTES_32,
+ ownerSigs
+ ],
+ false
+ );
+
+ const DharmaEscapeHatchRegistry = await tester.runTest(
+ `DharmaEscapeHatchRegistry contract deployment`,
+ tester.DharmaEscapeHatchRegistryDeployer,
+ "",
+ "deploy"
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms that an escape hatch does not exist until set`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatch",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can set the null address as an escape hatch account`,
+ DharmaEscapeHatchRegistry,
+ "setEscapeHatch",
+ "send",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can set an escape hatch account`,
+ DharmaEscapeHatchRegistry,
+ "setEscapeHatch",
+ "send",
+ [tester.addressTwo]
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can get an escape hatch account once set`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatch",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.exists);
+ assert.strictEqual(value.escapeHatch, tester.addressTwo);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager can call exitAdharmaContingency`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'exitAdharmaContingency',
- 'send',
- [
- DharmaSmartWalletImplementationV6.options.address,
- DharmaKeyRingImplementationV1.options.address
- ]
- )
+ fallbackEscapeHatch = await web3.eth.call({
+ to: DharmaEscapeHatchRegistry.options.address,
+ from: tester.address,
+ data: "0x"
+ });
- await runTest(
- `DharmaUpgradeBeaconControllerManager can have an EOA accept controller ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'agreeToAcceptControllerOwnership',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- true
- ]
- )
+ console.log(
+ " ✓ DharmaEscapeHatchRegistry can get an escape hatch account using the fallback"
+ );
+ assert.strictEqual(
+ web3.eth.abi.decodeParameter("address", fallbackEscapeHatch),
+ tester.addressTwo
+ );
+ tester.passed++;
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can get an escape hatch for a specific smart wallet`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatchForSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(value.exists);
+ assert.strictEqual(value.escapeHatch, tester.addressTwo);
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry cannot get an escape hatch the null address`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatchForSmartWallet",
+ "call",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can remove an escape hatch account`,
+ DharmaEscapeHatchRegistry,
+ "removeEscapeHatch"
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms that an escape hatch is successfully removed`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatch",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconControllerManager can initiate timelock for transferring controller ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'initiateTransferControllerOwnership',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- address,
- 0
- ]
- )
+ fallbackEscapeHatch = await web3.eth.call({
+ to: DharmaEscapeHatchRegistry.options.address,
+ from: tester.address,
+ data: "0x"
+ });
- // advance time by 4 weeks
- await advanceTime((60 * 60 * 24 * 7 * 4) + 5)
-
- await runTest(
- `DharmaUpgradeBeaconControllerManager can transfer controller ownership`,
- DharmaUpgradeBeaconControllerManagerCoverage,
- 'transferControllerOwnership',
- 'send',
- [
- DharmaUpgradeBeaconController.options.address,
- address
- ]
- )
+ console.log(
+ " ✓ DharmaEscapeHatchRegistry can gets null address for removed escape hatch account using the fallback"
+ );
+ assert.strictEqual(
+ web3.eth.abi.decodeParameter("address", fallbackEscapeHatch),
+ constants.NULL_ADDRESS
+ );
+ tester.passed++;
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry will not fire an event when removing an unset escape hatch account`,
+ DharmaEscapeHatchRegistry,
+ "removeEscapeHatch"
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms that escape hatch functionality is not initially disabled`,
+ DharmaEscapeHatchRegistry,
+ "hasDisabledEscapeHatchForSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value);
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry cannot get disabled status for null address`,
+ DharmaEscapeHatchRegistry,
+ "hasDisabledEscapeHatchForSmartWallet",
+ "call",
+ [constants.NULL_ADDRESS],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can reset an escape hatch account`,
+ DharmaEscapeHatchRegistry,
+ "setEscapeHatch",
+ "send",
+ [tester.ownerOne]
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can get an escape hatch account once reset`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatch",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(value.exists);
+ assert.strictEqual(value.escapeHatch, tester.ownerOne);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry setting an existing escape hatch account is a no-op`,
+ DharmaEscapeHatchRegistry,
+ "setEscapeHatch",
+ "send",
+ [tester.ownerOne]
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry can disable the escape hatch mechanism`,
+ DharmaEscapeHatchRegistry,
+ "permanentlyDisableEscapeHatch"
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms that escape hatch functionality is disabled`,
+ DharmaEscapeHatchRegistry,
+ "hasDisabledEscapeHatchForSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(value);
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms that an escape hatch is successfully removed when disabling`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatch",
+ "call",
+ [],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS);
+ }
+ );
- await runTest(
- `DharmaUpgradeBeaconController can get new owner`,
- DharmaUpgradeBeaconController,
- 'isOwner',
- 'call',
- [],
- true,
- value => {
- assert.ok(value)
- }
- )
+ fallbackEscapeHatch = await web3.eth.call({
+ to: DharmaEscapeHatchRegistry.options.address,
+ from: tester.address,
+ data: "0x"
+ });
- console.log(
- `completed ${passed + failed} test${passed + failed === 1 ? '' : 's'} ` +
- `with ${failed} failure${failed === 1 ? '' : 's'}.`
- )
+ console.log(
+ " ✓ DharmaEscapeHatchRegistry can gets null address for removed escape hatch account after disabling using the fallback"
+ );
+ assert.strictEqual(
+ web3.eth.abi.decodeParameter("address", fallbackEscapeHatch),
+ constants.NULL_ADDRESS
+ );
+ tester.passed++;
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry confirms escape hatch is removed after disabling for for a specific smart wallet`,
+ DharmaEscapeHatchRegistry,
+ "getEscapeHatchForSmartWallet",
+ "call",
+ [tester.address],
+ true,
+ value => {
+ assert.ok(!value.exists);
+ assert.strictEqual(value.escapeHatch, constants.NULL_ADDRESS);
+ },
+ tester.originalAddress
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry cannot set an escape hatch account once disabled`,
+ DharmaEscapeHatchRegistry,
+ "setEscapeHatch",
+ "send",
+ [tester.ownerTwo],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry cannot remove an escape hatch account once disabled`,
+ DharmaEscapeHatchRegistry,
+ "removeEscapeHatch",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaEscapeHatchRegistry cannot re-disable an escape hatch account once disabled`,
+ DharmaEscapeHatchRegistry,
+ "permanentlyDisableEscapeHatch",
+ "send",
+ [],
+ false
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 owner can start ownership transfer to multisig`,
+ tester.DharmaAccountRecoveryManagerV2,
+ "transferOwnership",
+ "send",
+ [DharmaAccountRecoveryMultisig.options.address]
+ );
+
+ rawData = tester.DharmaAccountRecoveryManagerV2.methods
+ .acceptOwnership()
+ .encodeABI();
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get a hash`,
+ DharmaAccountRecoveryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ // accept ownership
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can call execute to accept ownership`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 owner is now set to multisig`,
+ tester.DharmaAccountRecoveryManagerV2,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ DharmaAccountRecoveryMultisig.options.address
+ );
+ }
+ );
+
+ // TODO: test account recovery using the multisig?
+
+ // transfer ownership back
+ rawData = tester.DharmaAccountRecoveryManagerV2.methods
+ .transferOwnership(tester.address)
+ .encodeABI();
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can get a hash`,
+ DharmaAccountRecoveryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaAccountRecoveryMultisig can call execute to transfer ownership back`,
+ DharmaAccountRecoveryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 EOA can accept ownership transfer from multisig`,
+ tester.DharmaAccountRecoveryManagerV2,
+ "acceptOwnership"
+ );
+
+ await tester.runTest(
+ `DharmaAccountRecoveryManagerV2 owner is now set to EOA`,
+ tester.DharmaAccountRecoveryManagerV2,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryV2 owner can start ownership transfer to multisig`,
+ tester.DharmaKeyRegistryV2,
+ "transferOwnership",
+ "send",
+ [DharmaKeyRegistryMultisig.options.address]
+ );
+
+ rawData = tester.DharmaKeyRegistryV2.methods.acceptOwnership().encodeABI();
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get a hash`,
+ DharmaKeyRegistryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ // accept ownership
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can call execute to accept ownership`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryV2 owner is now set to multisig`,
+ tester.DharmaKeyRegistryV2,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ DharmaKeyRegistryMultisig.options.address
+ );
+ }
+ );
+
+ // TODO: test setting a new key using the multisig?
+
+ // transfer ownership back
+ rawData = tester.DharmaKeyRegistryV2.methods
+ .transferOwnership(tester.address)
+ .encodeABI();
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can get a hash`,
+ DharmaKeyRegistryMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaKeyRegistryMultisig can call execute to transfer ownership back`,
+ DharmaKeyRegistryMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryV2 EOA can accept ownership transfer from multisig`,
+ tester.DharmaKeyRegistryV2,
+ "acceptOwnership"
+ );
+
+ await tester.runTest(
+ `DharmaKeyRegistryV2 owner is now set to EOA`,
+ tester.DharmaKeyRegistryV2,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner is initially set to an EOA`,
+ tester.DharmaUpgradeBeaconControllerManager,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner can start ownership transfer to multisig`,
+ tester.DharmaUpgradeBeaconControllerManager,
+ "transferOwnership",
+ "send",
+ [DharmaUpgradeMultisig.options.address]
+ );
+
+ rawData = tester.DharmaUpgradeBeaconControllerManager.methods
+ .acceptOwnership()
+ .encodeABI();
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get a hash`,
+ DharmaUpgradeMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ // accept ownership
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can call execute to accept ownership`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner is now set to multisig`,
+ tester.DharmaUpgradeBeaconControllerManager,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, DharmaUpgradeMultisig.options.address);
+ }
+ );
+
+ // TODO: test an upgrade, rollback, etc with the multisig?
+
+ // transfer ownership back
+ rawData = tester.DharmaUpgradeBeaconControllerManager.methods
+ .transferOwnership(tester.address)
+ .encodeABI();
+ await tester.runTest(
+ `DharmaUpgradeMultisig can get a hash`,
+ DharmaUpgradeMultisig,
+ "getNextHash",
+ "call",
+ [rawData, tester.address, executorGasLimit],
+ true,
+ value => {
+ hash = value;
+ }
+ );
+
+ ownerOneSig = tester.signHashedPrefixedHexString(hash, tester.ownerOne);
+ ownerTwoSig = tester.signHashedPrefixedHexString(hash, tester.ownerTwo);
+ ownerThreeSig = tester.signHashedPrefixedHexString(hash, tester.ownerThree);
+ ownerSigs = ownerOneSig + ownerTwoSig.slice(2) + ownerThreeSig.slice(2);
+
+ await tester.runTest(
+ `DharmaUpgradeMultisig can call execute to transfer ownership back`,
+ DharmaUpgradeMultisig,
+ "execute",
+ "send",
+ [rawData, tester.address, executorGasLimit, ownerSigs]
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager EOA can accept ownership transfer from multisig`,
+ tester.DharmaUpgradeBeaconControllerManager,
+ "acceptOwnership"
+ );
+
+ await tester.runTest(
+ `DharmaUpgradeBeaconControllerManager owner is now set to EOA`,
+ tester.DharmaUpgradeBeaconControllerManager,
+ "owner",
+ "call",
+ [],
+ true,
+ value => {
+ assert.strictEqual(value, tester.address);
+ }
+ );
+
+ await testUpgradeBeaconControllerManagerPartTwo(
+ tester,
+ DharmaUpgradeBeaconControllerManagerCoverage,
+ tester.DharmaUpgradeBeaconController,
+ tester.DharmaKeyRingUpgradeBeaconController,
+ tester.DharmaUpgradeBeacon.options.address,
+ AdharmaSmartWalletImplementation.options.address,
+ DharmaSmartWalletImplementationV7.options.address,
+ DharmaKeyRingImplementationV1.options.address
+ );
- await longer()
+ console.log(
+ `completed ${tester.passed + tester.failed} test${
+ tester.passed + tester.failed === 1 ? "" : "s"
+ } ` + `with ${tester.failed} failure${tester.failed === 1 ? "" : "s"}.`
+ );
- if (failed > 0) {
- process.exit(1)
- }
+ await longer();
- // exit.
- return 0
+ if (tester.failed > 0) {
+ process.exit(1);
+ }
-}}
+ // exit.
+ return 0;
+}
+module.exports = {
+ test
+};
diff --git a/scripts/test/testCoverage.js b/scripts/test/testCoverage.js
index afdbaec..feca4cc 100644
--- a/scripts/test/testCoverage.js
+++ b/scripts/test/testCoverage.js
@@ -1,17 +1,17 @@
-var Web3 = require('web3')
-web3Provider = new Web3('ws://localhost:8555')
-
// import tests
-var deployMockExternal = require('./deployMockExternal.js')
-var deploy = require('./deploy.js')
-var test = require('./test.js')
+var deployMockExternal = require("./deployMockExternal.js");
+var deploy = require("./deploy.js");
+var test = require("./test.js");
// run tests
async function runTests() {
- await deployMockExternal.test(web3Provider, 'coverage')
- await deploy.test(web3Provider, 'coverage')
- await test.test(web3Provider, 'coverage')
- process.exit(0)
+ const context = process.env.TESTING_CONTEXT;
+
+ await deployMockExternal.test(context);
+ await deploy.test(context);
+ await test.test(context);
+
+ process.exit(0);
}
-runTests()
+runTests();
diff --git a/scripts/test/testHelpers.js b/scripts/test/testHelpers.js
new file mode 100644
index 0000000..acb0eef
--- /dev/null
+++ b/scripts/test/testHelpers.js
@@ -0,0 +1,1436 @@
+const { web3 } = require("./web3");
+const constants = require("./constants");
+const assert = require("assert");
+const util = require("ethereumjs-util");
+
+const MockCodeCheckArtifact = require("../../build/contracts/MockCodeCheck.json");
+
+const AdharmaSmartWalletImplementationArtifact = require("../../build/contracts/AdharmaSmartWalletImplementation.json");
+const AdharmaKeyRingImplementationArtifact = require("../../build/contracts/AdharmaKeyRingImplementation.json");
+
+const DharmaUpgradeBeaconControllerManagerArtifact = require("../../build/contracts/DharmaUpgradeBeaconControllerManager.json");
+const DharmaUpgradeBeaconControllerArtifact = require("../../build/contracts/DharmaUpgradeBeaconController.json");
+const DharmaUpgradeBeaconArtifact = require("../../build/contracts/DharmaUpgradeBeacon.json");
+const DharmaKeyRingUpgradeBeaconArtifact = require("../../build/contracts/DharmaKeyRingUpgradeBeacon.json");
+const DharmaUpgradeBeaconEnvoyArtifact = require("../../build/contracts/DharmaUpgradeBeaconEnvoy.json");
+
+const DharmaAccountRecoveryManagerV2Artifact = require("../../build/contracts/DharmaAccountRecoveryManagerV2.json");
+const DharmaKeyRegistryV2Artifact = require("../../build/contracts/DharmaKeyRegistryV2.json");
+const DharmaSmartWalletFactoryV1Artifact = require("../../build/contracts/DharmaSmartWalletFactoryV1.json");
+const DharmaSmartWalletFactoryV2Artifact = require("../../build/contracts/DharmaSmartWalletFactoryV2.json");
+
+const DharmaSmartWalletImplementationV6Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV6.json");
+const DharmaSmartWalletImplementationV7Artifact = require("../../build/contracts/DharmaSmartWalletImplementationV7.json");
+
+const DharmaKeyRingImplementationV1Artifact = require("../../build/contracts/DharmaKeyRingImplementationV1.json");
+const DharmaKeyRingFactoryV1Artifact = require("../../build/contracts/DharmaKeyRingFactoryV1.json");
+const DharmaKeyRingFactoryV2Artifact = require("../../build/contracts/DharmaKeyRingFactoryV2.json");
+const DharmaKeyRingFactoryV3Artifact = require("../../build/contracts/DharmaKeyRingFactoryV3.json");
+
+const UpgradeBeaconProxyV1Artifact = require("../../build/contracts/UpgradeBeaconProxyV1.json");
+const KeyRingUpgradeBeaconProxyV1Artifact = require("../../build/contracts/KeyRingUpgradeBeaconProxyV1.json");
+
+const DharmaUpgradeMultisigArtifact = require("../../build/contracts/DharmaUpgradeMultisig.json");
+const DharmaAccountRecoveryMultisigArtifact = require("../../build/contracts/DharmaAccountRecoveryMultisig.json");
+const DharmaAccountRecoveryOperatorMultisigArtifact = require("../../build/contracts/DharmaAccountRecoveryOperatorMultisig.json");
+const DharmaKeyRegistryMultisigArtifact = require("../../build/contracts/DharmaKeyRegistryMultisig.json");
+
+const DharmaEscapeHatchRegistryArtifact = require("../../build/contracts/DharmaEscapeHatchRegistry.json");
+
+const UpgradeBeaconImplementationCheckArtifact = require("../../build/contracts/UpgradeBeaconImplementationCheck.json");
+const BadBeaconArtifact = require("../../build/contracts/BadBeacon.json");
+const BadBeaconTwoArtifact = require("../../build/contracts/BadBeaconTwo.json");
+const TimelockEdgecaseTesterArtifact = require("../../build/contracts/TimelockEdgecaseTester.json");
+
+const MockDharmaKeyRingFactoryArtifact = require("../../build/contracts/MockDharmaKeyRingFactory.json");
+const IERC20Artifact = require("../../build/contracts/IERC20.json");
+const CTokenInterfaceArtifact = require("../../build/contracts/CTokenInterface.json");
+const BalanceCheckerArtifact = require("../../build/contracts/BalanceChecker.json");
+
+class Tester {
+ constructor(testingContext) {
+ this.context = testingContext;
+ this.failed = 0;
+ this.passed = 0;
+
+ const UpgradeBeaconImplementationCheckDeployer = new web3.eth.Contract(
+ UpgradeBeaconImplementationCheckArtifact.abi
+ );
+ UpgradeBeaconImplementationCheckDeployer.options.data =
+ UpgradeBeaconImplementationCheckArtifact.bytecode;
+ this.UpgradeBeaconImplementationCheckDeployer = UpgradeBeaconImplementationCheckDeployer;
+ }
+
+ async init() {
+ // get available addresses and assign them to various roles
+ const addresses = await web3.eth.getAccounts();
+ if (addresses.length < 1) {
+ console.log("cannot find enough addresses to run tests!");
+ process.exit(1);
+ }
+
+ let latestBlock = await web3.eth.getBlock("latest");
+
+ this.originalAddress = addresses[0];
+
+ this.address = await this.setupNewDefaultAddress(
+ "0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed"
+ );
+
+ this.addressTwo = await this.setupNewDefaultAddress(
+ "0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d"
+ );
+
+ this.ownerOne = await this.setupNewDefaultAddress(
+ constants.MOCK_OWNER_PRIVATE_KEYS[0]
+ );
+ this.ownerTwo = await this.setupNewDefaultAddress(
+ constants.MOCK_OWNER_PRIVATE_KEYS[1]
+ );
+ this.ownerThree = await this.setupNewDefaultAddress(
+ constants.MOCK_OWNER_PRIVATE_KEYS[2]
+ );
+ this.ownerFour = await this.setupNewDefaultAddress(
+ constants.MOCK_OWNER_PRIVATE_KEYS[3]
+ );
+ this.ownerFive = await this.setupNewDefaultAddress(
+ constants.MOCK_OWNER_PRIVATE_KEYS[4]
+ );
+
+ this.gasLimit = latestBlock.gasLimit;
+
+ const BalanceCheckerDeployer = new web3.eth.Contract(
+ BalanceCheckerArtifact.abi
+ );
+ BalanceCheckerDeployer.options.data = BalanceCheckerArtifact.bytecode;
+
+ this.BalanceChecker = await this.runTest(
+ `BalanceChecker contract deployment`,
+ BalanceCheckerDeployer,
+ "",
+ "deploy"
+ );
+
+ const MockCodeCheckDeployer = new web3.eth.Contract(
+ MockCodeCheckArtifact.abi
+ );
+ MockCodeCheckDeployer.options.data = MockCodeCheckArtifact.bytecode;
+
+ this.MockCodeCheck = await this.runTest(
+ `MockCodeCheck contract deployment`,
+ MockCodeCheckDeployer,
+ "",
+ "deploy"
+ );
+
+ await this.runTest(
+ "Deployed MockCodeCheck code is correct",
+ this.MockCodeCheck,
+ "code",
+ "call",
+ [this.MockCodeCheck.options.address],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ MockCodeCheckArtifact.deployedBytecode
+ );
+ }
+ );
+
+ await this.runTest(
+ "Deployed MockCodeCheck has correct extcodehash",
+ this.MockCodeCheck,
+ "hash",
+ "call",
+ [this.MockCodeCheck.options.address],
+ true,
+ value => {
+ assert.strictEqual(
+ value,
+ web3.utils.keccak256(
+ MockCodeCheckArtifact.deployedBytecode,
+ { encoding: "hex" }
+ )
+ );
+ }
+ );
+
+ await this.setupDeployedContracts();
+ }
+
+ async setupNewDefaultAddress(newPrivateKey) {
+ const pubKey = await web3.eth.accounts.privateKeyToAccount(
+ newPrivateKey
+ );
+ await web3.eth.accounts.wallet.add(pubKey);
+
+ await web3.eth.sendTransaction({
+ from: this.originalAddress,
+ to: pubKey.address,
+ value: 2 * 10 ** 18,
+ gas: "0x5208",
+ gasPrice: "0x4A817C800"
+ });
+
+ return pubKey.address;
+ }
+
+ async raiseGasLimit(necessaryGas) {
+ let iterations = 9999;
+
+ if (necessaryGas > 8000000) {
+ console.error("the gas needed is too high!");
+ process.exit(1);
+ } else if (typeof necessaryGas === "undefined") {
+ iterations = 20;
+ necessaryGas = 8000000;
+ }
+
+ // bring up gas limit if necessary by doing additional transactions
+ let block = await web3.eth.getBlock("latest");
+ while (iterations > 0 && block.gasLimit < necessaryGas) {
+ await web3.eth.sendTransaction({
+ from: this.originalAddress,
+ to: this.originalAddress,
+ value: "0x01",
+ gas: "0x5208",
+ gasPrice: "0x4A817C800"
+ });
+ block = await web3.eth.getBlock("latest");
+ iterations--;
+ }
+
+ console.log("raising gasLimit, currently at " + block.gasLimit);
+ return block.gasLimit;
+ }
+
+ async getDeployGas(dataPayload) {
+ await web3.eth
+ .estimateGas({
+ from: address,
+ data: dataPayload
+ })
+ .catch(async error => {
+ if (
+ error.message ===
+ "Returned error: gas required exceeds allowance or always failing " +
+ "transaction"
+ ) {
+ await this.raiseGasLimit();
+ await this.getDeployGas(dataPayload);
+ }
+ });
+
+ return web3.eth.estimateGas({
+ from: address,
+ data: dataPayload
+ });
+ }
+
+ async advanceTime(time) {
+ return new Promise((resolve, reject) => {
+ web3.currentProvider.send(
+ {
+ jsonrpc: "2.0",
+ method: "evm_increaseTime",
+ params: [time],
+ id: new Date().getTime()
+ },
+ (err, result) => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve(result);
+ }
+ );
+ });
+ }
+
+ async takeSnapshot() {
+ return new Promise((resolve, reject) => {
+ web3.currentProvider.send(
+ {
+ jsonrpc: "2.0",
+ method: "evm_snapshot",
+ id: new Date().getTime()
+ },
+ (err, snapshotId) => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve(snapshotId);
+ }
+ );
+ });
+ }
+
+ async revertToSnapShot(id) {
+ return new Promise((resolve, reject) => {
+ web3.currentProvider.send(
+ {
+ jsonrpc: "2.0",
+ method: "evm_revert",
+ params: [id],
+ id: new Date().getTime()
+ },
+ (err, result) => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve(result);
+ }
+ );
+ });
+ }
+
+ async advanceBlock() {
+ return new Promise((resolve, reject) => {
+ web3.currentProvider.send(
+ {
+ jsonrpc: "2.0",
+ method: "evm_mine",
+ id: new Date().getTime()
+ },
+ (err, result) => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve(result);
+ }
+ );
+ });
+ }
+
+ async rpc(request) {
+ return new Promise((okay, fail) =>
+ web3.currentProvider.send(request, (err, res) =>
+ err ? fail(err) : okay(res)
+ )
+ );
+ }
+
+ async getLatestBlockNumber() {
+ let { result: num } = await this.rpc({
+ method: "eth_blockNumber",
+ id: new Date().getTime() // for snapshotting
+ });
+ return num;
+ }
+
+ async advanceBlocks(blocksToAdvance, nonce) {
+ if (blocksToAdvance < 1) {
+ throw new Error("must advance at least one block.");
+ }
+
+ let currentBlockNumberHex = await this.getLatestBlockNumber();
+
+ const accountNonce =
+ typeof nonce === "undefined"
+ ? await web3.eth.getTransactionCount(this.address)
+ : nonce;
+
+ const extraBlocks = blocksToAdvance - 1;
+ const extraBlocksHex =
+ "0x" + (extraBlocks + parseInt(currentBlockNumberHex)).toString(16);
+
+ const nextBlockNumber = blocksToAdvance + 1;
+ const nextBlockNumberHex =
+ "0x" +
+ (nextBlockNumber + parseInt(currentBlockNumberHex)).toString(16);
+
+ await this.rpc({
+ method: "evm_mineBlockNumber",
+ params: [extraBlocksHex],
+ id: new Date().getTime()
+ });
+
+ const newBlockNumberHex =
+ "0x" +
+ (blocksToAdvance + parseInt(currentBlockNumberHex)).toString(16);
+ currentBlockNumberHex = await this.getLatestBlockNumber();
+
+ if (currentBlockNumberHex !== newBlockNumberHex) {
+ console.error(
+ `current block is now ${parseInt(
+ currentBlockNumberHex
+ )} - evm_mineBlockNumber failed... (expected ${parseInt(
+ newBlockNumberHex
+ )})`
+ );
+ process.exit(1);
+ }
+
+ const dummyTxReceipt = await web3.eth.sendTransaction({
+ from: this.address,
+ to: this.address,
+ data: "0x",
+ value: 0,
+ gas: 21000,
+ gasPrice: 1,
+ nonce: accountNonce
+ });
+
+ return await web3.eth.getBlock(dummyTxReceipt.blockHash);
+ }
+
+ async advanceTimeAndBlock(time) {
+ await this.advanceTime(time);
+ await this.advanceBlock();
+ return Promise.resolve(web3.eth.getBlock("latest"));
+ }
+
+ async advanceTimeAndBlocks(blocks, nonce) {
+ if (blocks < 2) {
+ return reject("must advance by at least two blocks.");
+ }
+ //let block = await web3.eth.getBlock(await this.getLatestBlockNumber())
+ await this.advanceTime(blocks * 15);
+ //block = await web3.eth.getBlock(await this.getLatestBlockNumber())
+
+ // next block must be extracted from this function ('getBlock' breaks)
+ return await this.advanceBlocks(blocks - 1, nonce);
+ }
+
+ signHashedPrefixedHexString(hashedHexString, account) {
+ const sig = util.ecsign(
+ util.toBuffer(
+ web3.utils.keccak256(
+ // prefix => "\x19Ethereum Signed Message:\n32"
+ "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
+ hashedHexString.slice(2),
+ { encoding: "hex" }
+ )
+ ),
+ util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
+ );
+
+ return (
+ util.bufferToHex(sig.r) +
+ util.bufferToHex(sig.s).slice(2) +
+ web3.utils.toHex(sig.v).slice(2)
+ );
+ }
+
+ signHashedPrefixedHashedHexString(hexString, account) {
+ const sig = util.ecsign(
+ util.toBuffer(
+ web3.utils.keccak256(
+ // prefix => "\x19Ethereum Signed Message:\n32"
+ "0x19457468657265756d205369676e6564204d6573736167653a0a3332" +
+ web3.utils
+ .keccak256(hexString, { encoding: "hex" })
+ .slice(2),
+ { encoding: "hex" }
+ )
+ ),
+ util.toBuffer(web3.eth.accounts.wallet[account].privateKey)
+ );
+
+ return (
+ util.bufferToHex(sig.r) +
+ util.bufferToHex(sig.s).slice(2) +
+ web3.utils.toHex(sig.v).slice(2)
+ );
+ }
+
+ async sendTransaction(
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ transactionShouldSucceed,
+ nonce
+ ) {
+ return instance.methods[method](...args)
+ .send({
+ from: from,
+ value: value,
+ gas: gas,
+ gasPrice: gasPrice,
+ nonce: nonce
+ })
+ .on("confirmation", (confirmationNumber, r) => {
+ confirmations[r.transactionHash] = confirmationNumber;
+ })
+ .catch(error => {
+ if (transactionShouldSucceed) {
+ console.error(error);
+ }
+ return { status: false };
+ });
+ }
+
+ async callMethod(
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ callShouldSucceed
+ ) {
+ let callSucceeded = true;
+
+ const returnValues = await instance.methods[method](...args)
+ .call({
+ from: from,
+ value: value,
+ gas: gas,
+ gasPrice: gasPrice
+ })
+ .catch(error => {
+ if (callShouldSucceed) {
+ console.error(error);
+ }
+ callSucceeded = false;
+ });
+
+ return { callSucceeded, returnValues };
+ }
+
+ async send(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ transactionShouldSucceed,
+ assertionCallback,
+ nonce
+ ) {
+ const receipt = await this.sendTransaction(
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ transactionShouldSucceed,
+ nonce
+ );
+
+ const transactionSucceeded = receipt.status;
+
+ if (transactionSucceeded) {
+ try {
+ assertionCallback(receipt);
+ } catch (error) {
+ console.log(error);
+ return false; // return false if assertions fail and throw an error
+ }
+ }
+
+ //return true if transaction success matches expectations, false if expectations are mismatched
+ return transactionSucceeded === transactionShouldSucceed;
+ }
+
+ async call(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ callShouldSucceed,
+ assertionCallback
+ ) {
+ const { callSucceeded, returnValues } = await this.callMethod(
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ callShouldSucceed
+ );
+
+ // if call succeeds, try assertion callback
+ if (callSucceeded) {
+ try {
+ assertionCallback(returnValues);
+ } catch (error) {
+ console.log(error);
+ return false;
+ }
+ }
+ return callSucceeded === callShouldSucceed;
+ }
+
+ async deploy(
+ title,
+ instance,
+ args,
+ from,
+ value,
+ gas,
+ gasPrice,
+ shouldSucceed,
+ assertionCallback
+ ) {
+ let deployData = instance.deploy({ arguments: args }).encodeABI();
+ let deployGas = await web3.eth
+ .estimateGas({
+ from: from,
+ data: deployData
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+ return this.gasLimit;
+ });
+
+ if (deployGas > this.gasLimit) {
+ console.error(
+ ` ✘ ${title}: deployment costs exceed block gas limit!`
+ );
+ process.exit(1);
+ }
+
+ if (typeof gas === "undefined") {
+ gas = deployGas;
+ }
+
+ if (deployGas > gas) {
+ console.error(` ✘ ${title}: deployment costs exceed supplied gas.`);
+ process.exit(1);
+ }
+
+ let signed;
+ let deployHash;
+ let receipt;
+ const contract = await instance
+ .deploy({ arguments: args })
+ .send({
+ from: from,
+ gas: gas,
+ gasPrice: gasPrice
+ })
+ .on("transactionHash", hash => {
+ deployHash = hash;
+ })
+ .on("receipt", r => {
+ receipt = r;
+ })
+ .on("confirmation", (confirmationNumber, r) => {
+ confirmations[r.transactionHash] = confirmationNumber;
+ })
+ .catch(error => {
+ if (shouldSucceed) {
+ console.error(error);
+ }
+
+ receipt = { status: false };
+ });
+
+ if (receipt.status !== shouldSucceed) {
+ if (contract) {
+ return [false, contract, gas];
+ }
+ return [false, instance, gas];
+ } else if (!shouldSucceed) {
+ if (contract) {
+ return [true, contract, gas];
+ }
+ return [true, instance, gas];
+ }
+
+ assert.ok(receipt.status);
+
+ let assertionsPassed;
+ try {
+ assertionCallback(receipt);
+ assertionsPassed = true;
+ } catch (error) {
+ assertionsPassed = false;
+ }
+
+ if (contract) {
+ return [assertionsPassed, contract, gas];
+ }
+ return [assertionsPassed, instance, gas];
+ }
+
+ /* aggregates the first 3 functions
+ * run test without coverage, once they're passing then run with coverage
+ * coverage changes the gas -- orders of magnitued more expensive
+ * any test that are gas dependent get grilled under coverage test
+ *
+ *
+ * default: send
+ */
+ async runTest(
+ title,
+ instance,
+ method,
+ callOrSendOrDeploy,
+ args,
+ shouldSucceed,
+ assertionCallback,
+ from,
+ value,
+ gas,
+ nonce
+ ) {
+ if (typeof callOrSendOrDeploy === "undefined") {
+ callOrSendOrDeploy = "send";
+ }
+ if (typeof args === "undefined") {
+ args = [];
+ }
+ if (typeof shouldSucceed === "undefined") {
+ shouldSucceed = true;
+ }
+ if (typeof assertionCallback === "undefined") {
+ assertionCallback = value => {};
+ }
+ if (typeof from === "undefined") {
+ from = this.address;
+ }
+ if (typeof value === "undefined") {
+ value = 0;
+ }
+ if (typeof gas === "undefined" && callOrSendOrDeploy !== "deploy") {
+ gas = 6009006;
+ if (this.context === "coverage") {
+ gas = this.gasLimit - 1;
+ }
+ }
+ let ok = false;
+ let contract;
+ let deployGas;
+ if (callOrSendOrDeploy === "send") {
+ ok = await this.send(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback,
+ nonce
+ );
+ } else if (callOrSendOrDeploy === "call") {
+ ok = await this.call(
+ title,
+ instance,
+ method,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback
+ );
+ } else if (callOrSendOrDeploy === "deploy") {
+ const fields = await this.deploy(
+ title,
+ instance,
+ args,
+ from,
+ value,
+ gas,
+ 1,
+ shouldSucceed,
+ assertionCallback
+ );
+ ok = fields[0];
+ contract = fields[1];
+ deployGas = fields[2];
+ } else {
+ console.error("must use call, send, or deploy!");
+ process.exit(1);
+ }
+
+ if (ok) {
+ console.log(
+ ` ✓ ${
+ callOrSendOrDeploy === "deploy" ? "successful " : ""
+ }${title}${
+ callOrSendOrDeploy === "deploy" ? ` (${deployGas} gas)` : ""
+ }`
+ );
+ this.passed++;
+ } else {
+ console.log(
+ ` ✘ ${
+ callOrSendOrDeploy === "deploy" ? "failed " : ""
+ }${title}${
+ callOrSendOrDeploy === "deploy" ? ` (${deployGas} gas)` : ""
+ }`
+ );
+ this.failed++;
+ }
+
+ if (contract) {
+ return contract;
+ }
+ }
+
+ async withBalanceCheck(account, initial, final, test, testArgs) {
+ // Get the initial balances.
+ const initialBalances = await this.getBalances(account);
+ const initialBalancesSet = new Set(Object.keys(initialBalances));
+
+ const initialSet = new Set(Object.keys(initial));
+ const finalSet = new Set(Object.keys(final));
+
+ // Initial and final sets must both have the same balance checks.
+ assert.strictEqual(initialSet.size, finalSet.size);
+ assert.strictEqual(
+ initialSet.size,
+ new Set([...initialSet, ...finalSet]).size
+ );
+
+ // Ensure that all the specified balance checks are actually returned.
+ assert.strictEqual(
+ new Set([...initialSet].filter(x => !initialBalancesSet.has(x)))
+ .size,
+ 0
+ );
+
+ // Get specified keys from balance check and compare to expected values.
+ const balanceChecks = [
+ ...new Set([...initialSet].filter(x => initialBalancesSet.has(x)))
+ ];
+
+ for (const balance of balanceChecks) {
+ assert.strictEqual(initialBalances[balance], initial[balance]);
+ }
+
+ // Run the test.
+ await test.bind(this)(...testArgs);
+
+ // Get the final balances.
+ const finalBalances = await this.getBalances(account);
+
+ for (const balance of balanceChecks) {
+ assert.strictEqual(finalBalances[balance], final[balance]);
+ }
+ }
+
+ async getBalances(account) {
+ const balances = await this.BalanceChecker.methods
+ .getBalances(account)
+ .call()
+ .catch(error => {
+ console.error(error);
+ process.exit(1);
+ });
+
+ const underlyingBalances = await this.BalanceChecker.methods
+ .getUnderlyingBalances(account)
+ .call()
+ .catch(error => {
+ console.error(error);
+ process.exit(1);
+ });
+
+ return {
+ account,
+ dDai:
+ parseFloat(web3.utils.fromWei(balances.dDaiBalance, "gwei")) *
+ 10,
+ dUSDC:
+ parseFloat(web3.utils.fromWei(balances.dUSDCBalance, "gwei")) *
+ 10,
+ dai: parseFloat(web3.utils.fromWei(balances.daiBalance, "ether")),
+ usdc: parseFloat(web3.utils.fromWei(balances.usdcBalance, "mwei")),
+ sai: parseFloat(web3.utils.fromWei(balances.saiBalance, "ether")),
+ cSai:
+ parseFloat(web3.utils.fromWei(balances.cSaiBalance, "gwei")) *
+ 10,
+ cDai:
+ parseFloat(web3.utils.fromWei(balances.cDaiBalance, "gwei")) *
+ 10,
+ cUSDC:
+ parseFloat(web3.utils.fromWei(balances.cUSDCBalance, "gwei")) *
+ 10,
+ ether: parseFloat(
+ web3.utils.fromWei(balances.etherBalance, "ether")
+ ),
+ dDaiUnderlying: parseFloat(
+ web3.utils.fromWei(
+ underlyingBalances.dDaiBalanceUnderlying,
+ "ether"
+ )
+ ),
+ dUSDCUnderlying: parseFloat(
+ web3.utils.fromWei(
+ underlyingBalances.dUSDCBalanceUnderlying,
+ "mwei"
+ )
+ ),
+ cSaiUnderlying: parseFloat(
+ web3.utils.fromWei(
+ underlyingBalances.cSaiBalanceUnderlying,
+ "ether"
+ )
+ ),
+ cDaiUnderlying: parseFloat(
+ web3.utils.fromWei(
+ underlyingBalances.cDaiBalanceUnderlying,
+ "ether"
+ )
+ ),
+ cUSDCUnderlying: parseFloat(
+ web3.utils.fromWei(
+ underlyingBalances.cUSDCBalanceUnderlying,
+ "mwei"
+ )
+ ),
+ dDaiRaw: balances.dDaiBalance,
+ dUSDCRaw: balances.dUSDCBalance,
+ daiRaw: balances.daiBalance,
+ usdcRaw: balances.usdcBalance,
+ saiRaw: balances.saiBalance,
+ cSaiRaw: balances.cSaiBalance,
+ cDaiRaw: balances.cDaiBalance,
+ cUSDCRaw: balances.cUSDCBalance,
+ etherRaw: balances.etherBalance,
+ dDaiUnderlyingRaw: underlyingBalances.dDaiBalanceUnderlying,
+ dUSDCUnderlyingRaw: underlyingBalances.dUSDCBalanceUnderlying,
+ cSaiUnderlyingRaw: underlyingBalances.cSaiBalanceUnderlying,
+ cDaiUnderlyingRaw: underlyingBalances.cDaiBalanceUnderlying,
+ cUSDCUnderlyingRaw: underlyingBalances.cUSDCBalanceUnderlying
+ };
+ }
+
+ getEvents(receipt, contractNames) {
+ const { events } = receipt;
+
+ // web3 "helpfully" collects multiple events into arrays... flatten them :)
+ let flattenedEvents = {};
+ for (const e of Object.values(events)) {
+ if (Array.isArray(e)) {
+ for (const n of e) {
+ flattenedEvents[n.logIndex] = n;
+ }
+ } else {
+ flattenedEvents[e.logIndex] = e;
+ }
+ }
+
+ return Object.values(flattenedEvents)
+ .map(value => {
+ // Handle MKR events independently (Pot and Vat called by cDai)
+ if (value.raw.topics.length === 4) {
+ const callerAddress = web3.utils.toChecksumAddress(
+ "0x" + value.raw.topics[1].slice(26)
+ );
+ return {
+ address: contractNames[value.address],
+ eventName: null,
+ returnValues: {
+ selector: value.raw.topics[0].slice(0, 10),
+ caller:
+ callerAddress in contractNames
+ ? contractNames[callerAddress]
+ : callerAddress,
+ arg1: value.raw.topics[2],
+ arg2: value.raw.topics[3]
+ }
+ };
+ }
+
+ const topic = value.raw.topics[0];
+ const log = constants.EVENT_DETAILS[topic];
+
+ return {
+ address: contractNames[value.address],
+ eventName: log.name,
+ returnValues: web3.eth.abi.decodeLog(
+ log.abi,
+ value.raw.data,
+ value.raw.topics.slice(1)
+ )
+ };
+ })
+ .filter(value => value !== null);
+ }
+
+ async checkAndDeploy(
+ name,
+ address,
+ salt,
+ runtimeCode,
+ creationCode,
+ mockCodeCheck,
+ create2Factory
+ ) {
+ let currentCode;
+ await this.runTest(
+ `Checking ${name} runtime code`,
+ mockCodeCheck,
+ "code",
+ "call",
+ [address],
+ true,
+ value => {
+ currentCode = value;
+ }
+ );
+
+ if (currentCode !== runtimeCode) {
+ await this.runTest(
+ `${name} contract address check through immutable create2 factory`,
+ create2Factory,
+ "findCreate2Address",
+ "call",
+ [salt, creationCode],
+ true,
+ value => {
+ assert.strictEqual(value, address);
+ }
+ );
+
+ await this.runTest(
+ `${name} contract deployment through immutable create2 factory`,
+ create2Factory,
+ "safeCreate2",
+ "send",
+ [salt, creationCode]
+ );
+ }
+
+ await this.runTest(
+ `Deployed ${name} code is correct`,
+ mockCodeCheck,
+ "code",
+ "call",
+ [address],
+ true,
+ value => {
+ assert.strictEqual(value, runtimeCode);
+ }
+ );
+ }
+
+ newDeployer(artifact) {
+ let deployer = new web3.eth.Contract(artifact.abi);
+ deployer.options.data = artifact.bytecode;
+ return deployer;
+ }
+
+ async setupDeployedContracts() {
+ this.DharmaUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
+ this.DharmaUpgradeBeacon = new web3.eth.Contract(
+ DharmaUpgradeBeaconArtifact.abi,
+ constants.UPGRADE_BEACON_ADDRESS
+ );
+ this.DharmaKeyRingUpgradeBeaconController = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerArtifact.abi,
+ constants.KEY_RING_UPGRADE_BEACON_CONTROLLER_ADDRESS
+ );
+
+ this.DharmaKeyRingUpgradeBeacon = new web3.eth.Contract(
+ DharmaKeyRingUpgradeBeaconArtifact.abi,
+ constants.KEY_RING_UPGRADE_BEACON_ADDRESS
+ );
+
+ this.DharmaAccountRecoveryManagerV2 = new web3.eth.Contract(
+ DharmaAccountRecoveryManagerV2Artifact.abi,
+ constants.ACCOUNT_RECOVERY_MANAGER_V2_ADDRESS
+ );
+
+ this.DharmaKeyRegistryV2 = new web3.eth.Contract(
+ DharmaKeyRegistryV2Artifact.abi,
+ constants.KEY_REGISTRY_V2_ADDRESS
+ );
+
+ this.DharmaUpgradeBeaconControllerManager = new web3.eth.Contract(
+ DharmaUpgradeBeaconControllerManagerArtifact.abi,
+ constants.UPGRADE_BEACON_CONTROLLER_MANAGER_ADDRESS
+ );
+
+ this.DharmaSmartWalletFactoryV1OnChain = new web3.eth.Contract(
+ DharmaSmartWalletFactoryV1Artifact.abi,
+ constants.FACTORY_ADDRESS
+ );
+
+ this.Comptroller = new web3.eth.Contract(
+ constants.COMPTROLLER_ABI,
+ constants.COMPTROLLER_MAINNET_ADDRESS
+ );
+
+ this.CSAI_BORROW = new web3.eth.Contract(
+ [
+ {
+ constant: false,
+ inputs: [{ name: "borrowAmount", type: "uint256" }],
+ name: "borrow",
+ outputs: [{ name: "", type: "uint256" }],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ }
+ ],
+ constants.CSAI_MAINNET_ADDRESS
+ );
+
+ this.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
+ );
+
+ this.SAI = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.SAI_MAINNET_ADDRESS
+ );
+
+ this.DAI = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.DAI_MAINNET_ADDRESS
+ );
+
+ this.USDC = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.USDC_MAINNET_ADDRESS
+ );
+
+ this.CSAI = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.CSAI_MAINNET_ADDRESS
+ );
+
+ this.CSAI_MINT = new web3.eth.Contract(
+ CTokenInterfaceArtifact.abi,
+ constants.CSAI_MAINNET_ADDRESS
+ );
+
+ this.CDAI = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.CDAI_MAINNET_ADDRESS
+ );
+
+ this.CUSDC = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.CUSDC_MAINNET_ADDRESS
+ );
+
+ this.DDAI = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.DDAI_MAINNET_ADDRESS
+ );
+
+ this.DUSDC = new web3.eth.Contract(
+ IERC20Artifact.abi,
+ constants.DUSDC_MAINNET_ADDRESS
+ );
+
+ const MetaABI = [
+ {
+ constant: false,
+ inputs: [
+ { internalType: "address", name: "owner", type: "address" },
+ {
+ internalType: "address",
+ name: "spender",
+ type: "address"
+ },
+ { internalType: "uint256", name: "value", type: "uint256" },
+ { internalType: "bool", name: "increase", type: "bool" },
+ {
+ internalType: "uint256",
+ name: "expiration",
+ type: "uint256"
+ },
+ { internalType: "bytes32", name: "salt", type: "bytes32" },
+ { internalType: "bytes", name: "signatures", type: "bytes" }
+ ],
+ name: "modifyAllowanceViaMetaTransaction",
+ outputs: [
+ { internalType: "bool", name: "success", type: "bool" }
+ ],
+ payable: false,
+ stateMutability: "nonpayable",
+ type: "function"
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ internalType: "bytes4",
+ name: "functionSelector",
+ type: "bytes4"
+ },
+ { internalType: "bytes", name: "arguments", type: "bytes" },
+ {
+ internalType: "uint256",
+ name: "expiration",
+ type: "uint256"
+ },
+ { internalType: "bytes32", name: "salt", type: "bytes32" }
+ ],
+ name: "getMetaTransactionMessageHash",
+ outputs: [
+ {
+ internalType: "bytes32",
+ name: "messageHash",
+ type: "bytes32"
+ },
+ { internalType: "bool", name: "valid", type: "bool" }
+ ],
+ payable: false,
+ stateMutability: "view",
+ type: "function"
+ }
+ ];
+
+ this.DDAI_META = new web3.eth.Contract(
+ MetaABI,
+ constants.DDAI_MAINNET_ADDRESS
+ );
+
+ this.DUSDC_META = new web3.eth.Contract(
+ MetaABI,
+ constants.DUSDC_MAINNET_ADDRESS
+ );
+
+ this.BadBeaconDeployer = this.newDeployer(BadBeaconArtifact);
+
+ this.BadBeaconTwoDeployer = this.newDeployer(BadBeaconTwoArtifact);
+
+ this.AdharmaSmartWalletImplementationDeployer = this.newDeployer(
+ AdharmaSmartWalletImplementationArtifact
+ );
+
+ this.DharmaSmartWalletImplementationV6Deployer = this.newDeployer(
+ DharmaSmartWalletImplementationV6Artifact
+ );
+
+ this.DharmaSmartWalletImplementationV7Deployer = this.newDeployer(
+ DharmaSmartWalletImplementationV7Artifact
+ );
+
+ this.AdharmaKeyRingImplementationDeployer = this.newDeployer(
+ AdharmaKeyRingImplementationArtifact
+ );
+
+ this.DharmaKeyRingImplementationV1Deployer = this.newDeployer(
+ DharmaKeyRingImplementationV1Artifact
+ );
+
+ this.UpgradeBeaconImplementationCheckDeployer = this.newDeployer(
+ UpgradeBeaconImplementationCheckArtifact
+ );
+
+ this.TimelockEdgecaseTesterDeployer = this.newDeployer(
+ TimelockEdgecaseTesterArtifact
+ );
+
+ this.DharmaUpgradeBeaconControllerDeployer = this.newDeployer(
+ DharmaUpgradeBeaconControllerArtifact
+ );
+
+ this.DharmaUpgradeBeaconDeployer = this.newDeployer(
+ DharmaUpgradeBeaconArtifact
+ );
+
+ this.DharmaKeyRingUpgradeBeaconDeployer = this.newDeployer(
+ DharmaKeyRingUpgradeBeaconArtifact
+ );
+
+ this.DharmaUpgradeBeaconEnvoyDeployer = this.newDeployer(
+ DharmaUpgradeBeaconEnvoyArtifact
+ );
+
+ this.DharmaUpgradeBeaconControllerManagerDeployer = this.newDeployer(
+ DharmaUpgradeBeaconControllerManagerArtifact
+ );
+
+ this.UpgradeBeaconProxyV1Deployer = this.newDeployer(
+ UpgradeBeaconProxyV1Artifact
+ );
+
+ this.KeyRingUpgradeBeaconProxyV1Deployer = this.newDeployer(
+ KeyRingUpgradeBeaconProxyV1Artifact
+ );
+
+ this.DharmaKeyRegistryV2Deployer = this.newDeployer(
+ DharmaKeyRegistryV2Artifact
+ );
+
+ this.DharmaSmartWalletFactoryV1Deployer = this.newDeployer(
+ DharmaSmartWalletFactoryV1Artifact
+ );
+
+ this.DharmaSmartWalletFactoryV2Deployer = this.newDeployer(
+ DharmaSmartWalletFactoryV2Artifact
+ );
+
+ this.DharmaKeyRingFactoryV1Deployer = this.newDeployer(
+ DharmaKeyRingFactoryV1Artifact
+ );
+
+ this.DharmaKeyRingFactoryV2Deployer = this.newDeployer(
+ DharmaKeyRingFactoryV2Artifact
+ );
+
+ this.DharmaKeyRingFactoryV3Deployer = this.newDeployer(
+ DharmaKeyRingFactoryV3Artifact
+ );
+
+ this.MockDharmaKeyRingFactoryDeployer = this.newDeployer(
+ MockDharmaKeyRingFactoryArtifact
+ );
+
+ this.DharmaAccountRecoveryManagerV2Deployer = this.newDeployer(
+ DharmaAccountRecoveryManagerV2Artifact
+ );
+
+ this.DharmaUpgradeMultisigDeployer = this.newDeployer(
+ DharmaUpgradeMultisigArtifact
+ );
+
+ this.DharmaAccountRecoveryMultisigDeployer = this.newDeployer(
+ DharmaAccountRecoveryMultisigArtifact
+ );
+
+ this.DharmaAccountRecoveryOperatorMultisigDeployer = this.newDeployer(
+ DharmaAccountRecoveryOperatorMultisigArtifact
+ );
+
+ this.DharmaKeyRegistryMultisigDeployer = this.newDeployer(
+ DharmaKeyRegistryMultisigArtifact
+ );
+
+ this.DharmaEscapeHatchRegistryDeployer = this.newDeployer(
+ DharmaEscapeHatchRegistryArtifact
+ );
+ }
+}
+
+function swapMetadataHash(bytecode, newMetadataHashes) {
+ const totalBzzrs = bytecode.split(constants.METADATA_IDENTIFIER).length - 1;
+
+ if (totalBzzrs !== newMetadataHashes.length) {
+ throw "number of metadata hashes to replace must match provided number.";
+ }
+
+ let startingPoint = bytecode.length - 1;
+
+ for (let i = 0; i < totalBzzrs; i++) {
+ let replacement =
+ constants.METADATA_IDENTIFIER + newMetadataHashes.slice(i)[0];
+ let lastIndex = bytecode.lastIndexOf(
+ constants.METADATA_IDENTIFIER,
+ startingPoint
+ );
+ bytecode =
+ bytecode.slice(0, lastIndex) +
+ replacement +
+ bytecode.slice(lastIndex + replacement.length, bytecode.length);
+ startingPoint = lastIndex - 1;
+ }
+ return bytecode;
+}
+
+function newContractAndSwapMetadataHash(artifact) {
+ const contract = new web3.eth.Contract(artifact.abi);
+
+ contract.options.data = swapMetadataHash(artifact.bytecode, [
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ ]);
+
+ return contract;
+}
+
+// used to wait for more confirmations
+function longer() {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve();
+ }, 500);
+ });
+}
+
+module.exports = {
+ Tester,
+ swapMetadataHash,
+ newContractAndSwapMetadataHash,
+ longer
+};
diff --git a/scripts/test/web3.js b/scripts/test/web3.js
new file mode 100644
index 0000000..30ad0c2
--- /dev/null
+++ b/scripts/test/web3.js
@@ -0,0 +1,11 @@
+const context = process.env.TESTING_CONTEXT;
+
+const connectionConfig = require("../../truffle-config.js");
+
+const connection = connectionConfig.networks[context];
+
+const web3 = connection.provider;
+
+module.exports = {
+ web3
+};
diff --git a/yarn.lock b/yarn.lock
index 479ab1c..da1caff 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -25,11 +25,46 @@
dependencies:
regenerator-runtime "^0.13.2"
+"@babel/runtime@^7.6.3":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308"
+ integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==
+ dependencies:
+ regenerator-runtime "^0.13.2"
+
+"@nodelib/fs.scandir@2.1.3":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
+ integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.3"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
+ integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
+ integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.3"
+ fastq "^1.6.0"
+
"@openzeppelin/contracts@2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-2.3.0.tgz#043961a6e37b87e0eb80647c7528a7c62c41361f"
integrity sha512-lf8C3oULQAnsu3OTRP4tP5/ddfil6l65Lg3JQCwAIgc99vZ1jz5qeBoETGGGmczxt+bIyMI06WPP2apC74EZag==
+"@samverschueren/stream-to-observable@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
+ integrity sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==
+ dependencies:
+ any-observable "^0.3.0"
+
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
@@ -49,6 +84,30 @@
dependencies:
"@types/node" "*"
+"@types/color-name@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
+ integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
+
+"@types/events@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+ integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/glob@^7.1.1":
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+ integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+ dependencies:
+ "@types/events" "*"
+ "@types/minimatch" "*"
+ "@types/node" "*"
+
+"@types/minimatch@*", "@types/minimatch@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
"@types/node@*":
version "12.7.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.1.tgz#3b5c3a26393c19b400844ac422bd0f631a94d69d"
@@ -59,6 +118,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.15.tgz#e8f7729b631be1b02ae130ff0b61f3e018000640"
integrity sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g==
+"@types/parse-json@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
JSONStream@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@@ -121,6 +185,14 @@ agentkeepalive@^3.4.1:
dependencies:
humanize-ms "^1.2.1"
+aggregate-error@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0"
+ integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==
+ dependencies:
+ clean-stack "^2.0.0"
+ indent-string "^4.0.0"
+
ajv@^5.2.2:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
@@ -160,6 +232,11 @@ ansi-colors@^1.0.1:
dependencies:
ansi-wrap "^0.1.0"
+ansi-escapes@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+ integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
ansi-escapes@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.1.tgz#4dccdb846c3eee10f6d64dea66273eab90c37228"
@@ -201,6 +278,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
+ansi-styles@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
+ integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
+ dependencies:
+ "@types/color-name" "^1.1.1"
+ color-convert "^2.0.1"
+
ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
@@ -211,6 +296,11 @@ antlr4@4.7.1:
resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773"
integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==
+any-observable@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
+ integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==
+
any-promise@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@@ -305,6 +395,11 @@ arr-union@^3.1.0:
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+array-differ@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
+ integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
+
array-each@^1.0.0, array-each@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
@@ -344,6 +439,11 @@ array-sort@^1.0.0:
get-value "^2.0.6"
kind-of "^5.0.2"
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
@@ -354,6 +454,11 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+arrify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
asn1.js@^4.0.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
@@ -587,6 +692,13 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
+braces@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -816,7 +928,7 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-chalk@^1.1.1:
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
@@ -827,7 +939,7 @@ chalk@^1.1.1:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -836,6 +948,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
+chalk@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
+ integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
@@ -909,11 +1029,23 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
+clean-stack@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
+ integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
+
cli-boxes@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
+cli-cursor@^2.0.0, cli-cursor@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+ integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+ dependencies:
+ restore-cursor "^2.0.0"
+
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@@ -928,6 +1060,14 @@ cli-table@^0.3.1:
dependencies:
colors "1.0.3"
+cli-truncate@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
+ integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=
+ dependencies:
+ slice-ansi "0.0.4"
+ string-width "^1.0.1"
+
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
@@ -1025,11 +1165,23 @@ color-convert@^1.9.0:
dependencies:
color-name "1.1.3"
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
color-support@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
@@ -1067,7 +1219,7 @@ commander@2.18.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970"
integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==
-commander@^2.9.0, commander@~2.20.3:
+commander@^2.20.0, commander@^2.9.0, commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -1084,6 +1236,11 @@ commander@~2.8.1:
dependencies:
graceful-readlink ">= 1.0.0"
+compare-versions@^3.5.1:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393"
+ integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==
+
component-emitter@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
@@ -1193,7 +1350,7 @@ cors@^2.8.1:
object-assign "^4"
vary "^1"
-cosmiconfig@^5.0.7:
+cosmiconfig@^5.0.7, cosmiconfig@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
@@ -1203,6 +1360,17 @@ cosmiconfig@^5.0.7:
js-yaml "^3.13.1"
parse-json "^4.0.0"
+cosmiconfig@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982"
+ integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.1.0"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.7.2"
+
create-ecdh@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
@@ -1254,6 +1422,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
+cross-spawn@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
+ integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
crypto-browserify@3.12.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
@@ -1296,6 +1473,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
+date-fns@^1.27.2:
+ version "1.30.1"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
+ integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
+
death@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318"
@@ -1399,6 +1581,11 @@ decompress@^4.0.0:
pify "^2.3.0"
strip-dirs "^2.0.0"
+dedent@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
+ integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
+
deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
@@ -1455,6 +1642,20 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
+del@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
+ integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==
+ dependencies:
+ globby "^10.0.1"
+ graceful-fs "^4.2.2"
+ is-glob "^4.0.1"
+ is-path-cwd "^2.2.0"
+ is-path-inside "^3.0.1"
+ p-map "^3.0.0"
+ rimraf "^3.0.0"
+ slash "^3.0.0"
+
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -1512,6 +1713,13 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
@@ -1576,6 +1784,11 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+elegant-spinner@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
+ integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=
+
elliptic@6.3.3:
version "6.3.3"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f"
@@ -2018,6 +2231,21 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^2.0.3, execa@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99"
+ integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==
+ dependencies:
+ cross-spawn "^7.0.0"
+ get-stream "^5.0.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^3.0.0"
+ onetime "^5.1.0"
+ p-finally "^2.0.0"
+ signal-exit "^3.0.2"
+ strip-final-newline "^2.0.0"
+
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
@@ -2173,6 +2401,17 @@ fast-diff@^1.1.2, fast-diff@^1.2.0:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
+fast-glob@^3.0.3:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82"
+ integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.0"
+ merge2 "^1.3.0"
+ micromatch "^4.0.2"
+
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -2183,6 +2422,13 @@ fast-levenshtein@~2.0.4:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+fastq@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2"
+ integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==
+ dependencies:
+ reusify "^1.0.0"
+
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
@@ -2195,6 +2441,21 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
+figures@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+ integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
+ dependencies:
+ escape-string-regexp "^1.0.5"
+ object-assign "^4.1.0"
+
+figures@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+ integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
figures@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9"
@@ -2255,6 +2516,13 @@ fill-range@^4.0.0:
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
@@ -2268,7 +2536,7 @@ finalhandler@~1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
-find-up@4.1.0:
+find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
@@ -2298,6 +2566,13 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
+find-versions@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e"
+ integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==
+ dependencies:
+ semver-regex "^2.0.0"
+
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@@ -2529,6 +2804,11 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-own-enumerable-property-symbols@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
+ integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
+
get-stdin@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
@@ -2554,7 +2834,7 @@ get-stream@^4.0.0, get-stream@^4.1.0:
dependencies:
pump "^3.0.0"
-get-stream@^5.1.0:
+get-stream@^5.0.0, get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
@@ -2596,6 +2876,13 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
+glob-parent@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
+ integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
+ dependencies:
+ is-glob "^4.0.1"
+
glob-stream@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
@@ -2699,6 +2986,20 @@ globals@^11.7.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+globby@^10.0.1:
+ version "10.0.2"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
+ integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
+ dependencies:
+ "@types/glob" "^7.1.1"
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.0.3"
+ glob "^7.1.3"
+ ignore "^5.1.1"
+ merge2 "^1.2.3"
+ slash "^3.0.0"
+
glogg@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f"
@@ -2748,6 +3049,11 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.1
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.1.tgz#1c1f0c364882c868f5bff6512146328336a11b1d"
integrity sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==
+graceful-fs@^4.2.2:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
+ integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+
"graceful-readlink@>= 1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
@@ -2850,6 +3156,11 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
has-symbol-support-x@^1.4.1:
version "1.4.2"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
@@ -3036,6 +3347,22 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
+husky@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.1.tgz#b09f1bd9129e6c323cc515dc17081d0615e2d7c1"
+ integrity sha512-Qa0lRreeIf4Tl92sSs42ER6qc3hzoyQPPorzOrFWfPEVbdi6LuvJEqWKPk905fOWIR76iBpp7ECZNIwk+a8xuQ==
+ dependencies:
+ chalk "^3.0.0"
+ ci-info "^2.0.0"
+ compare-versions "^3.5.1"
+ cosmiconfig "^6.0.0"
+ find-versions "^3.2.0"
+ opencollective-postinstall "^2.0.2"
+ pkg-dir "^4.2.0"
+ please-upgrade-node "^3.2.0"
+ slash "^3.0.0"
+ which-pm-runs "^1.0.0"
+
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -3072,6 +3399,11 @@ ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+ignore@^5.1.1, ignore@^5.1.4:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
+ integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
+
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
@@ -3088,6 +3420,14 @@ import-fresh@^3.0.0:
parent-module "^1.0.0"
resolve-from "^4.0.0"
+import-fresh@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
+ integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
@@ -3098,6 +3438,16 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+indent-string@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+ integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
+
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
infer-owner@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
@@ -3333,7 +3683,7 @@ is-glob@^3.1.0:
dependencies:
is-extglob "^2.1.0"
-is-glob@^4.0.0:
+is-glob@^4.0.0, is-glob@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -3387,7 +3737,12 @@ is-number@^4.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
-is-obj@^1.0.0:
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-obj@^1.0.0, is-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
@@ -3397,6 +3752,18 @@ is-object@^1.0.1:
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
+is-observable@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e"
+ integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==
+ dependencies:
+ symbol-observable "^1.1.0"
+
+is-path-cwd@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+ integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
is-path-inside@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
@@ -3404,6 +3771,11 @@ is-path-inside@^1.0.0:
dependencies:
path-is-inside "^1.0.1"
+is-path-inside@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
+ integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
+
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -3438,6 +3810,11 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
+is-regexp@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
+ integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
+
is-relative@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
@@ -3455,6 +3832,11 @@ is-stream@^1.0.0, is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+
is-symbol@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
@@ -3796,6 +4178,75 @@ liftoff@^3.1.0:
rechoir "^0.6.2"
resolve "^1.1.7"
+lines-and-columns@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+ integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+
+lint-staged@^9.2.1:
+ version "9.5.0"
+ resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-9.5.0.tgz#290ec605252af646d9b74d73a0fa118362b05a33"
+ integrity sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA==
+ dependencies:
+ chalk "^2.4.2"
+ commander "^2.20.0"
+ cosmiconfig "^5.2.1"
+ debug "^4.1.1"
+ dedent "^0.7.0"
+ del "^5.0.0"
+ execa "^2.0.3"
+ listr "^0.14.3"
+ log-symbols "^3.0.0"
+ micromatch "^4.0.2"
+ normalize-path "^3.0.0"
+ please-upgrade-node "^3.1.1"
+ string-argv "^0.3.0"
+ stringify-object "^3.3.0"
+
+listr-silent-renderer@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e"
+ integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=
+
+listr-update-renderer@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2"
+ integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==
+ dependencies:
+ chalk "^1.1.3"
+ cli-truncate "^0.2.1"
+ elegant-spinner "^1.0.1"
+ figures "^1.7.0"
+ indent-string "^3.0.0"
+ log-symbols "^1.0.2"
+ log-update "^2.3.0"
+ strip-ansi "^3.0.1"
+
+listr-verbose-renderer@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db"
+ integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==
+ dependencies:
+ chalk "^2.4.1"
+ cli-cursor "^2.1.0"
+ date-fns "^1.27.2"
+ figures "^2.0.0"
+
+listr@^0.14.3:
+ version "0.14.3"
+ resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586"
+ integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==
+ dependencies:
+ "@samverschueren/stream-to-observable" "^0.3.0"
+ is-observable "^1.1.0"
+ is-promise "^2.1.0"
+ is-stream "^1.1.0"
+ listr-silent-renderer "^1.1.1"
+ listr-update-renderer "^0.5.0"
+ listr-verbose-renderer "^0.5.0"
+ p-map "^2.0.0"
+ rxjs "^6.3.3"
+
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -3835,6 +4286,29 @@ lodash@^4.14.2, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.2.0
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+log-symbols@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
+ integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=
+ dependencies:
+ chalk "^1.0.0"
+
+log-symbols@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
+ integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==
+ dependencies:
+ chalk "^2.4.2"
+
+log-update@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708"
+ integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg=
+ dependencies:
+ ansi-escapes "^3.0.0"
+ cli-cursor "^2.0.0"
+ wrap-ansi "^3.0.1"
+
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
@@ -3960,6 +4434,16 @@ merge-descriptors@1.0.1:
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.2.3, merge2@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
+ integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
+
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@@ -4003,6 +4487,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
+micromatch@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
+ integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+ dependencies:
+ braces "^3.0.1"
+ picomatch "^2.0.5"
+
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -4185,6 +4677,11 @@ move-concurrently@^1.0.1:
rimraf "^2.5.4"
run-queue "^1.0.3"
+mri@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
+ integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==
+
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -4200,6 +4697,17 @@ ms@^2.0.0, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+multimatch@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
+ integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
+ dependencies:
+ "@types/minimatch" "^3.0.3"
+ array-differ "^3.0.0"
+ array-union "^2.1.0"
+ arrify "^2.0.1"
+ minimatch "^3.0.4"
+
mute-stdout@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331"
@@ -4440,6 +4948,13 @@ npm-run-path@^2.0.0:
dependencies:
path-key "^2.0.0"
+npm-run-path@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5"
+ integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==
+ dependencies:
+ path-key "^3.0.0"
+
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -4566,6 +5081,13 @@ once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
dependencies:
wrappy "1"
+onetime@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+ integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+ dependencies:
+ mimic-fn "^1.0.0"
+
onetime@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5"
@@ -4573,6 +5095,11 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
+opencollective-postinstall@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89"
+ integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==
+
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
@@ -4668,6 +5195,11 @@ p-finally@^1.0.0:
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+p-finally@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
+ integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
+
p-is-promise@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
@@ -4708,6 +5240,18 @@ p-locate@^4.1.0:
dependencies:
p-limit "^2.2.0"
+p-map@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
+ integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
+
+p-map@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
+ integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
+ dependencies:
+ aggregate-error "^3.0.0"
+
p-timeout@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
@@ -4838,6 +5382,16 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
+parse-json@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f"
+ integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-better-errors "^1.0.1"
+ lines-and-columns "^1.1.6"
+
parse-node-version@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
@@ -4895,6 +5449,11 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
path-parse@^1.0.5, path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@@ -4926,6 +5485,11 @@ path-type@^1.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
pbkdf2@^3.0.3:
version "3.0.17"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
@@ -4952,6 +5516,11 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+picomatch@^2.0.5:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
+ integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -4974,6 +5543,20 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+pkg-dir@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+ dependencies:
+ find-up "^4.0.0"
+
+please-upgrade-node@^3.1.1, please-upgrade-node@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
+ integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==
+ dependencies:
+ semver-compare "^1.0.0"
+
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
@@ -4999,6 +5582,11 @@ preserve@^0.2.0:
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+prettier@1.16.4:
+ version "1.16.4"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
+ integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==
+
prettier@^1.14.3:
version "1.18.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
@@ -5009,6 +5597,18 @@ pretty-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
+pretty-quick@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-2.0.1.tgz#417ee605ade98ecc686e72f63b5d28a2c35b43e9"
+ integrity sha512-y7bJt77XadjUr+P1uKqZxFWLddvj3SKY6EU4BuQtMxmmEFSMpbN132pUWdSG1g1mtUfO0noBvn7wBf0BVeomHg==
+ dependencies:
+ chalk "^2.4.2"
+ execa "^2.1.0"
+ find-up "^4.1.0"
+ ignore "^5.1.4"
+ mri "^1.1.4"
+ multimatch "^4.0.0"
+
process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -5470,6 +6070,14 @@ responselike@^1.0.2:
dependencies:
lowercase-keys "^1.0.0"
+restore-cursor@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+ integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+ dependencies:
+ onetime "^2.0.0"
+ signal-exit "^3.0.2"
+
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@@ -5488,6 +6096,11 @@ retry@^0.10.0:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
+reusify@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@@ -5495,6 +6108,13 @@ rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
dependencies:
glob "^7.1.3"
+rimraf@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.1.tgz#48d3d4cb46c80d388ab26cd61b1b466ae9ae225a"
+ integrity sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==
+ dependencies:
+ glob "^7.1.3"
+
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -5518,6 +6138,11 @@ run-async@^2.2.0:
dependencies:
is-promise "^2.1.0"
+run-parallel@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
+ integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
+
run-queue@^1.0.0, run-queue@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
@@ -5525,6 +6150,13 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
+rxjs@^6.3.3:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+ integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
+ dependencies:
+ tslib "^1.9.0"
+
rxjs@^6.4.0:
version "6.5.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
@@ -5595,6 +6227,11 @@ seek-bzip@^1.0.5:
dependencies:
commander "~2.8.1"
+semver-compare@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
+ integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
+
semver-diff@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@@ -5609,6 +6246,11 @@ semver-greatest-satisfied-range@^1.1.0:
dependencies:
sver-compat "^1.5.0"
+semver-regex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338"
+ integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==
+
semver-utils@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/semver-utils/-/semver-utils-1.1.4.tgz#cf0405e669a57488913909fc1c3f29bf2a4871e2"
@@ -5721,11 +6363,23 @@ shebang-command@^1.2.0:
dependencies:
shebang-regex "^1.0.0"
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
shelljs@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
@@ -5759,6 +6413,16 @@ sisteransi@^1.0.3:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.3.tgz#98168d62b79e3a5e758e27ae63c4a053d748f4eb"
integrity sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+slice-ansi@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+ integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
+
slice-ansi@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
@@ -6052,6 +6716,11 @@ strict-uri-encode@^1.0.0:
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
+string-argv@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
+ integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==
+
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -6103,6 +6772,15 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
+stringify-object@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
+ integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
+ dependencies:
+ get-own-enumerable-property-symbols "^3.0.0"
+ is-obj "^1.0.1"
+ is-regexp "^1.0.0"
+
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@@ -6143,6 +6821,11 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-hex-prefix@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f"
@@ -6188,6 +6871,13 @@ supports-color@^5.3.0:
dependencies:
has-flag "^3.0.0"
+supports-color@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
+ integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ dependencies:
+ has-flag "^4.0.0"
+
sver-compat@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8"
@@ -6214,6 +6904,11 @@ swarm-js@0.1.39:
tar "^4.0.2"
xhr-request-promise "^0.1.2"
+symbol-observable@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+ integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+
table@^5.2.3:
version "5.4.5"
resolved "https://registry.yarnpkg.com/table/-/table-5.4.5.tgz#c8f4ea2d8fee08c0027fac27b0ec0a4fe01dfa42"
@@ -6333,6 +7028,13 @@ to-regex-range@^2.1.0:
is-number "^3.0.0"
repeat-string "^1.6.1"
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
@@ -7004,6 +7706,11 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+which-pm-runs@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
+ integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
+
which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
@@ -7011,6 +7718,13 @@ which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
dependencies:
isexe "^2.0.0"
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
@@ -7043,6 +7757,14 @@ wrap-ansi@^2.0.0:
string-width "^1.0.1"
strip-ansi "^3.0.1"
+wrap-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba"
+ integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=
+ dependencies:
+ string-width "^2.1.1"
+ strip-ansi "^4.0.0"
+
wrap-ansi@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
@@ -7159,6 +7881,13 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+yaml@^1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.7.2.tgz#f26aabf738590ab61efaca502358e48dc9f348b2"
+ integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==
+ dependencies:
+ "@babel/runtime" "^7.6.3"
+
yargs-parser@^13.1.0:
version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"