Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add weth gateway registration #44

Merged
merged 72 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
ec5967d
everything before cleanup
spsjvc Dec 28, 2023
f653ec2
start cleaning up stuff
spsjvc Dec 28, 2023
b9b5cf0
clean up more
spsjvc Dec 28, 2023
67be35a
clean up more
spsjvc Dec 28, 2023
4aea262
rm unused
spsjvc Dec 28, 2023
be153ed
rm unused again
spsjvc Dec 28, 2023
d0a1eac
make parent configurable in test rollup
spsjvc Dec 28, 2023
b88c709
temp fix
spsjvc Dec 28, 2023
782eee3
wait for retryables
spsjvc Jan 9, 2024
44445ad
unused import
spsjvc Jan 9, 2024
3034c4c
move stuff around
spsjvc Jan 9, 2024
f5860e5
more ethers viem compat stuff
spsjvc Jan 9, 2024
cea16a8
return retryables
spsjvc Jan 9, 2024
4e256d6
Merge branch 'main' into feat-token-bridge-creator
spsjvc Jan 9, 2024
9a2de12
format
spsjvc Jan 9, 2024
7d565c1
bump token bridge contracts
spsjvc Jan 9, 2024
018179b
increase test timeout
spsjvc Jan 10, 2024
e7d0f69
fix test
spsjvc Jan 22, 2024
716249c
add helper to deploy token bridge creator
spsjvc Jan 22, 2024
c028ce7
cast to address
spsjvc Jan 22, 2024
f85aae5
wrap up test
spsjvc Jan 23, 2024
d462cde
remove unneeded code
spsjvc Jan 23, 2024
6f0561a
fix nitro-testnode ref
spsjvc Jan 23, 2024
e53c510
fix
spsjvc Jan 23, 2024
aa049d6
try
spsjvc Jan 23, 2024
c06ac5f
comment
spsjvc Jan 23, 2024
bd3deca
add logs
spsjvc Jan 23, 2024
1f67c88
load rollup and rollup owner
spsjvc Jan 23, 2024
1d97f85
Merge branch 'main' into feat-token-bridge-creator
TucksonDev Jan 24, 2024
f6d8a39
Clean up token bridge ABI and add createRollupFetchCoreContracts and …
TucksonDev Jan 24, 2024
efdb47e
Add feedback changes
TucksonDev Jan 25, 2024
fdccf15
Fix publicClientToProvider RPC bug
TucksonDev Jan 25, 2024
2e33364
Add approval methods and examples
TucksonDev Jan 25, 2024
cb9d564
Increase tests timeout
TucksonDev Jan 26, 2024
d6cea89
Test with simpler args for testnode on CI
TucksonDev Jan 29, 2024
73fb8c5
Add integration test for a token bridge on l3 with custom fee token
TucksonDev Jan 30, 2024
8582253
Add gas overriding options for creating a token bridge
TucksonDev Jan 30, 2024
6463345
Revert branch change for token-bridge-contracts
TucksonDev Jan 30, 2024
1b6ce9e
Bring back no-token-bridge flag
TucksonDev Jan 30, 2024
efb4b4d
Change branch of token-bridge-contracts
TucksonDev Jan 30, 2024
0369f82
Add comment back on CI file and add testnode command to README
TucksonDev Jan 30, 2024
87cb0e1
Merge branch 'main' into feat-token-bridge-creator
TucksonDev Jan 30, 2024
894b8a3
feat: add weth gateway registration
TucksonDev Feb 1, 2024
bba4fc3
Change gas limit percentage increase to enforced minimum gasLimit
TucksonDev Feb 1, 2024
704c3cf
Format
TucksonDev Feb 1, 2024
b3ff466
Adjust default value for token bridge creation
TucksonDev Feb 1, 2024
5447e56
Update example to create token bridge
TucksonDev Feb 1, 2024
8db15a0
Format
TucksonDev Feb 1, 2024
fc82da8
Merge branch 'feat-token-bridge-creator' into feat-add-weth-gateway-r…
TucksonDev Feb 1, 2024
2ef2e55
Added changes from review
TucksonDev Feb 7, 2024
3bfe7e2
Adjust testnode CI action flags
TucksonDev Feb 8, 2024
145063e
Change TokenBridgeCreator address on L1 testnode since the rollup own…
TucksonDev Feb 8, 2024
9511462
Merge branch 'main' into feat-token-bridge-creator
TucksonDev Feb 8, 2024
9547b8e
Adjustments from merge
TucksonDev Feb 8, 2024
ff94adc
Add fetch contracts in example and add check for retryables status
TucksonDev Feb 8, 2024
bd90710
Format
TucksonDev Feb 8, 2024
4f51836
Merge branch 'feat-token-bridge-creator' into feat-add-weth-gateway-r…
TucksonDev Feb 8, 2024
2cf9c96
Changes from merge
TucksonDev Feb 8, 2024
b739e1e
Format
TucksonDev Feb 8, 2024
cfe21f7
Smol adjustments
TucksonDev Feb 8, 2024
5da1247
Bump viem peerDependency
TucksonDev Feb 8, 2024
e1cc9a1
Merge branch 'feat-token-bridge-creator' into feat-add-weth-gateway-r…
TucksonDev Feb 8, 2024
bb123f9
Merge branch 'main' into feat-add-weth-gateway-registration
TucksonDev Feb 20, 2024
54e9f04
Changes from last merge
TucksonDev Feb 20, 2024
59ae2ae
Some cleanup
TucksonDev Feb 20, 2024
98a7f17
Format
TucksonDev Feb 20, 2024
f4b913c
Add orbit contract verification on example
TucksonDev Feb 20, 2024
3ed5f2e
Merge branch 'main' into feat-add-weth-gateway-registration
TucksonDev Feb 28, 2024
d428e9a
Use the new TokenBridgeCreator override to fix the failing integratio…
TucksonDev Feb 28, 2024
6addddd
Format
TucksonDev Feb 28, 2024
b4174fd
Remove extra retryables and add check for Orbit side
TucksonDev Feb 29, 2024
2c175a7
Format
TucksonDev Feb 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ARBISCAN_API_KEY=
PRIVATE_KEY=0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659

NITRO_TESTNODE_DEPLOYER_PRIVATE_KEY=0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659
NITRO_TESTNODE_L2_ROLLUP_OWNER_PRIVATE_KEY=0xdc04c5399f82306ec4b4d654a342f40e2e0620fe39950d967e1e574b32d4dd36
NITRO_TESTNODE_L3_ROLLUP_OWNER_PRIVATE_KEY=0xecdf21cb41c65afb51f91df408b7656e2c8739a5877f2814add0afd780cc210e
9 changes: 4 additions & 5 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,13 @@ jobs:
uses: OffchainLabs/actions/run-nitro-test-node@main
with:
nitro-testnode-ref: release
# don't deploy the regular token bridge using arbitrum-sdk, as it will be deployed through the TokenBridgeCreator
no-token-bridge: true
# Use simple mode
no-simple: false
# RollupCreator on L1 is deployed by default
# RollupCreator on L2 is deployed with --l3node
l3-node: true
# TokenBridgeCreator on L1 is deployed with --tokenbridge
# TokenBridgeCreator on L2 is deployed with --l3-token-bridge
args: --tokenbridge --l3-token-bridge
# L3 node with custom fee token when using --l3-fee-token
args: --l3-fee-token

- name: Copy .env
run: cp ./.env.example ./.env
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ Make sure you are using Node v18 or greater.
yarn add @arbitrum/orbit-sdk viem
```

## Run integration tests

Clone the branch `main` of [nitro-testnode](https://github.com/OffchainLabs/nitro-testnode), and run the testnode using the following arguments:

```bash
./test-node.bash --init --tokenbridge --l3node --l3-fee-token --l3-token-bridge
```

Then, run the integration tests:

```bash
yarn test:integration
```

## Examples

See [examples](./examples).
13 changes: 13 additions & 0 deletions examples/create-token-bridge-custom-fee-token/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Address of the Rollup contract
ROLLUP_ADDRESS=

# Private key of the account with executor privileges in the UpgradeExecutor admin contract for the chain
# (usually, the deployer of the chain)
ROLLUP_OWNER_PRIVATE_KEY=

# Custom fee token address on the parent chain
CUSTOM_FEE_TOKEN_ADDRESS=

# Orbit chain configuration
ORBIT_CHAIN_ID=
ORBIT_CHAIN_RPC=
147 changes: 147 additions & 0 deletions examples/create-token-bridge-custom-fee-token/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { Chain, createPublicClient, http, Address, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { arbitrumSepolia } from 'viem/chains';
import {
createTokenBridgeEnoughCustomFeeTokenAllowance,
createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest,
createTokenBridgePrepareTransactionRequest,
createTokenBridgePrepareTransactionReceipt,
} from '@arbitrum/orbit-sdk';
import { config } from 'dotenv';
config();

function sanitizePrivateKey(privateKey: string): `0x${string}` {
if (!privateKey.startsWith('0x')) {
return `0x${privateKey}`;
}

return privateKey as `0x${string}`;
}

function getBlockExplorerUrl(chain: Chain) {
return chain.blockExplorers?.default.url;
}

if (typeof process.env.ROLLUP_ADDRESS === 'undefined') {
throw new Error(`Please provide the "ROLLUP_ADDRESS" environment variable`);
}

if (typeof process.env.ROLLUP_OWNER_PRIVATE_KEY === 'undefined') {
throw new Error(`Please provide the "ROLLUP_OWNER_PRIVATE_KEY" environment variable`);
}

if (typeof process.env.ORBIT_CHAIN_ID === 'undefined') {
throw new Error(`Please provide the "ORBIT_CHAIN_ID" environment variable`);
}

if (typeof process.env.ORBIT_CHAIN_RPC === 'undefined') {
throw new Error(`Please provide the "ORBIT_CHAIN_RPC" environment variable`);
}

if (typeof process.env.CUSTOM_FEE_TOKEN_ADDRESS === 'undefined') {
throw new Error(`Please provide the "CUSTOM_FEE_TOKEN_ADDRESS" environment variable`);
}

// set the parent chain and create a public client for it
const parentChain = arbitrumSepolia;
const parentChainPublicClient = createPublicClient({
chain: parentChain,
transport: http(),
});

// define chain config for the orbit chain
const orbitChain = defineChain({
id: Number(process.env.ORBIT_CHAIN_ID),
network: 'Orbit chain',
name: 'orbit',
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: {
http: [process.env.ORBIT_CHAIN_RPC],
},
public: {
http: [process.env.ORBIT_CHAIN_RPC],
},
},
testnet: true,
});
const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() });

// load the rollup owner account
const rollupOwner = privateKeyToAccount(sanitizePrivateKey(process.env.ROLLUP_OWNER_PRIVATE_KEY));

async function main() {
// set the custom fee token
const nativeToken: Address = process.env.CUSTOM_FEE_TOKEN_ADDRESS as `0x${string}`;

// prepare transaction to approve custom fee token spend
const allowanceParams = {
nativeToken,
owner: rollupOwner.address,
publicClient: parentChainPublicClient,
};
if (!(await createTokenBridgeEnoughCustomFeeTokenAllowance(allowanceParams))) {
const approvalTxRequest =
await createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest(allowanceParams);

// sign and send the transaction
const approvalTxHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(approvalTxRequest),
});

// get the transaction receipt after waiting for the transaction to complete
const approvalTxReceipt = await parentChainPublicClient.waitForTransactionReceipt({
hash: approvalTxHash,
});

console.log(
`Tokens approved in ${getBlockExplorerUrl(parentChain)}/tx/${
approvalTxReceipt.transactionHash
}`,
);
}

// prepare the transaction for deploying the core contracts
const txRequest = await createTokenBridgePrepareTransactionRequest({
params: {
rollup: process.env.ROLLUP_ADDRESS as `0x${string}`,
rollupOwner: rollupOwner.address,
},
parentChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
});

// sign and send the transaction
console.log(`Deploying the TokenBridge...`);
const txHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(txRequest),
});

// get the transaction receipt after waiting for the transaction to complete
const txReceipt = createTokenBridgePrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
);
console.log(`Deployed in ${getBlockExplorerUrl(parentChain)}/tx/${txReceipt.transactionHash}`);

// wait for retryables to execute
console.log(`Waiting for retryable tickets to execute on the Orbit chain...`);
const orbitChainRetryableReceipts = await txReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
console.log(`Retryables executed`);
console.log(
`Transaction hash for first retryable is ${orbitChainRetryableReceipts[0].transactionHash}`,
);
console.log(
`Transaction hash for second retryable is ${orbitChainRetryableReceipts[1].transactionHash}`,
);

// fetching the TokenBridge contracts
const tokenBridgeContracts = await txReceipt.getTokenBridgeContracts({
parentChainPublicClient,
});
console.log(`TokenBridge contracts:`, tokenBridgeContracts);
}

main();
13 changes: 13 additions & 0 deletions examples/create-token-bridge-custom-fee-token/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "create-token-bridge-custom-fee-token",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "tsc --outDir dist && node ./dist/index.js"
},
"devDependencies": {
"@types/node": "^20.9.0",
"typescript": "^5.2.2"
}
}
4 changes: 4 additions & 0 deletions examples/create-token-bridge-custom-fee-token/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.base.json",
"include": ["./**/*"]
}
10 changes: 10 additions & 0 deletions examples/create-token-bridge-eth/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Address of the Rollup contract
ROLLUP_ADDRESS=

# Private key of the account with executor privileges in the UpgradeExecutor admin contract for the chain
# (usually, the deployer of the chain)
ROLLUP_OWNER_PRIVATE_KEY=

# Orbit chain configuration
ORBIT_CHAIN_ID=
ORBIT_CHAIN_RPC=
148 changes: 148 additions & 0 deletions examples/create-token-bridge-eth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { Chain, createPublicClient, http, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { arbitrumSepolia } from 'viem/chains';
import {
createTokenBridgePrepareSetWethGatewayTransactionReceipt,
createTokenBridgePrepareSetWethGatewayTransactionRequest,
createTokenBridgePrepareTransactionReceipt,
createTokenBridgePrepareTransactionRequest,
} from '@arbitrum/orbit-sdk';
import { config } from 'dotenv';
config();

function sanitizePrivateKey(privateKey: string): `0x${string}` {
if (!privateKey.startsWith('0x')) {
return `0x${privateKey}`;
}

return privateKey as `0x${string}`;
}

function getBlockExplorerUrl(chain: Chain) {
return chain.blockExplorers?.default.url;
}

if (typeof process.env.ROLLUP_ADDRESS === 'undefined') {
throw new Error(`Please provide the "ROLLUP_ADDRESS" environment variable`);
}

if (typeof process.env.ROLLUP_OWNER_PRIVATE_KEY === 'undefined') {
throw new Error(`Please provide the "ROLLUP_OWNER_PRIVATE_KEY" environment variable`);
}

if (typeof process.env.ORBIT_CHAIN_ID === 'undefined') {
throw new Error(`Please provide the "ORBIT_CHAIN_ID" environment variable`);
}

if (typeof process.env.ORBIT_CHAIN_RPC === 'undefined') {
throw new Error(`Please provide the "ORBIT_CHAIN_RPC" environment variable`);
}

// set the parent chain and create a public client for it
const parentChain = arbitrumSepolia;
const parentChainPublicClient = createPublicClient({ chain: parentChain, transport: http() });

// define chain config for the orbit chain
const orbitChain = defineChain({
id: Number(process.env.ORBIT_CHAIN_ID),
network: 'Orbit chain',
name: 'orbit',
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: {
http: [process.env.ORBIT_CHAIN_RPC],
},
public: {
http: [process.env.ORBIT_CHAIN_RPC],
},
},
testnet: true,
});
const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() });

// load the rollup owner account
const rollupOwner = privateKeyToAccount(sanitizePrivateKey(process.env.ROLLUP_OWNER_PRIVATE_KEY));

async function main() {
// prepare the transaction for creating the token bridge
const txRequest = await createTokenBridgePrepareTransactionRequest({
params: {
rollup: process.env.ROLLUP_ADDRESS as `0x${string}`,
rollupOwner: rollupOwner.address,
},
parentChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
});

// sign and send the transaction
console.log(`Deploying the TokenBridge...`);
const txHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(txRequest),
});

// get the transaction receipt after waiting for the transaction to complete
const txReceipt = createTokenBridgePrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
);
console.log(`Deployed in ${getBlockExplorerUrl(parentChain)}/tx/${txReceipt.transactionHash}`);

// wait for retryables to execute
console.log(`Waiting for retryable tickets to execute on the Orbit chain...`);
const orbitChainRetryableReceipts = await txReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
console.log(`Retryables executed`);
console.log(
`Transaction hash for first retryable is ${orbitChainRetryableReceipts[0].transactionHash}`,
);
console.log(
`Transaction hash for second retryable is ${orbitChainRetryableReceipts[1].transactionHash}`,
);

// set weth gateway
const setWethGatewayTxRequest = await createTokenBridgePrepareSetWethGatewayTransactionRequest({
rollup: process.env.ROLLUP_ADDRESS as `0x${string}`,
parentChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
gasOverrides: {
retryableTicketGasLimit: {
percentIncrease: 200n,
},
},
});

// sign and send the transaction
const setWethGatewayTxHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(setWethGatewayTxRequest),
});

// get the transaction receipt after waiting for the transaction to complete
const setWethGatewayTxReceipt = createTokenBridgePrepareSetWethGatewayTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: setWethGatewayTxHash }),
);

console.log(
`Weth gateway set in ${getBlockExplorerUrl(parentChain)}/tx/${
setWethGatewayTxReceipt.transactionHash
}`,
);

// Wait for retryables to execute
const orbitChainSetWethGatewayRetryableReceipt = await setWethGatewayTxReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
console.log(`Retryables executed`);
console.log(
`Transaction hash for retryable is ${orbitChainSetWethGatewayRetryableReceipt.transactionHash}`,
);

// fetching the TokenBridge contracts
const tokenBridgeContracts = await txReceipt.getTokenBridgeContracts({
parentChainPublicClient,
});
console.log(`TokenBridge contracts:`, tokenBridgeContracts);
}

main();
Loading
Loading