The comprehensive Ethereum smart contract wallet that can do anything.
- Video demo
- Towards the end video recording was cut off for some reason, so here is the last transaction shown in the video. You can see cDAI was minted, and we entered PoolTogether (plDAI is minted weekly, which is why it's not visible in Etherscan)
This tool provides you with a smart contract wallet that supports the following:
- Interact with any contract on Ethereum
- Batch any combination of transactions (as long as it's within the block gas limit) so they are sent within the same transaction. This saves time and gas!
- Integration with Biconomy for meta-transaction support—ETH for gas is not needed.
This section will describe the workflow from a user's perspective along with relevant implementation details.
- Login with your web3 wallet
- This can be any web3 wallet, but for this demo only MetaMask support was added
- On your first login, deploy your contract wallet
- There is a factory contract,
CompreWalletFactory
, that stores a mapping of user addresses to their contract wallets. Upon login, you will be prompted to deploy your contract wallet if you do not have one. - After clicking "Deploy Wallet", you will be prompted for an EIP-712 signature. This signature, along with other required function data, will be relayed via the Biconomy API so Biconomy can call the
createContract
method ofCompreWalletFactory.sol
to deploy your contract wallet.
- There is a factory contract,
- Click "View Account" in the top right and it will show the web3 address and contract wallet address associated with your account.
- After logging in, you will be redirected to the dashboard. The top half shows a few token balances, and the bottom half lets you compose any combination of contract calls into a single, bundled transaction. For now, only a select few contracts and ABIs are populated.
- This section is currently a pretty poor user experience. You have to enter comma-separated arguments into the inputs box. An improvement would be functionality similar to One Click dApp or Drizzle, where the contract ABI is used to generate various individual input fields
- For each call, you can specify whether or not the full bundle of
- After configuring your transaction, click "Send Transactions"
- This will parse the inputs and format the calldata, then the transaction will again be relayed via Biconomy
- This will call the
aggregate
function of the user'sCompreWallet
contract - Note: The meta-transaction relay here currently does not work, and the Biconomy team is investigating this issue
Create a file at the project root called .env with the following contents:
INFURA_ID=yourInfuraId
TOKEN_HOLDER=0x425249Cf0F2f91f488E24cF7B1AA3186748f7516
MNEMONIC="your mnemonic here"
Here, TOKEN_HOLDER is simply an account with a lot of Dai and other tokens used for testing on against a forked Kovan.
Next, run cd app and create a file called .env.dev with the following contents:
INFURA_ID=yourInfuraId
BICONOMY_API_KEY=yourBiconomyApiKey
For production deployment, create a file similar to the above but called and .env.prod with the same contents but different API keys.
Now, from the project root install dependencies as follows:
npm install
cd app
npm install
From the project root run:
cd app
npm run dev
From the project root run:
npm run test
- Compile the contracts with
npm run compile
- Make sure your MNEMONIC is set in
.env
- Run
npx oz accounts
to confirm the right address would be used for deployment - Run
npm run deploy-contracts
and follow the prompts to deployCompreWalletFactory.sol
- From the app, login and deploy a wallet for your MetaMask account
- Now that both contracts are deployed, we must configure our settings in the Biconomy Dashboard to ensure meta-transactions are properly relayed. Please see the Biconomy documentation for details on how to do this. Note that you must setup a meta-transaction API endpoint for both the factory contract and your specific contract wallet.
- An improvement upon this would be to let users interact with their contract wallet through the factory contract, similar to how it is done here. This would enable us to only need one API endpoint instead of setting up a new one for each contract, which of course is not very practical.
Done! There will now be a file called .openzeppelin/<network>.json
which contains deployment info for the contracts. Be sure not to delete that file. This file should be committed to the repository.
For CompreWallet.sol
, the initializeWallet()
function can be replaced with a regular constructor if desired. The initializer function was used because the factory contract was originally configured to deploy minimal proxy wallets. However, it was discovered that for some reason minimal proxies are incompatible with the Biconomy framework, as the nonce is not properly read or updated. As a result, signature verification fails when relaying a meta-transaction, so the factory contract now uses ordinary deployment.