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
L1Escrow
contract. - Bridge DAI from Polygon zkEVM to Ethereum mainnet via
L2Dai
contract.
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 install
Create .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 test
You 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 -vvvv
Note You can set
ETHERSCAN_API_KEY
to 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_ = 1000000000000000000
Note 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
.