-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
923 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
export const inboxAbi = [ | ||
{ | ||
inputs: [], | ||
name: 'depositEth', | ||
outputs: [{ type: 'uint256' }], | ||
stateMutability: 'payable', | ||
type: 'function' | ||
}, | ||
{ | ||
inputs: [ | ||
{ name: 'to', type: 'address' }, | ||
{ name: 'l2CallValue', type: 'uint256' }, | ||
{ name: 'maxSubmissionCost', type: 'uint256' }, | ||
{ name: 'excessFeeRefundAddress', type: 'address' }, | ||
{ name: 'callValueRefundAddress', type: 'address' }, | ||
{ name: 'gasLimit', type: 'uint256' }, | ||
{ name: 'maxFeePerGas', type: 'uint256' }, | ||
{ name: 'data', type: 'bytes' } | ||
], | ||
name: 'createRetryableTicket', | ||
outputs: [{ type: 'uint256' }], | ||
stateMutability: 'payable', | ||
type: 'function' | ||
}, | ||
{ | ||
anonymous: false, | ||
inputs: [ | ||
{ indexed: false, name: 'messageNum', type: 'uint256' }, | ||
{ indexed: false, name: 'data', type: 'bytes' } | ||
], | ||
name: 'InboxMessageDelivered', | ||
type: 'event' | ||
}, | ||
{ | ||
anonymous: false, | ||
inputs: [ | ||
{ indexed: false, name: 'messageNum', type: 'uint256' } | ||
], | ||
name: 'InboxMessageDeliveredFromOrigin', | ||
type: 'event' | ||
} | ||
] as const |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export const l1GatewayRouterAbi = [ | ||
{ | ||
inputs: [ | ||
{ name: '_token', type: 'address' }, | ||
{ name: '_to', type: 'address' }, | ||
{ name: '_amount', type: 'uint256' }, | ||
{ name: '_maxGas', type: 'uint256' }, | ||
{ name: '_gasPriceBid', type: 'uint256' }, | ||
{ name: '_data', type: 'bytes' } | ||
], | ||
name: 'outboundTransfer', | ||
outputs: [{ type: 'bytes' }], | ||
stateMutability: 'payable', | ||
type: 'function' | ||
}, | ||
{ | ||
inputs: [{ name: '_token', type: 'address' }], | ||
name: 'getGateway', | ||
outputs: [{ type: 'address' }], | ||
stateMutability: 'view', | ||
type: 'function' | ||
} | ||
] as const |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { | ||
type PublicClient, | ||
type WalletClient, | ||
type Client, | ||
encodeFunctionData, | ||
Account, | ||
Address, | ||
parseTransaction, | ||
serializeTransaction | ||
} from 'viem' | ||
import { localEthChain } from '../chains' | ||
import { inboxAbi } from './abis/inbox' | ||
|
||
export type ArbitrumDepositActions = { | ||
depositEth: (args: { | ||
amount: bigint; | ||
account: Account | Address; | ||
walletClient: WalletClient; | ||
}) => Promise<`0x${string}`> | ||
} | ||
|
||
type ArbitrumChainConfig = { | ||
ethBridge: { | ||
inbox: `0x${string}` | ||
} | ||
} | ||
|
||
export function arbitrumDepositActions(childChain: ArbitrumChainConfig) { | ||
return <TClient extends PublicClient>(parentPublicClient: TClient): ArbitrumDepositActions => { | ||
const getDepositRequest = async ({ | ||
amount, | ||
account | ||
}: { | ||
amount: bigint | ||
account: Account | Address | ||
}) => { | ||
const from = typeof account === 'string' ? account : account.address | ||
|
||
return { | ||
to: childChain.ethBridge.inbox, | ||
value: amount, | ||
data: encodeFunctionData({ | ||
abi: inboxAbi, | ||
functionName: 'depositEth', | ||
args: [] | ||
}), | ||
from | ||
} | ||
} | ||
|
||
return { | ||
async depositEth({ amount, account, walletClient }) { | ||
const request = await getDepositRequest({ | ||
amount, | ||
account | ||
}) | ||
|
||
const gasPrice = await parentPublicClient.getGasPrice() | ||
|
||
const nonce = await parentPublicClient.getTransactionCount({ | ||
address: typeof account === 'string' ? account as `0x${string}` : account.address, | ||
blockTag: 'latest' | ||
}) | ||
|
||
const signedTx = await walletClient.signTransaction({ | ||
...request, | ||
account, | ||
chain: localEthChain, | ||
gas: BigInt('130000'), | ||
maxFeePerGas: gasPrice, | ||
maxPriorityFeePerGas: gasPrice, | ||
nonce | ||
}) | ||
|
||
// Parse and serialize with L2 chain ID | ||
const parsedTx = parseTransaction((signedTx as any).raw) | ||
const serializedTx = serializeTransaction({ | ||
...parsedTx, | ||
}) | ||
|
||
// Send to L2 | ||
const hash = await parentPublicClient.sendRawTransaction({ | ||
serializedTransaction: serializedTx | ||
}) | ||
|
||
return hash | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import type { Address, Hash, Transport } from 'viem' | ||
import type { | ||
PublicClient, | ||
WalletClient, | ||
Account, | ||
Chain | ||
} from 'viem' | ||
|
||
export type ArbitrumDepositConfig = { | ||
inboxAddress: Address | ||
} | ||
|
||
export type GasOverrides = { | ||
gasLimit?: { | ||
min?: bigint | ||
max?: bigint | ||
} | ||
maxFeePerGas?: { | ||
min?: bigint | ||
max?: bigint | ||
} | ||
maxSubmissionCost?: { | ||
min?: bigint | ||
max?: bigint | ||
} | ||
} | ||
|
||
export type RetryableGasParams = { | ||
gasLimit: bigint | ||
maxFeePerGas: bigint | ||
maxSubmissionCost: bigint | ||
} | ||
|
||
export type EthDepositParameters = { | ||
amount: bigint | ||
account: Account | Address | ||
to?: Address // Optional destination address | ||
retryableGasOverrides?: GasOverrides | ||
} | ||
|
||
export type Erc20DepositParameters = { | ||
token: Address | ||
amount: bigint | ||
account: Account | Address | ||
to?: Address // Optional destination address, defaults to sender | ||
} | ||
|
||
export type ApproveErc20Parameters = { | ||
token: Address | ||
amount: bigint | ||
account: Account | Address | ||
} | ||
|
||
export type ArbitrumDepositActions = { | ||
depositEth: (args: EthDepositParameters) => Promise<Hash> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { type Chain } from 'viem' | ||
|
||
export const localEthChain = { | ||
id: 1337, | ||
name: 'EthLocal', | ||
nativeCurrency: { | ||
decimals: 18, | ||
name: 'Ether', | ||
symbol: 'ETH', | ||
}, | ||
rpcUrls: { | ||
default: { http: ['http://localhost:8545'] }, | ||
public: { http: ['http://localhost:8545'] }, | ||
} | ||
} as const satisfies Chain | ||
|
||
export const localArbChain = { | ||
id: 412346, | ||
name: 'ArbLocal', | ||
nativeCurrency: { | ||
decimals: 18, | ||
name: 'Ether', | ||
symbol: 'ETH', | ||
}, | ||
rpcUrls: { | ||
default: { http: ['http://localhost:8547'] }, | ||
public: { http: ['http://localhost:8547'] }, | ||
} | ||
} as const satisfies Chain | ||
|
||
function getChainConfig(chainId: number) { | ||
const chains = { | ||
[localEthChain.id]: localEthChain, | ||
[localArbChain.id]: localArbChain | ||
} | ||
return chains[chainId as keyof typeof chains] | ||
} | ||
|
||
export { getChainConfig } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { expect } from 'chai' | ||
import { createWalletClient, createPublicClient, http, parseEther } from 'viem' | ||
import { privateKeyToAccount } from 'viem/accounts' | ||
import { arbitrumDepositActions } from '../../src/experimental/arbitrumDeposit/actions' | ||
import { testSetup, config } from '../../scripts/testSetup' | ||
import { localEthChain, localArbChain } from '../../src/experimental/chains' | ||
|
||
describe('arbitrumDepositActions', function() { | ||
this.timeout(60000) | ||
|
||
it('deposits ether', async function() { | ||
const { childChain } = await testSetup() | ||
|
||
const account = privateKeyToAccount(`0x${config.ethKey}` as `0x${string}`) | ||
|
||
// Create parent clients | ||
const parentWalletClient = createWalletClient({ | ||
account, | ||
chain: localEthChain, | ||
transport: http(config.ethUrl) | ||
}) | ||
|
||
const parentPublicClient = createPublicClient({ | ||
chain: localEthChain, | ||
transport: http(config.ethUrl) | ||
}).extend(arbitrumDepositActions({ | ||
ethBridge: { | ||
inbox: childChain.ethBridge.inbox as `0x${string}` | ||
} | ||
})) | ||
|
||
// Create child client for balance checks | ||
const childPublicClient = createPublicClient({ | ||
chain: localArbChain, | ||
transport: http(config.arbUrl) | ||
}) | ||
|
||
const initialBalance = await childPublicClient.getBalance({ | ||
address: account.address | ||
}) | ||
console.log('Initial child balance:', initialBalance) | ||
|
||
const depositAmount = parseEther('0.01') | ||
console.log('Deposit amount:', depositAmount) | ||
|
||
const hash = await parentPublicClient.depositEth({ | ||
amount: depositAmount, | ||
account: account.address, | ||
walletClient: parentWalletClient | ||
}) | ||
|
||
// Wait for parent transaction | ||
const receipt = await parentPublicClient.waitForTransactionReceipt({ | ||
hash, | ||
confirmations: 1 | ||
}) | ||
|
||
expect(receipt.status).to.equal('success') | ||
|
||
// Poll for child balance change | ||
let finalBalance = initialBalance | ||
let attempts = 0 | ||
const maxAttempts = 10 | ||
|
||
while (attempts < maxAttempts) { | ||
await new Promise(resolve => setTimeout(resolve, 3000)) | ||
|
||
const currentBalance = await childPublicClient.getBalance({ | ||
address: account.address | ||
}) | ||
|
||
console.log(`Attempt ${attempts + 1} - Current balance:`, currentBalance) | ||
|
||
if (currentBalance > initialBalance) { | ||
finalBalance = currentBalance | ||
break | ||
} | ||
|
||
attempts++ | ||
} | ||
|
||
console.log('Final child balance:', finalBalance) | ||
console.log('Balance difference:', finalBalance - initialBalance) | ||
|
||
expect(Number(finalBalance)).to.be.greaterThan( | ||
Number(initialBalance), | ||
'child balance did not increase after deposit' | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.