Skip to content

Commit

Permalink
PolEthBridge: Update bridge owner and README as well as add missing n…
Browse files Browse the repository at this point in the history
…atspec (#166)

* feat: update bridge owner and README as well as add missing natspec

* chore: update inherit doc

* feat: add support for multiple proof burns

* chore: add missing natspec

* feat: add isTokenMapped function

* Update README.md

* feat: check against 0xeee

* chore: add TXs to README

* chore: add tx to exit

* feat: forward eth

* chore: cleanup readme

* chore: remove column

* Update README.md

* Update README.md

* Update README.md
  • Loading branch information
Fermin 'Piscu' Carranza authored Nov 21, 2023
1 parent 83a3dbe commit ab4e6dc
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 47 deletions.
7 changes: 4 additions & 3 deletions scripts/DeployBridges.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ pragma solidity ^0.8.0;

import {EthereumScript, PolygonScript} from 'src/ScriptUtils.sol';
import {AavePolEthERC20Bridge} from 'src/bridges/AavePolEthERC20Bridge.sol';
import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol';
import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol';
import {GovernanceV3Polygon} from 'aave-address-book/GovernanceV3Polygon.sol';

contract DeployEthereum is EthereumScript {
function run() external broadcast {
bytes32 salt = 'Aave Treasury Bridge';
new AavePolEthERC20Bridge{salt: salt}(AaveGovernanceV2.SHORT_EXECUTOR);
new AavePolEthERC20Bridge{salt: salt}(GovernanceV3Ethereum.EXECUTOR_LVL_1);
}
}

contract DeployPolygon is PolygonScript {
function run() external broadcast {
bytes32 salt = 'Aave Treasury Bridge';
new AavePolEthERC20Bridge{salt: salt}(AaveGovernanceV2.POLYGON_BRIDGE_EXECUTOR);
new AavePolEthERC20Bridge{salt: salt}(GovernanceV3Polygon.EXECUTOR_LVL_1);
}
}
57 changes: 37 additions & 20 deletions src/bridges/AavePolEthERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {ChainIds} from '../ChainIds.sol';
import {IAavePolEthERC20Bridge} from './IAavePolEthERC20Bridge.sol';

interface IRootChainManager {
function childToRootToken(address token) external view returns (address);

function exit(bytes calldata inputData) external;
}

Expand All @@ -34,48 +36,46 @@ contract AavePolEthERC20Bridge is Ownable, Rescuable, IAavePolEthERC20Bridge {

error InvalidChain();

event Exit();
event Exit(bytes proof);
event FailedToSendETH();
event Bridge(address token, uint256 amount);
event WithdrawToCollector(address token, uint256 amount);

address public constant ROOT_CHAIN_MANAGER = 0xA0c68C638235ee32657e8f720a23ceC1bFc77C77;

/// @param _owner The owner of the contract upon deployment
constructor(address _owner) {
_transferOwnership(_owner);
}

/*
* This function withdraws an ERC20 token from Polygon to Mainnet. exit() needs
* to be called on mainnet with the corresponding burnProof in order to complete.
* @notice Polygon only. Function will revert if called from other network.
* @param token Polygon address of ERC20 token to withdraw
* @param amount Amount of tokens to withdraw
*/
/// @inheritdoc IAavePolEthERC20Bridge
function bridge(address token, uint256 amount) external onlyOwner {
if (block.chainid != ChainIds.POLYGON) revert InvalidChain();

IERC20Polygon(token).withdraw(amount);
emit Bridge(token, amount);
}

/*
* This function completes the withdrawal process from Polygon to Mainnet.
* Burn proof is generated via API. Please see README.md
* @notice Mainnet only. Function will revert if called from other network.
* @param burnProof Burn proof generated via API.
*/
/// @inheritdoc IAavePolEthERC20Bridge
function exit(bytes calldata burnProof) external {
if (block.chainid != ChainIds.MAINNET) revert InvalidChain();

IRootChainManager(ROOT_CHAIN_MANAGER).exit(burnProof);
emit Exit();
emit Exit(burnProof);
}

/*
* Withdraws tokens on Mainnet contract to Aave V3 Collector.
* @notice Mainnet only. Function will revert if called from other network.
* @param token Mainnet address of token to withdraw to Collector
*/
/// @inheritdoc IAavePolEthERC20Bridge
function exit(bytes[] calldata burnProofs) external {
if (block.chainid != ChainIds.MAINNET) revert InvalidChain();

uint256 proofsLength = burnProofs.length;
for (uint256 i = 0; i < proofsLength; ++i) {
IRootChainManager(ROOT_CHAIN_MANAGER).exit(burnProofs[i]);
emit Exit(burnProofs[i]);
}
}

/// @inheritdoc IAavePolEthERC20Bridge
function withdrawToCollector(address token) external {
if (block.chainid != ChainIds.MAINNET) revert InvalidChain();

Expand All @@ -85,7 +85,24 @@ contract AavePolEthERC20Bridge is Ownable, Rescuable, IAavePolEthERC20Bridge {
emit WithdrawToCollector(token, balance);
}

/// @inheritdoc IAavePolEthERC20Bridge
function isTokenMapped(address l2token) external view returns (bool) {
if (block.chainid != ChainIds.MAINNET) revert InvalidChain();

return IRootChainManager(ROOT_CHAIN_MANAGER).childToRootToken(l2token) != address(0);
}

/// @inheritdoc Rescuable
function whoCanRescue() public view override returns (address) {
return owner();
}

receive() external payable {
if (block.chainid != ChainIds.MAINNET) revert InvalidChain();

(bool success, ) = address(AaveV3Ethereum.COLLECTOR).call{value: address(this).balance}("");
if (!success) {
emit FailedToSendETH();
}
}
}
40 changes: 40 additions & 0 deletions src/bridges/IAavePolEthERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,49 @@
pragma solidity ^0.8.0;

interface IAavePolEthERC20Bridge {
/*
* Returns the address of the Mainnet contract to exit the burn from
*/
function ROOT_CHAIN_MANAGER() external view returns (address);

/*
* This function withdraws an ERC20 token from Polygon to Mainnet. exit() needs
* to be called on mainnet with the corresponding burnProof in order to complete.
* @notice Polygon only. Function will revert if called from other network.
* @param token Polygon address of ERC20 token to withdraw
* @param amount Amount of tokens to withdraw
*/
function bridge(address token, uint256 amount) external;

/*
* This function completes the withdrawal process from Polygon to Mainnet.
* Burn proof is generated via API. Please see README.md
* @notice Mainnet only. Function will revert if called from other network.
* @param burnProof Burn proof generated via API.
*/
function exit(bytes calldata burnProof) external;

/*
* This function completes the withdrawal process from Polygon to Mainnet.
* Burn proofs are generated via API. Please see README.md
* @notice Mainnet only. Function will revert if called from other network.
* @param burnProofs Array of burn proofs generated via API.
*/
function exit(bytes[] calldata burnProofs) external;

/*
* Withdraws tokens on Mainnet contract to Aave V3 Collector.
* @notice Mainnet only. Function will revert if called from other network.
* @param token Mainnet address of token to withdraw to Collector
*/
function withdrawToCollector(address token) external;

/*
* This function checks whether the L2 token to L1 token mapping exists.
* If the mapping doesn't exist, DO NOT BRIDGE from Polygon.
* @notice Call on Mainnet only.
* @param l2token Address of the token on Polygon.
* @returns Boolean denoting whether mapping exists or not.
*/
function isTokenMapped(address l2token) external view returns (bool);
}
57 changes: 50 additions & 7 deletions src/bridges/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ The same contract exists on both chains with the same address, so this contract

## Functions

`function isTokenMapped(address l2token) external view returns(bool);`

Callable on Mainnet. Returns whether a token mapping exists between Polygon and Mainnet.

**DO NOT BRIDGE** if this function returns false, funds will be lost forever.

Here's a list of Polygon Aave V2 and Aave V3 tokens and whether they are mapped or not, and respective transactions showing a bridge.

| Token | Is Mapped | Burn | Exit |
| --- | --- | --- | --- |
| USDC | yes | [Tx](https://polygonscan.com/tx/0xd670439927d5b067b742e79a2c2f8ac375f38ac0fe77b77bfcdd5a4d7b60f8b7) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| DAI | yes | [Tx](https://polygonscan.com/tx/0x3827bda3f18f117b1b216b2152465708a6e72dfb8bbb2f91c0dcf7a19f817fcc) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| LINK | yes | [Tx](https://polygonscan.com/tx/0x5cbe8749bb496627ab6f53c3ef7f8b451c2f9a3e7933c0231f09d70696615e20) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| WBTC | yes | [Tx](https://polygonscan.com/tx/0xd95ba8488fb67146b7a5946977db3c74433928c0cf1ef08802e46b40cd8a53d6) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| CRV | yes | [Tx](https://polygonscan.com/tx/0x144f5532d1bf88bbdbd914c9d79caaf7e3861aefb0412db69fd46136a4232246) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| BAL | yes | [Tx](https://polygonscan.com/tx/0xafa75edc210566b4d9e3b0986c433f77531eae8a3fb51d4b4e27bf0b241782bb) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| USDT | yes | [Tx](https://polygonscan.com/tx/0xfd091ad2753435126d09c88168234a0c8d536ebc1c942359f02081f8a9d595a2) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) | [Tx](https://polygonscan.com/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| WETH | yes | [Tx](https://polygonscan.com/tx/0x813c4821f5da822a0f60db31070ca025f57ff81953f42f95270a77bc941b266d) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| WMATIC | NO | NO | NO |
| AAVE | yes | [Tx](https://polygonscan.com/tx/0x338f0b763cd4f4080cb0f54a8b76172cd750a21d3f2960ef6e19960a0e9c7df2) | [Tx](https://etherscan.io/tx/0x5b410b2d35acefe23785fca64242521503720c89540cba7580a96c7d48de65ff) |
| GHST | yes | | |
| DPI | yes | | |
| SUSHI | yes | | |
| EURS | yes | | |
| jEUR | NO | NO | NO |
| agEUR | yes | | |
| miMATIC | NO | NO | NO |
| stMATIC | yes | | |
| MaticX | yes | | |
| wstETH | yes | [Tx](https://polygonscan.com/tx/0x30a6f403211fea0edcd2fcd89e505eb0bd6b584a375482e80beec21537a20291) | [Tx](https://etherscan.io/tx/0xa521582be2bb589055827d1556acc4255dad981286ec01942a991b0d31edceaa) |

`function bridge(address token, uint256 amount) external;`

Callable on Polygon to withdraw ERC20 token. It withdraws `amount` of passed `token` to mainnet.
Expand All @@ -14,14 +45,23 @@ Callable on Polygon to withdraw ERC20 token. It withdraws `amount` of passed `to

Callable on Mainnet to finish the withdrawal process. Callable 30-90 minutes after `bridge()` is called and proof is available via API.

`function exit(bytes[] calldata burnProofs) external;`

Callable on Mainnet to finish the withdrawal process. Callable 30-90 minutes after `bridge()` is called and proof is available via API.
This function takes an array of proofs to do multiple burns in one transaction.

`function withdrawToCollector(address token) external;`

Callable on Mainnet. Withdraws balance of held token to the Aave Collector.

`function rescueTokens(address[] calldata tokens) external;`
`function emergencyTokenTransfer(address erc20Token, address to, uint256 amount) external;`

Callable on Polygon. Withdraws tokens from bridge contract back to Aave Collector on Polygon.

`receive() external payable;`

Function to receive Ether and forward it to Aave Collector. If not mainnet, it will revert.

## Burn Proof Generation

After you have called `bridge()` Polygon, it will take 30-90 minutes for a checkpoint to happen. Once the next checkpoint includes the burn transaction, you can withdraw the tokens on Mainnet.
Expand All @@ -30,20 +70,23 @@ The API endpoint used to generate the burn proof is as follows, where `TRANSACTI

https://proof-generator.polygon.technology/api/v1/matic/exit-payload/<TRANSACTION_HASH>?eventSignature=<EVENT_SIGNATURE>

Here's a sample transaction: https://polygonscan.com/tx/0x08365e09c94c5796ae300e706cc516714661a42c50dfff2fa1e9a01b036b21d6
Here's a sample transaction: https://polygonscan.com/tx/0xafa75edc210566b4d9e3b0986c433f77531eae8a3fb51d4b4e27bf0b241782bb

The log topic to use is the `Transfer` function to the zero address (aka. burn).

https://polygonscan.com/tx/0x08365e09c94c5796ae300e706cc516714661a42c50dfff2fa1e9a01b036b21d6#eventlog
https://polygonscan.com/tx/0xafa75edc210566b4d9e3b0986c433f77531eae8a3fb51d4b4e27bf0b241782bb#eventlog

TRANSACTION_HASH: 0x08365e09c94c5796ae300e706cc516714661a42c50dfff2fa1e9a01b036b21d6
TRANSACTION_HASH: 0xafa75edc210566b4d9e3b0986c433f77531eae8a3fb51d4b4e27bf0b241782bb
EVENT_SIGNATURE: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

And the generated proof: https://proof-generator.polygon.technology/api/v1/matic/exit-payload/0x08365e09c94c5796ae300e706cc516714661a42c50dfff2fa1e9a01b036b21d6?eventSignature=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
And the generated proof: https://proof-generator.polygon.technology/api/v1/matic/exit-payload/0xafa75edc210566b4d9e3b0986c433f77531eae8a3fb51d4b4e27bf0b241782bb?eventSignature=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

The result is the bytes data that is later passed to `exit()`.

If doing multiple burns in one transaction, each proof has to be generated individually. To get a specific logIndex to generate the correct proof when doing multiple, you can append to the API URL `&tokenIndex=[INDEX_OF_TARGET_LOG]`. The Index of the target log is the # of the `Transfer()` function, with a 0 based index. A sample transaction with multiple burns can be seen [here.](https://polygonscan.com/tx/0xc73b85175045e272161abe38b25eac76546eea20247d0947926d7ef4e901b567#eventlog)
An array of proofs can be passed to the `exit(bytes[] memory proofs)` function to do all withdrawals in a single transaction instead of the regular `exit(bytes memory proof)` method, on the Mainnet contract.

## Deployed Addresses

Mainnet:
Polygon:
Mainnet: [0x1C2BA5b8ab8e795fF44387ba6d251fa65AD20b36](https://etherscan.io/address/0x1C2BA5b8ab8e795fF44387ba6d251fa65AD20b36)
Polygon: [0x1C2BA5b8ab8e795fF44387ba6d251fa65AD20b36](https://polygonscan.com/address/0x1C2BA5b8ab8e795fF44387ba6d251fa65AD20b36)
Loading

0 comments on commit ab4e6dc

Please sign in to comment.