https://github.com/gnosischain/tokenbridge-contracts/blob/xdaibridge/USDSMigration.md
# USDS migration
> > After the migration, xDAI Foreign Bridge take USDS as collateral instead of DAI.
> > Background: https://forum.gnosis.io/t/gip-118-should-sdai-be-replaced-by-susds-in-the-bridge/9354
> To address a potential front-running issue\* from the previous design, a new implementation has been introduced. The key changes includes:
1. New USDS deposit contract on Gnosis Chain
2. `token` parameter is introduced in the `UserRequestForSignature` event.
3. The `executeSignaturesUSDS` function is removed from the BridgeRouter and XdaiForeignBridge contract.
Target audiences:
1. 3rd party applications: please refer to [Call To Action](#call-to-action-update-your-code).
2. User: No action required.
3. Bridge validator: update the validator image to [v3.10.0](https://hub.docker.com/layers/gnosischain/tokenbridge-oracle/v3.10.0/images/sha256-f135fbec56c3755d40ebf68257bfab4258c80242566ed157a49e1e5cfc692c91).
\*refer to Omega audit XDFB1.
## Table of Contents
- [General Overview](#general-overview)
- [Dev](#dev)
- [Contracts overview](#contracts)
- [Interact with contracts](#interact-with-the-contracts)
- [Call to Action: Update your code](#call-to-action-update-your-code--indexer)
- [Test with post migration environment](#how-to-test-with-post-migration-environment)
- [Note for Bridge governors](#note-for-bridge-governors)
## General overview
1. The **xDAI bridge contract** is undergoing a critical upgrade: **DAI will be replaced with USDS as the default accepted token on Ethereum, while xDAI will continue to be minted on Gnosis Chain**.
### Key Changes for Third-Party Applications:
Etherum -> Gnosis Chain
- Third-party applications **must integrate** with the new **Bridge Router contract on Ethereum**.
- The **Bridge Router** serves as the entry point for token relay transactions, routing them to the appropriate bridge contract on Gnosis Chain (**xDAI Bridge** or **Omnibridge**).
- **DAI & USDS transactions must go through the Bridge Router.** Transactions sent directly to the xDAI Bridge on Ethereum will **fail** if they attempt to relay DAI after the upgrade, but they will succeed in relaying USDS provided the sender has approved USDS for the bridge (\*Check [Edge Case](#edge-case))
- **For tokens other than DAI & USDS**, using the Bridge Router is **optional**—third-party applications can continue interacting with Omnibridge directly.
Gnosis Chain -> Ethereum
- To get USDS on Ethereum, one **MUST** switch to USDSDepositContract on Gnosis Chain when initiating the transaction.
- To get DAI on Ethereum, one **MUST** remain calling the Home xDAI Bridge as it is.
- Third-party applications **MUST** update their indexer to index the new event format emitted from Gnosis Chain.
- Claiming token on Ethereum remains the same function `executeSignatures(bytes memory message, bytes memory signatures)`. One can call it either on BridgeRouter or the XDaiForeignBridge contract on Ethereum.
### Transition Period:
- Before the USDS upgrade on the xDAI Bridge, third-party applications have time to **adapt to the Bridge Router interface, new USDS Deposit contract** and **update their indexer for new event signature on Gnosis Chain**.
## Dev
### Prerequisite
- [Node v10.18](https://nodejs.org/en/blog/release/v10.18.0) (as specified in .[nvm](https://github.com/nvm-sh/nvm)rc)
- [Foundry v0.2.0 or later](https://book.getfoundry.sh/getting-started/installation)
- Ethereum, Gnosis Chain RPC endpoint (for testing and deployment)
### Framework
[Foundry](https://book.getfoundry.sh/)
> > This repository was initially developed using [Truffle](https://archive.trufflesuite.com/docs/truffle/). However, due to the [sunsetting of Truffle](https://consensys.io/blog/consensys-announces-the-sunset-of-truffle-and-ganache-and-new-hardhat?utm_source=chatgpt.com), we transition our development workflow to Foundry.
### Setup
```sh
nvm use
npm i
forge install
forge build
```
### Test
```sh
source .env
chmod +x ./test/foundry/fork-test.sh && ./test/foundry/fork-test.sh
chmod +x ./test/foundry/e2e/e2e-test.sh && ./test/foundry/e2e/e2e-test.sh
```
For more details about testing, please check [this repository](https://github.com/gnosischain/xdaiBridge-usds-migration-test)
### Deploy
```sh
forge script script/Deploy.s.sol:Deploy --rpc-url $RPC_MAINNET --private-key $PRIVATE_KEY --verify --etherscan-api-key --broadcast
```
### Get deployed bytecode of the contract
```sh
npm run get-deployed-bytecode
```
The result will be written into `scripts/usds_migration/deployBytecode_usds_migration.json`.
### Get keccak256 hash of the contract
```sh
npm run get-contract-keccak256
```
The result will be written into `scripts/usds_migration/keccak256hash.json`.
| Contract | Contract Hash (keccak256) |
| ----------------------------------------- | -------------------------------------------------------------------- |
| xDaiForeignBridge | `0xbadd059fea2d7ab61bcd36db3418c6c73dca7a4fc02917ce5db2f78d962821f8` |
| BridgeRouter | `0xab729fba35c9d369445f85c3556db5644eb7356228ed3fda441bff4e7e1eacb8` |
| XDaiBridgePeripheral | `0x3d5e7ff9da196691d2dc57c93036c7414b68d63921dce530c5747017ea39afb5` |
| XDaiBridgePeripheralForDaiPreUsdsUpgrade | `0x721cfb942f77f4b04de65a4dbb7b1686e2c363689c83de3bee58da3ab9ae0bb3` |
| XDaiBridgePeripheralForUsdsPreUsdsUpgrade | `0x74284da7c9b250a0348d431981364bf4e82987ca93524f2c392ea2455fd1e8a9` |
| HomeBridgeErcToNative | `0xb5a198416e6936a3443e718e53c675bf07621769bebb57b8c61389e740678f30` |
| USDSDepositContract | `0x347eaf2c91db18b5e5096a009b4a398daae84149a87bdf0cefa4545ea39b0f8c` |
For details about the keccak256 of the contract, please check [Sourcify's doc](https://docs.sourcify.dev/docs/full-vs-partial-match/#full-perfect-matches) and [Solidity's doc](https://docs.soliditylang.org/en/latest/metadata.html)
### Contract versions
| Contract | Version | Optimizer Runs |
| --------------------------------------------- | ----------------------- | -------------- |
| BridgeRouter.sol | v0.8.25+commit.b61c2a91 | 10 |
| XDaiBridgePeripheral.sol | v0.8.25+commit.b61c2a91 | 10 |
| XDaiBridgePeripheralForDaiPreUsdsUpgrade.sol | v0.8.25+commit.b61c2a91 | 10 |
| XDaiBridgePeripheralForUsdsPreUsdsUpgrade.sol | v0.8.25+commit.b61c2a91 | 10 |
| XDaiForeignBridge.sol | v0.4.24+commit.e67f0147 | 10 |
| HomeBridgeErcToNative.sol | v0.4.24+commit.e67f0147 | 10 |
| USDSDepositContract.sol | v0.8.25+commit.b61c2a91 | 10 |
# Contracts Overview
## New contracts
1. `BridgeRouter.sol`: An entry point for token transferring, abstracting relayTokens() for Omnibridge and xDAI bridge. Upgradeable with `TransparentUpgradeableProxy`.
2. `XDaiBridgePeripheral.sol`: Peripheral contract to convert between DAI and USDS after bridge migration.
3. `USDSDepositContract.sol`: Deposit contract to notify the bridge where the intended recieved token is USDS on Ethereum.
Transitional contracts during migration
1. `XDaiBridgePeripheralForDaiPreUsdsUpgrade.sol`: Allow `relayTokens` with DAI.
2. `XDaiBridgePeripheralForUsdsPreUsdsUpgrade.sol`: Allow `relayTokens` with USDS.
## Modified contracts
1. `SavingsDaiConnector.sol`: `daiToken()` address is changed to USDS address, `sDaiToken()` address is changed to sUSDS address.
2. `XDaiForeignBridge.sol`: new function introduced
1. `swapSDAIToUSDS`: one time function for bridge migration
2. Add token parameter in message parsing.
3. `HomeBridgeErcToNative.sol`: token parameter is included in event `UserRequestForSignature`, in `Message` library for parsing and encoding.
4. `HomeOverdrawManagement.sol`: add token parameter in `fixAssetsAboveLimits` function.
5. `ErcToNativeBridgeHelper.sol`: add token parameter to `getMessageHash` function.
## Audits
> > Original audit reports from the previous design.
1. [Omega](https://github.com/OmegaAudits/audits/blob/main/202510-Gnosis-Bridge-USDS-Upgrade.pdf)
2. Gnosis Ltd [1](./docs/audits/xdai-bridge-usds-upgrade-gnosis.pdf),[2](https://github.com/cducrest/audit-reports/blob/main/bridge-USDS-upgrade3.pdf)
### Contract addresses
| Contract | Chain | Address |
| ------------------------------------------ | ------------ | -------------------------------------------- |
| BridgeRouter Proxy | Ethereum | `0x9a873656c19Efecbfb4f9FAb5B7acdeAb466a0B0` |
| BridgeRouter Implementation | Ethereum | `0x74899961224538E423eFfD1A0Ff3346adf3F4C56` |
| XDaiBridgePeripheral | Ethereum | `0x3b6669727927b934753B018EB421a84Ed4eb0a43` |
| XDaiBridgePeripheralForDaiPreUsdsUpgrade | Ethereum | `0xF676cc15Eb6d15b794aeC65bC20052aFB53D9052` |
| XDaiBridgePeripheralForUsdsPreUsdsUpgrade | Ethereum | `0x7df0e6a8BA609A6cC3Ab2fA33D953a3B5584f10C` |
| XDaiForeignBridge(Implementation Contract) | Ethereum | `0x257bDD093Cab1Bd39eBF837dCB60f33d031d7d49` |
| HomeBridgeErcToNative Implementation | Gnosis Chain | `0xe6998b0C03D3cb9ee8C04f266e573c7Fa8782846` |
| USDSDepositContract.sol | Gnosis Chain | `0x5C183C8A49aBA6e31049997a56D75600E27FF8c9` |
| Erc20ToNativeBridgeHelper.sol | Gnosis Chain | `0xe30269bc61E677cD60aD163a221e464B7022fbf5` |
# Interacting with the contracts
## Before the xDAI Bridge migration
**Bridge Router setup**
Caller: BridgeRouterOwner `0x42F38ec5A75acCEc50054671233dfAC9C0E7A3F6` (same as the bridge owner)
```
router.setRoute(DAI,address(XDaiBridgePeripheralForDaiPreUsdsUpgrade));
router.setRoute(USDS,address(XDaiBridgePeripheralForUsdsPreUsdsUpgrade));
```
### Relay tokens from Ethereum
```mermaid
graph TD
User([User]) -->|"relayTokens: DAI"| BridgeRouter
User -->|"relayTokens: USDS"| BridgeRouter
User -->|"relayTokens: Other ERC20"| BridgeRouter
User -->|"relayTokens: ETH"| BridgeRouter
subgraph "BridgeRouter Contract"
BridgeRouter[BridgeRouter]
end
subgraph "Pre-Upgrade Peripherals"
DaiPeripheral[XDaiBridgePeripheralForDaiPreUsdsUpgrade]
UsdsPeripheral[XDaiBridgePeripheralForUsdsPreUsdsUpgrade]
end
BridgeRouter -->|DAI| DaiPeripheral
BridgeRouter -->|USDS| UsdsPeripheral
BridgeRouter -->|Other ERC20| OmniBridge[Foreign OmniBridge]
BridgeRouter -->|ETH| WETHRouter[WETH OmniBridge Router]
DaiPeripheral --> XDaiForeignBridge
UsdsPeripheral -->|"Convert USDS to DAI"| XDaiForeignBridge
subgraph "Omnibridge contract"
OmniBridge --> OmniBridgeHome[Mint bridged token on Gnosis Chain]
WETHRouter --> OmniBridgeHome
end
subgraph "XDaiForeignBridge Contract (Pre-Upgrade)"
XDaiForeignBridge[XDaiForeignBridge] -->|"DAI as collateral"| GnosisChain[Mint xDAI on Gnosis Chain]
end
```
### To claim token on Ethereum
```mermaid
graph TD
subgraph "BridgeRouter Contract"
BridgeRouter[BridgeRouter]
end
subgraph "XDaiForeignBridge Contact"
XDaiForeignBridge[XDaiForeignBridge] -->|DAI as collateral| GnosisChain[unlock DAI to recipient]
end
subgraph "ForeignAMB Contract"
ForeignAMB[ForeignAMB] --> Action[Unlock token to recipient]
end
%% For claim operations (pre-upgrade)
User -->|executeSignatures| BridgeRouter
User -.->|revert executeSignaturesUSDS| BridgeRouter
User -->|safeExecuteSignaturesWithAutoGasLimit| BridgeRouter
BridgeRouter -->|executeSignatures| XDaiForeignBridge
BridgeRouter -->|safeExecuteSignaturesWithAutoGasLimit| ForeignAMB[Foreign AMB]
```
1. `BridgeRouter.relayTokens(address token, address recipient, uint256 amount)`
-> When token is DAI / USDS from Ethereum, receive xDAI on GC.
-> When token is other tokens from Ethereum, receive the bridged version token on GC.
2. `BridgeRouter.executeSignatures(bytes memory message, bytes memory signatures)`
-> claim DAI on Ethereum
3. `BridgeRouter.executeSignaturesUSDS(bytes memory message, bytes memory signatures)`
-> revert `ClaimUsdsNotSupported()`
4. `BridgeRouter.safeExecuteSignaturesWithAutoGasLimit(bytes memory message, bytes memory signatures)`
-> claim token from Omnibridge
5. `xDAIForeignBridge.relayTokens(address recipient, uint256 amount)`
-> relay DAI from Ethereum, receive xDAI on GC
6. `xDAIForeignBridge.executeSignatures(bytes memory message, bytes memory signatures)`
-> claim DAI on Ethereum
### Function Callflow
```mermaid
sequenceDiagram
participant User
participant BridgeRouter
participant DaiPeripheral as XDaiBridgePeripheralForDaiPreUsdsUpgrade
participant UsdsPeripheral as XDaiBridgePeripheralForUsdsPreUsdsUpgrade
participant DaiUsds as DaiUsds
participant XDaiForeignBridge as XDaiForeignBridge on Ethereum
participant GnosisChain as XDaiHomeBridge on Gnosis Chain
participant Receiver
box Ethereum
participant User
participant BridgeRouter
participant DaiPeripheral
participant UsdsPeripheral
participant DaiUsds
participant XDaiForeignBridge
end
box Gnosis Chain
participant GnosisChain
participant Receiver
end
%% Relay DAI Flow
par
Note over User,Receiver: Relay DAI
User->>BridgeRouter: DAI.approve(BridgeRouter, amount)
User->>BridgeRouter: relayTokens(DAI, receiver, amount)
BridgeRouter->>DaiPeripheral: Transfer DAI
DaiPeripheral->>XDaiForeignBridge: relayTokens(receiver, amount)
XDaiForeignBridge->>XDaiForeignBridge: Lock DAI as collateral
XDaiForeignBridge-->>GnosisChain: Bridging process
GnosisChain->>Receiver: Receive xDAI
end
%% Claim DAI Flow
par
Note over User,Receiver: Claim DAI
User->>BridgeRouter: executeSignatures(message, signatures)
BridgeRouter->>XDaiForeignBridge: executeSignatures(message, signatures)
XDaiForeignBridge->>User: Transfer DAI to Receiver
end
%% Relay USDS Flow
par
Note over User,Receiver: Relay USDS
User->>BridgeRouter: USDS.approve(BridgeRouter, amount)
User->>BridgeRouter: relayTokens(USDS, receiver, amount)
BridgeRouter->>UsdsPeripheral: Transfer USDS
UsdsPeripheral->>DaiUsds: swapUsdsToDai()
DaiUsds->>XDaiForeignBridge: Approve DAI
XDaiForeignBridge->>XDaiForeignBridge: Lock DAI as collateral
XDaiForeignBridge-->>GnosisChain: Bridging process
GnosisChain->>Receiver: Receive xDAI
end
%% Claim USDS Flow (Fails)
par
Note over User,Receiver: Claim USDS
User->>BridgeRouter: executeSignaturesUSDS(message, signatures)
BridgeRouter->>BridgeRouter: Revert ClaimUsdsNotSupported()
end
```
**Relay DAI**
1. DAI.approve(BridgeRouter, amount)
-> [BridgeRouter.relayTokens(DAI, receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L37)
-> [XDaiBridgePeripheralForDaiPreUsdsUpgrade.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/XDaiBridgePeripheralForDaiPreUsdsUpgrade.sol#L34)
-> [xDAIForeignBridge.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol#L66)
**Claim DAI**
1. [BridgeRouter.executeSignatures(message, signatures)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L77)
-> [xDAIForeignBridge.executeSignatures(message, signatures)](./contracts/upgradeable_contracts/BasicForeignBridge.sol#L22)
-> (internal) [onExecuteMessage](./contracts/upgradeable_contracts/erc20_to_native/XDaiForeignBridge.sol#L123) |Here is where the DAI is transferred
**Relay USDS**
1. USDS.approve(BridgeRouter, amount)
-> [BridgeRouter.relayTokens(USDS, receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L37)
-> [XDaiBridgePeripheralForUsdsPreUsdsUpgrade.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/XDaiBridgePeripheralForUsdsPreUsdsUpgrade.sol#L36) |Here is where USDS is swap to DAI
-> [xDAIForeignBridge.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol#L66)
**Claim USDS**
1. [BridgeRouter.executeSignaturesUSDS(message,signatures)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L102)
-> revert `ClaimUsdsNotSupported()` `0x662554fc43b5d87090a5f9e8b365ca35213d23ae7082671886b760dc510ee8da`
XDaiForeignBridge's current implementation: https://etherscan.io/address/0x166124b75c798cedf1b43655e9b5284ebd5203db
Code: https://github.com/gnosischain/tokenbridge-contracts/tree/xdaibridge/contracts/upgradeable_contracts/erc20_to_native
## Upgrade procedure
```mermaid
graph TD
subgraph "Upgrade txs"
UpgradeBundledTx[Execute BundledSafeTx by bridge governors]
UpgradeBundledTx -->|Disable interest for DAI, Enable interest for USDS| XDaiForeignBridge
UpgradeBundledTx -->|Set USDS as collateral token| XDaiForeignBridge
UpgradeBundledTx -->|Set DAI route| BridgeRouter --> |DAI| XDaiBridgePeripheral
UpgradeBundledTx -->|Set USDS route| BridgeRouter --> |USDS| XDaiForeignBridge
end
subgraph "Pre upgrade configuration"
PreConfig[Pre-Upgrade Configuration]
PreConfig -->|Set DAI route to| BridgeRouterPreUpgrade[BridgeRouter] -->|DAI| DaiPeripheralPre[XDaiBridgePeripheralForDaiPreUsdsUpgrade]
PreConfig -->|Set USDS route to| BridgeRouterPreUpgrade[BridgeRouter] -->|USDS |UsdsPeripheralPre[XDaiBridgePeripheralForUsdsPreUsdsUpgrade]
PreConfig -->|DAI as collateral| XDaiForeignBridgeDaiCollateral[XDaiForeignBridge]
end
PreConfig -->|Upgrade| UpgradeBundledTx
```
Test for the upgrade procedures is written in [BridgeRouter.t.sol#upgradeBridgeAndSetupRoute](./test/foundry/BridgeRouter.t.sol#L533)
### Function calls during the proxy upgrade
> > The function calls during the upgrade on BridgeProxy and Router is a bundled Safe transaction, that will be signed and executed by [bridge governors](https://docs.gnosischain.com/bridges/management/#bridge-governance).
**Call on bridge contracts**
ethereumXdaiBridgeProxy=`0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016`
gnosisChainXdaiBridgeProxy = `0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6`
ethereumBridgeOwner= `0x42F38ec5A75acCEc50054671233dfAC9C0E7A3F6`
gnosisChainBridgeOwner= `0x7a48Dac683DA91e4faa5aB13D91AB5fd170875bd`
- Ethereum
```solidity
uint256 initialVersion = 9
address newImpl = 0x257bDD093Cab1Bd39eBF837dCB60f33d031d7d49
ethereumXdaiBridgeProxy.upgradeTo(initialVersion + 1, address(newImpl));
// disable interested for DAI and swap sDAI -> sUSDS
ethereumXdaiBridgeProxy.swapSDAIToUSDS();
ethereumXdaiBridgeProxy.initializeInterest(
address(USDS): 0xdC035D45d973E3EC169d2276DDab16f1e407384F,
minCashThreshold: 1000000000000000000000000,
minInterestPaid: 1000000000000000000000,
gnosisInterestReceiver: 0x670daeaF0F1a5e336090504C68179670B5059088
);
ethereumXdaiBridgeProxy.invest(address(USDS));
```
- Gnosis Chain
```solidity
uint256 initialVersion = 6
address newImpl = 0xe6998b0C03D3cb9ee8C04f266e573c7Fa8782846
address usdsDepositContract = 0x5C183C8A49aBA6e31049997a56D75600E27FF8c9
gnosisChainXdaiBridgeProxy.upgradeTo(initialVersion + 1, address(newImpl))
gnosisChainXdaiBridgeProxy.setUSDSDepositContract(usdsDepositContract);
```
**Upgrade BrigeRouter implementation and Update routes**
Caller: BridgeRouterOwner `0x42F38ec5A75acCEc50054671233dfAC9C0E7A3F6` (same as the bridge owner)
ROUTER_PROXY_ADDRESS=`0x9a873656c19Efecbfb4f9FAb5B7acdeAb466a0B0`
ProxyAdminContract=`0xD7e65A32bEd4ce8cc57Ec188F2bBb8016dc4b1cd`
XDAI_BRIDGE_PERIPHERAL=`0x3b6669727927b934753B018EB421a84Ed4eb0a43`
XDAI_FOREIGNBRIDGE_PROXY=`0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016`
```solidity
proxyAdminContract.upgradeAndCall(ROUTER_PROXY_ADDRESS,newImplementation, "");
router.setRoute(address(DAI), address(xDAIBridgeperipheral));
router.setRoute(address(USDS), xDAIForeignBridgeProxy);
```
## After the upgrade
### Relay token from Ethereum
```mermaid
graph TD
User([User]) -->|"relayTokens: DAI"| BridgeRouter
User -->|"relayTokens: USDS"| BridgeRouter
User -->|"relayTokens: Other ERC20"| BridgeRouter
User -->|"relayTokens: ETH"| BridgeRouter
subgraph "BridgeRouter Contract"
BridgeRouter[BridgeRouter]
end
subgraph "Post-Upgrade Peripheral"
UsdsPeripheral[XDaiBridgePeripheral]
end
BridgeRouter -->|DAI| UsdsPeripheral
BridgeRouter -->|USDS| XDaiForeignBridge
BridgeRouter -->|Other ERC20| OmniBridge[Foreign OmniBridge]
BridgeRouter -->|ETH| WETHRouter[WETH OmniBridge Router]
UsdsPeripheral -->|"Convert DAI to USDS"| XDaiForeignBridge
subgraph "Omnibridge contract"
OmniBridge --> OmniBridgeHome[Mint bridged token on Gnosis Chain]
WETHRouter --> OmniBridgeHome
end
subgraph "XDaiForeignBridge Contract (Post-Upgrade)"
XDaiForeignBridge[XDaiForeignBridge] -->|"USDS as collateral"| GnosisChain[Mint xDAI on Gnosis Chain]
end
```
### Relay xDAI from Gnosis Chain
```mermaid
graph TD
User([User]) --> |send xDAI and want DAI| xDAIHomeBridge
User([User]) --> |send xDAI and want USDS| USDSDepositContract
USDSDepositContract --> xDAIHomeBridge
xDAIHomeBridge --> |emit new UserRequestForSignature|Event[recipient, value, nonce, token]
```
### To claim token on Ethereum
```mermaid
graph TD
subgraph "BridgeRouter Contract"
BridgeRouter[BridgeRouter]
end
subgraph "XDaiForeignBridge Contact"
XDaiForeignBridge[XDaiForeignBridge] -->|exeucteSignatures| DAI_USDS[unlock USDS / swap USDS to DAI to recipient]
end
subgraph "ForeignAMB Contract"
ForeignAMB[ForeignAMB] --> Action[Unlock token to recipient]
end
%% For claim operations
User -->|executeSignatures| BridgeRouter
User -->|safeExecuteSignaturesWithAutoGasLimit| BridgeRouter
BridgeRouter -->|executeSignatures| XDaiForeignBridge
BridgeRouter -->|safeExecuteSignaturesWithAutoGasLimit| ForeignAMB[Foreign AMB]
```
1. `BridgeRouter.relayTokens(address token, address recipient, uint256 amount)`
-> When token is DAI / USDS from Ethereum, receive xDAI on GC.
-> When token is other tokens from Ethereum, receive the bridged version token on GC through Omnibridge.
2. `BridgeRouter.executeSignatures(bytes memory message, bytes memory signatures)`
-> Call xDAIForeignBridge.executeSignatures
3. `BridgeRouter.safeExecuteSignaturesWithAutoGasLimit(bytes memory message, bytes memory signatures)`
-> claim token from Omnibridge
4. `xDAIForeignBridge.relayTokens(address recipient, uint256 amount)`
-> relay USDS from Ethereum, receive xDAI on GC
5. `xDAIForeignBridge.executeSignatures(bytes memory message, bytes memory signatures)`
-> claim USDS / swap USDS->DAI on Ethereum
### Function Callflow
```mermaid
sequenceDiagram
box Ethereum
participant User
participant BridgeRouter
participant XDaiBridgePeripheral
participant DaiUsds as DaiUsds
participant XDaiForeignBridge
end
box Gnosis Chain
participant GnosisChain as xDaiHomeBridge on Gnosis Chain
participant USDSDepositContract
participant Receiver
end
%% Relay DAI Flow
par
Note over User,Receiver: Relay DAI
User->>BridgeRouter: DAI.approve(BridgeRouter, amount)
User->>BridgeRouter: relayTokens(DAI, receiver, amount)
BridgeRouter->>XDaiBridgePeripheral: Transfer DAI
XDaiBridgePeripheral->>DaiUsds: swapDaiToUsds()
DaiUsds->>XDaiForeignBridge: Approve USDS
XDaiForeignBridge->>XDaiForeignBridge: Lock USDS as collateral
XDaiForeignBridge-->>GnosisChain: Bridging process
GnosisChain->>Receiver: receive xDAI
end
%% Claim DAI Flow
par
Note over User,Receiver: Claim DAI
User->>BridgeRouter: executeSignatures(message, signatures)
BridgeRouter->>XDaiForeignBridge: executeSignatures(message, signatures)
XDaiForeignBridge->>DaiUsds: swapUsdsToDai()
XDaiForeignBridge->>User: Transfer DAI to receiver
end
%% Relay USDS Flow
par
Note over User,Receiver: Relay USDS
User->>BridgeRouter: USDS.approve(BridgeRouter, amount)
User->>BridgeRouter: relayTokens(USDS, receiver, amount)
BridgeRouter->>XDaiForeignBridge: Direct transfer of USDS
XDaiForeignBridge->>XDaiForeignBridge: Lock USDS as collateral
XDaiForeignBridge-->>GnosisChain: Bridging process
GnosisChain->>Receiver: receive xDAI
end
%% Claim USDS Flow
par
Note over User,Receiver: Claim USDS
User->>BridgeRouter: executeSignatures(message, signatures)
BridgeRouter->>XDaiForeignBridge: executeSignatures(message, signatures)
XDaiForeignBridge->>User: Transfer USDS to receiver
end
%% Relay xDAI Flow
par
Note over User,Receiver: Relay xDAI and get DAI
User->>GnosisChain: xDaiHomeBridge.transfer{value:msg.value} or xDaiHomeBridge.relayTokens{value:msg.value}(recipient)
User ->> BridgeRouter: executeSignatures(message,recipient)
BridgeRouter ->> XDaiForeignBridge: executeSignatures(message,recipient)
XDaiForeignBridge ->> DaiUsds: swapUsdsToDai()
XDaiForeignBridge ->> Receiver: transfer DAI
end
%% Relay xDAI Flow
par
Note over User,Receiver: Relay xDAI and get USDS
User->>USDSDepositContract: USDSDepositContract.transfer{value:msg.value} or USDSDepositContract.relayTokens{value:msg.value}(recipient)
User ->> BridgeRouter: executeSignatures(message,recipient)
BridgeRouter ->> XDaiForeignBridge: executeSignatures(message,recipient)
XDaiForeignBridge ->> Receiver: unlock USDS
end
```
**Relay DAI**
1. DAI.approve(BridgeRouter, amount)
-> [BridgeRouter.relayTokens(DAI, receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L37)
-> [XDaiBridgePeripheral.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/XDaiBridgePeripheral.sol#L35)
-> [xDAIForeignBridge.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol#L66)
**Claim DAI**
1. [BridgeRouter.executeSignatures(message, signatures)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L77)
-> [xDAIForeignBridge.executeSignatures(message, signatures)](./contracts/upgradeable_contracts/BasicForeignBridge.sol#L22)
-> (internal)[onExecuteMessage](./contracts/upgradeable_contracts/erc20_to_native/XDaiForeignBridge.sol#L123) |Here is where USDS is swap to DAI
**Relay USDS**
1. USDS.approve(bridgeRouter, amount)
-> [BridgeRouter.relayTokens(USDS, receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L37)
-> [xDAIForeignBridge.relayTokens(receiver, amount)](./contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol#L66)
**Claim USDS**
1. [BridgeRouter.executeSignatures(message, signatures)](./contracts/upgradeable_contracts/erc20_to_native/BridgeRouter.sol#L77)
-> [xDAIForeignBridge.executeSignatures(message,signatures)](./contracts/upgradeable_contracts/BasicForeignBridge.sol#L22) -> (internal)[onExecuteMessage](./contracts/upgradeable_contracts/erc20_to_native/XDaiForeignBridge.sol#L123) |Here is where USDS is swap to DAI
**Relay xDAI and get DAI**
1. [xDAIHomeBridge.transfer{value: msg.value}("")](./contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol#L28) or [xDAIHomeBridge.relayTokens{value: msg.value}(address recipient)](./contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol#L67)
**Relay xDAI and get USDS**
1. [USDSDepositContract.transfer{value: msg.value}("")](./contracts/USDSDepositContract.sol#L13) or [USDSDepositContract.relayTokens{value: msg.value}(address recipient)](./contracts/USDSDepositContract.sol#L17)
### Edge case
1. After the upgrade, the xDAI Foreign Bridge assumes the sender wants to relay USDS.
- If a user intends to relay DAI, but still has an existing USDS allowance for the bridge, the bridge will use the USDS allowance and relay USDS instead of DAI.
- To avoid unintended relays:
- Always interact with the Bridge Router when relaying DAI.
- Approve only the exact amount of USDS you intend to relay, rather than leaving a large allowance.
### Note on BridgeRouter.sol
BridgeRouter.sol uses TransparentUpgradeableProxy from Openzeppelin as proxy.
1. TransparentUpgradeableProxy.sol is deployed from [Openzeppelin/openzeppelin-contract@acd4ff7](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/acd4ff74de833399287ed6b31b4debf6b2b35527) v5.2.0. Audited in [2024-10-v5.1.pdf](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/audits/2024-10-v5.1.pdf)
2. ProxyAdmibn.sol is deployed from [Openzeppelin/openzeppelin-contract@acd4ff7](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/acd4ff74de833399287ed6b31b4debf6b2b35527) v5.2.0. Audited in [2023-10-v5.0.pdf](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/audits/2023-10-v5.0.pdf)
To verify deployed bytecode, checkout [this repository](https://github.com/zengzengzenghuy/USDS-migration-xDAIBridge-contract-verification)
# Call to Action: Update your code & indexer
To modify your existing smart contract code to work with the xDAI bridge after USDS migration, complete the following changes:
## Contract Interface
Ethereum -> Gnosis Chain
### Relay tokens
```solidity
>>> Previous
xDAIForeignBridge.relayTokens(address recipient, uint256 value)
<<< Latest
BridgeRouter.relayTokens(address token, address recipient, uint256 value)
```
### Claim tokens
```solidity
>>> Previous
xDAIForeignBridge.executeSignatures(bytes message, bytes signatures)
<<< Latest
BridgeRouter.executeSignatures(bytes message, bytes signatures)
```
Gnosis Chain -> Ethereum
### Relay tokens
```solidity
>>> Previous
HomeBridgeErcToNative.relayTokens{value: msg.value}(address recipient)
HomeBridgeErcToNative.call{value: msg.value}("")
<<< Latest
// To get DAI on Ethereum
HomeBridgeErcToNative.relayTokens{value: msg.value}(address recipient)
// To get DAI on Ethereum
HomeBridgeErcToNative.call{value: msg.value}("")
// To get USDS on Ethereum
USDSDepositContract.relayTokens{value: msg.value}(address recipient)
// To get USDS on Ethereum
USDSDepositContract.call{value: msg.value}("")
```
## Event signature
```solidity
>>> Previous
// 0xbcb4ebd89690a7455d6ec096a6bfc4a8a891ac741ffe4e678ea2614853248658
event UserRequestForSignature(address recipient, uint256 value, bytes32 nonce);
<<< Latest
// 0xe1e0bc4a1db39a361e3589cae613d7b4862e1f9114dd3ff12ff45be395046968
event UserRequestForSignature(address recipient, uint256 value, bytes32 nonce, address token);
```
# Glossary
1. **BridgeRouter**: Entry point contract after the migration on Ethereum, facilitating routing and token swapping.
2. **xDAIForeignBridge**: xDAI bridge on Ethereum.
3. **HomeBridgeErcToNative** / **xDAI Home Bridge**: xDAI bridge on Gnosis Chain.
4. **USDSDepositContract**: Deposit contract on Gnosis Chain that acts as an entry point contract if user wants to receive USDS on Ethereum.
5. **Foreign Chain**: Ethereum
6. **Home Chain**: Gnosis Chain
# How to test with post migration environment
To simulate the actual mainnet environment, we use [Tenderly Virtual TestNets](https://tenderly.co/virtual-testnets) for both Ethereum and Gnosis Chain. Third-party applications are encouraged to use the following RPC endpoints to simulate the post-migration environment.
**Switch your RPC**:
1. Ethereum: https://virtual.mainnet.eu.rpc.tenderly.co/f3e5e498-bd28-4b49-a8f6-93f033e6fa6e
- Explorer: https://dashboard.tenderly.co/explorer/vnet/f3e5e498-bd28-4b49-a8f6-93f033e6fa6e
2. Gnosis Chain: https://virtual.gnosis.eu.rpc.tenderly.co/4c9e4122-6c01-46bd-a44a-e08133d2d2cc
- Explorer: https://dashboard.tenderly.co/explorer/vnet/4c9e4122-6c01-46bd-a44a-e08133d2d2cc
# Note for bridge governors
For call traces, state changes, emitted event, touched contracts, please check:
1. Tenderly Simulation on Ethereum: https://dashboard.tenderly.co/public/safe/safe-apps/simulator/7a369788-8c38-4ace-b7ed-1f25981e8bee
2. Tenderly Simulation on Gnosis Chain: https://dashboard.tenderly.co/public/safe/safe-apps/simulator/3940609f-bcf2-4428-9432-11a4c98ccd73
**Core contract in the upgrade**
1. XDaiForeignBridge.sol: `0x257bDD093Cab1Bd39eBF837dCB60f33d031d7d49`
2. HomeBridgeErcToNative.sol: `0xe6998b0C03D3cb9ee8C04f266e573c7Fa8782846`
3. USDSDepositContract.sol: `0x5C183C8A49aBA6e31049997a56D75600E27FF8c9`
**Peripheral contract in the upgrade**
1. BridgeRouter.sol: `0x74899961224538E423eFfD1A0Ff3346adf3F4C56`
2. TransparentUpgradeableProxy.sol: `0x9a873656c19Efecbfb4f9FAb5B7acdeAb466a0B0`
3. ProxyAdmin.sol: `0xD7e65A32bEd4ce8cc57Ec188F2bBb8016dc4b1cd`
4. XDaiBridgePeripheral.sol: `0x3b6669727927b934753B018EB421a84Ed4eb0a43`
**Contract & parameters mentioned in the upgrade transaction**
1. `0x257bDD093Cab1Bd39eBF837dCB60f33d031d7d49`(Ethereum): XDaiForeignBridge new implementation
2. `0xe6998b0C03D3cb9ee8C04f266e573c7Fa8782846`(Ethereum): HomeBridgeErcToNative new implementation
3. `0x5C183C8A49aBA6e31049997a56D75600E27FF8c9`(Gnosis Chain): USDSDepositContract
4. `0x74899961224538E423eFfD1A0Ff3346adf3F4C56`(Ethereum): BridgeRouter new implementaiton
5. `0x9a873656c19Efecbfb4f9FAb5B7acdeAb466a0B0`(Ethereum): TransparentUpgradeableProxy for BridgeRouter
6. `0xD7e65A32bEd4ce8cc57Ec188F2bBb8016dc4b1cd`(Ethereum): ProxyAdmin.sol for BridgeRouter, controls upgrade for the implementation contract w.r.t Proxy address
7. `0x3b6669727927b934753B018EB421a84Ed4eb0a43`(Ethereum): XDaiBridgePeripheral, swap DAI->USDS for user before bridging
8. `0x4aa42145aa6ebf72e164c9bbc74fbd3788045016`(Ethereum): XDaiForeignBridgeProxy
9. `0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6`(GnosisChain): HomeBridgErcToNativeProxy
10. `0x670daeaF0F1a5e336090504C68179670B5059088`(GnosisChain): InterestReceiver contract when `payInterest` is called. Related to sDAI yield when sDAI adapter `claim` function is [called](https://gnosisscan.io/address/0x670daeaf0f1a5e336090504c68179670b5059088#tokentxns)
11. `0x6B175474E89094C44Da98b954EedeAC495271d0F`(Ethereum): DAI token address
12. `0xdC035D45d973E3EC169d2276DDab16f1e407384F`(Ethereum): USDS token address
13. `minCashThreshold`: is the minimum USDS that the bridge need to hold for user to claim USDS back. It acts as a buffer and the minCashThreshold amount is not used for investing. Value: `1000000000000000000000000`. (Same as [`minCashThreshold(DAI)`](:https://etherscan.io/address/0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016#readProxyContract#F14))
14. `minInterestPaid`: The minimum amount of interest from sUSDS that can be withdrawn during a payInterest call. The payInterest call will be invalid if the available interest < minInterestedPaid. Value: `1000000000000000000000`. (Same as [`minInterestedPaid(DAI)`](https://etherscan.io/address/0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016#readProxyContract#F11))
**Technical Analysis**
We have requested Omega team to audit and verify the Safe transaction payload of the upgrade txs on both Ethereum and Gnosis Chain. The upgrade txs are consistent with the description on both this technical documentation and the governance forum.
Upgrade tx on Ethereum: [url](https://app.safe.global/transactions/tx?safe=eth:0x42F38ec5A75acCEc50054671233dfAC9C0E7A3F6&id=multisig_0x42F38ec5A75acCEc50054671233dfAC9C0E7A3F6_0x7309151c47d50ea0bac9eac0b28a13b8c2904857d7ddd6c65653336d9b53acc0)
Upgrade tx on Gnosis Chain: [url](https://app.safe.global/transactions/tx?safe=gno:0x7a48Dac683DA91e4faa5aB13D91AB5fd170875bd&id=multisig_0x7a48Dac683DA91e4faa5aB13D91AB5fd170875bd_0xb6d709f3f6fe73958bf4de18a2d8ba81b8981a18e0c17c9f608e61c03ec0e166)
Omega validations
- [x] The deployed bytecode of the deployed contracts match the deployed bytecode of the contracts audited by Omega.
- [x] The parameters and state changes of the transactions match the intented upgrade behaviors
- [x] The signatures in Bridge governors Safe correspond with the SafeTxHash and signatures of the Safe.
Both transactions are executed on Nov 7 2025.