Skip to content

Conversation

@bmzig
Copy link
Contributor

@bmzig bmzig commented Oct 28, 2024

Summary

Adding backwards and forwards compatibility

When attempting to deploy the Arbitrum_CustomGasTokens_Adapter to support Aleph Zero, we realized that the deployed ERC20BridgeContract does not actually contain the nativeTokenDecimals() function as the contracts would suggest. More critically, the amount to be bridged is not scaled in the legacy AbsInbox but it is in the new one.

It turns out the issue is that Aleph Zero contracts were deployed using an outdated version of Arbitrum contracts. The contract has been modified to work with legacy and new versions of the Inbox contract:

  • We add a new constructor argument to set the native token decimals, rather than reading it from the bridge contract’s nativeTokenDecimals() function which won’t exist on legacy deployments.
  • We have confirmed that all legacy deployments like Aleph Zero's will use 18 decimals of precision, so we can keep the _from18ToNativeDecimals() conversion function in the relayTokens/relayMessage logic

Other changes

The following opportunistic fixes were also made to the Arbitrum_CustomGasTokens_Adapter contract in this PR:

  • Pass the Circle CCTP Domain ID in the constructor of the adapter instead of hardcoding the CCTP domain ID. This is just a stylistic refactor.
  • Modify the l2CallValueField of our call to createRetryableTicket when bridging the custom gas token to specify the amount of native token to bridge.

Notes

Re-implementation of #690

nicholaspai and others added 7 commits October 8, 2024 22:19
…ken precision (#589)

* improve(Arbitrum_CustomGasToken_Adapter): Handle non-18 custom gas token precision

Based on this [Inbox](https://github.com/OffchainLabs/nitro-contracts/blob/fbbcef09c95f69decabaced3da683f987902f3e2/src/bridge/AbsInbox.sol#L237) code which implies that the `tokenTotalFeeAmount` passed into the [ERC20Inbox](https://github.com/OffchainLabs/nitro-contracts/blob/fbbcef09c95f69decabaced3da683f987902f3e2/src/bridge/ERC20Inbox.sol#L85) should be in the custom gas token's precision while the `maxSubmissionCost`, `gasPrice`, and `gasLimit` should all be same as for normal Arbitrum messages

* Update contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol

* Update contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol

* Update Arbitrum_CustomGasToken_Adapter.sol

* support deecimals > 18

* divCeil instead of divFLoor
World Chain implements Circle's bridged USDC standard. Deposits &
withdrawals cannot be initiated via the L1StandardBridge and
L2StandardBridge contracts respectively. Instead they must be sent to
World Chain's own implementations of Circle's bridged USDC standard.

In recognition of the fact that this will likely be a repeating pattern
for new deployments, restyle the World Chain adapter as a generic OP
adapter and instead rely on deployment scripts to configure it with the
correct bridges.

Circle's standard is described here:
https://github.com/circlefin/stablecoin-evm/blob/master/doc/bridged_USDC_standard.md

The process for bridged USDC deposits & withdrawals is here:
https://github.com/defi-wonderland/opUSDC/tree/main?tab=readme-ov-file#l1--l2-usdc-canonical-bridging
* fix: Support OP bridged USDC in WorldChain adapter

Signed-off-by: bennett <bennett@umaproject.org>

---------

Signed-off-by: bennett <bennett@umaproject.org>
Co-authored-by: Paul <108695806+pxrl@users.noreply.github.com>
These are recorded under the OP adapter due to the name of the contract
that was deployed. Some or all of this will be overwritten on subsequent
OP adapter deployments.
This is the deployment info for the WorldChain_SpokePool deployed at the 
current audit-latest code.

Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
@james-a-morris
Copy link
Contributor

Is this ready to go in? cc @melisaguevara @bmzig @pxrl

@nicholaspai nicholaspai added the do not merge do not merge label Oct 28, 2024
Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
* - The token must have a max of 2^256 - 1 wei total supply unscaled
* - The token must have a max of 2^256 - 1 wei total supply when scaled to 18 decimals
*/
interface ArbitrumL1ERC20Bridge {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these interfaces be read from the base adapter file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Yeah it should: 897a339

Signed-off-by: bennett <bennett@umaproject.org>
bmzig added 4 commits October 29, 2024 16:28
Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
Copy link
Member

@nicholaspai nicholaspai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two suggestions

Signed-off-by: bennett <bennett@umaproject.org>
Signed-off-by: bennett <bennett@umaproject.org>
@nicholaspai nicholaspai changed the base branch from audit-latest to master October 30, 2024 14:55
@nicholaspai nicholaspai changed the base branch from master to audit-latest November 5, 2024 20:19
@nicholaspai nicholaspai changed the base branch from audit-latest to master November 5, 2024 20:20
@nicholaspai nicholaspai removed the do not merge do not merge label Nov 5, 2024
Signed-off-by: bennett <bennett@umaproject.org>
}
}

function _fromNativeTo18Decimals(uint256 amount) internal view returns (uint256) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was taken from here. I removed the check for uint256 overflow, since this shouldn't happen assuming the constructors are correct, which we can easily verify before enabling anything in the hub pool. Also, the scaling is taken from here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to note, in the case where NATIVE_TOKEN_DECIMALS > 18, we'll be dividing and effectively rounding down the result. Is that OK when passing in this rounded down value into the Inbox.createRetryableTicket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a small comment about this here: 7082475

Signed-off-by: bennett <bennett@umaproject.org>
L1_INBOX.createRetryableTicket(
to, // destAddr destination L2 contract address
L2_CALL_VALUE, // l2CallValue call value for retryable L2 message
_fromNativeTo18Decimals(amount), // l2CallValue call value for retryable L2 message
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't just a decimal change, this seems to be a deeper functional change.

Previously, the second arg looks like it was always set to 0. Now it appears that we're passing in the amount (decimal converted).

Was the previous code wrong in setting this field to a 0 constant? Or is the new code doing something more subtle that I'm failing to understand?

Copy link
Contributor Author

@bmzig bmzig Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For (hopefully) full context:
Setting this to 0 was incorrect. This function is called only when trying to bridge the AZERO token. When we set this to zero, the aliased L1 sender address will receive amountToBridge, i.e. amount+bridge fees, and then call the target with 0 value (in this context, 0 value means no L2 native token transfer). It then only refunds excess bridge gas costs to the L2 target. This means that amount is stuck in the aliased address on L2 (for example, we can see this happened with the aliased dev wallet and the aliased adapter). While it's not loss of funds, since we effectively have control over the aliased address by nudging the bridge from L1, we obviously didn't want this.

The first change was to just put in amount as the l2CallValue field here, which works for AZERO, since AZERO happens to have 18 decimals, but for a token which has non-18 decimal precision, we would be passing in a value with native token precision, when the contracts assume l2Callvalue is in 18 decimal precision. This lead to the second change, seen above, where we convert l2CallValue from native token decimals to 18.

Copy link
Contributor

@mrice32 mrice32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Signed-off-by: bennett <bennett@umaproject.org>
@nicholaspai nicholaspai merged commit e8921d7 into master Nov 6, 2024
9 checks passed
@nicholaspai nicholaspai deleted the bz/azeroChanges branch November 6, 2024 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants