Native DAI implementation is consist of two smart contracts:
- L1Escrow: This contract is deployed on Ethereum mainnet and interact directly with Spark protocol.
- L2Dai: This contract is deployed on Polygon zkEVM.
With Native DAI, user can do the following:
- Bridge DAI from Ethereum mainnet to Polygon zkEVM via
L1Escrowcontract. - Bridge DAI from Polygon zkEVM to Ethereum mainnet via
L2Daicontract.
This repository is using foundry. You can install foundry via foundryup.
Clone the repository:
git clone git@github.com:pyk/zkevm-dai.git
cd zkevm-dai/Install the dependencies:
forge installCreate .env with the following contents:
ETH_RPC_URL=""
ZKEVM_RPC_URL="https://zkevm-rpc.com"
ETHERSCAN_API_KEY=""
Use the following command to run the test:
forge testYou can also run individual test using the following command:
forge test --fork-url $ETH_RPC_URL --match-test testSendExcessYield -vvvv
forge test --fork-url "https://zkevm-rpc.com" --match-path test/L2Dai.t.sol --match-test testBridgeWithMockedBridge -vvvvNote You can set
ETHERSCAN_API_KEYto helps you debug the call trace.
Use the following command to deploy on Goerli:
forge script ...| Smart contract | Network | Address |
|---|---|---|
| DAI | Mainnet | 0x6B175474E89094C44Da98b954EedeAC495271d0F |
| sDAI | Mainnet | 0x83f20f44975d03b1b09e64809b757c47f942beea |
| Polygon ZkEVM Bridge | Mainnet | 0x2a3dd3eb832af982ec71669e178424b10dca2ede |
| zkEVM Mainnet | 0x2a3dd3eb832af982ec71669e178424b10dca2ede | |
| L1Escrow | Mainnet | 0x4a27ac91c5cd3768f140ecabde3fc2b2d92edb98 |
| L2Dai | zkEVM Mainnet | 0x744c5860ba161b5316f7e80d9ec415e2727e5bd5 |
| Smart contract | Network | Address |
|---|---|---|
| DAI | Goerli | 0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844 |
| sDAI | Goerli | 0xD8134205b0328F5676aaeFb3B2a0DC15f4029d8C |
| Polygon ZkEVM Bridge | Goerli | 0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7 |
| zkEVM Testnet | 0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7 | |
| L1Escrow | Goerli | 0x2929b2635E51f2dA1373A76F166A237322694fA6 |
| L2Dai | zkEVM Testnet | 0x755CB8A808c99706afAA34547204f17cD33C6316 |
When we deposit x amount of DAI to sDAI, we will get y amount of sDAI based
on the current exchange rate r. Due to how y is rounded down by sDAI, there
is possibility that when we redeem y amount of sDAI we will get x' = x - 1
amount of DAI.
For, example:
uint256 x = 1000000000000000001;
uint256 y = sdai.deposit(x);
uint255 x_ = sdai.redeem(y); // x_ = 1000000000000000000Note See sDAI.t.sol for more details.
Ofcourse, r will be increased over time and this 1 wei will be covered.
To make sure that bridged DAI is always 1:1, it is advised to donate small
amount of DAI on L1Escrow on the first time it get deployed (e.g. 0.01 DAI).
sendExcessYield will send excess yield if the total yield is more than
0.05 DAI and will leave 0.01 DAI from the yield in L1Escrow.
Currently there is no way to check the maximum deposit amount of sDAI.
sdai.maxDeposit(address) is hardcoded to type(uint256).max.
sdai.deposit(amount, recipient) may reverted and it is possible that total
amount of locked DAI in the L1Escrow is greater than the specified
totalProtocolDAI.