@@ -18,6 +18,7 @@ const {
18
18
ParentEthDepositTransactionReceipt,
19
19
} = require ( '@arbitrum/sdk' ) ;
20
20
const { getBaseFee } = require ( '@arbitrum/sdk/dist/lib/utils/lib' ) ;
21
+ const { ERC20__factory } = require ( '@arbitrum/sdk/dist/lib/abi/factories/ERC20__factory' ) ;
21
22
require ( 'dotenv' ) . config ( ) ;
22
23
requireEnvVariables ( [ 'PRIVATE_KEY' , 'CHAIN_RPC' , 'PARENT_CHAIN_RPC' , 'TransferTo' ] ) ;
23
24
@@ -50,15 +51,24 @@ const main = async () => {
50
51
const ethBridger = new EthBridger ( childChainNetwork ) ;
51
52
const inboxAddress = ethBridger . childNetwork . ethBridge . inbox ;
52
53
54
+ /**
55
+ * We find out whether the child chain we are using is a custom gas token chain
56
+ * We need to perform an additional approve call to transfer
57
+ * the native tokens to pay for the gas of the retryable tickets.
58
+ */
59
+ const isCustomGasTokenChain =
60
+ childChainNetwork . nativeToken && childChainNetwork . nativeToken !== ethers . constants . AddressZero ;
61
+
53
62
/**
54
63
* We deploy EthDeposit contract to the parent chain first and send eth to
55
64
* the child chain via this contract.
56
65
* Funds will deposit to the contract's alias address first.
57
66
*/
58
- const DepositContract = await (
59
- await hre . ethers . getContractFactory ( 'EthDeposit' )
60
- ) . connect ( parentChainWallet ) ;
61
- console . log ( 'Deploying EthDeposit contract...' ) ;
67
+ const depositContractName = isCustomGasTokenChain ? 'CustomGasTokenDeposit' : 'EthDeposit' ;
68
+ const DepositContract = ( await hre . ethers . getContractFactory ( depositContractName ) ) . connect (
69
+ parentChainWallet ,
70
+ ) ;
71
+ console . log ( `Deploying ${ depositContractName } contract...` ) ;
62
72
const depositContract = await DepositContract . deploy ( inboxAddress ) ;
63
73
await depositContract . deployed ( ) ;
64
74
console . log ( `deployed to ${ depositContract . address } ` ) ;
@@ -71,18 +81,41 @@ const main = async () => {
71
81
72
82
console . log ( `Sending deposit transaction...` ) ;
73
83
74
- const ethDepositTx = await depositContract . depositToChildChain ( {
75
- value : ethers . utils . parseEther ( '0.01' ) ,
76
- } ) ;
77
- const ethDepositRec = await ethDepositTx . wait ( ) ;
84
+ let depositTx ;
85
+ let nativeTokenDecimals = 18 ; // We default to 18 decimals for ETH and most of ERC-20 tokens
86
+ if ( isCustomGasTokenChain ) {
87
+ // Approve the gas token to be sent to the contract
88
+ console . log ( 'Giving allowance to the contract to transfer the chain native token' ) ;
89
+ const nativeToken = new ethers . Contract (
90
+ childChainNetwork . nativeToken ,
91
+ ERC20__factory . abi ,
92
+ parentChainWallet ,
93
+ ) ;
94
+ nativeTokenDecimals = await nativeToken . decimals ( ) ;
95
+ const approvalTransaction = await nativeToken . approve (
96
+ depositContract . address ,
97
+ ethers . utils . parseUnits ( '1' , nativeTokenDecimals ) ,
98
+ ) ;
99
+ const approvalTransactionReceipt = await approvalTransaction . wait ( ) ;
100
+ console . log ( `Approval transaction receipt is: ${ approvalTransactionReceipt . transactionHash } ` ) ;
101
+
102
+ depositTx = await depositContract . depositToChildChain (
103
+ ethers . utils . parseUnits ( '0.01' , nativeTokenDecimals ) ,
104
+ ) ;
105
+ } else {
106
+ depositTx = await depositContract . depositToChildChain ( {
107
+ value : ethers . utils . parseEther ( '0.01' ) , // Here we know we are using ETH, so we can use parseEther
108
+ } ) ;
109
+ }
110
+ const depositReceipt = await depositTx . wait ( ) ;
78
111
79
- console . log ( `Deposit txn confirmed on the parent chain! 🙌 ${ ethDepositRec . transactionHash } ` ) ;
112
+ console . log ( `Deposit txn confirmed on the parent chain! 🙌 ${ depositReceipt . transactionHash } ` ) ;
80
113
81
114
console . log (
82
115
'Waiting for the execution of the deposit in the child chain. This may take up to 10-15 minutes ⏰' ,
83
116
) ;
84
117
85
- const parentChainDepositTxReceipt = new ParentEthDepositTransactionReceipt ( ethDepositRec ) ;
118
+ const parentChainDepositTxReceipt = new ParentEthDepositTransactionReceipt ( depositReceipt ) ;
86
119
const childChainDepositResult = await parentChainDepositTxReceipt . waitForChildTransactionReceipt (
87
120
childChainProvider ,
88
121
) ;
@@ -103,7 +136,7 @@ const main = async () => {
103
136
) ;
104
137
} else {
105
138
throw new Error (
106
- `Deposit to the child chain failed, EthDepositStatus is ${
139
+ `Deposit to the child chain failed, DepositStatus is ${
107
140
EthDepositStatus [ childChainDepositResult . message . status ]
108
141
} `,
109
142
) ;
@@ -147,7 +180,7 @@ const main = async () => {
147
180
{
148
181
from : contractAliasAddress ,
149
182
to : transferTo ,
150
- l2CallValue : ethers . utils . parseEther ( '0.01' ) , // because we deposited 0.01 ether, so we also transfer 0.01 ether out here.
183
+ l2CallValue : ethers . utils . parseUnits ( '0.01' , nativeTokenDecimals ) , // because we deposited 0.01 ether, so we also transfer 0.01 ether out here.
151
184
excessFeeRefundAddress : depositContract . address ,
152
185
callValueRefundAddress : depositContract . address ,
153
186
data : [ ] ,
@@ -175,7 +208,9 @@ const main = async () => {
175
208
* we need to subtract it here so the transaction in the parent chain doesn't pay l2callvalue
176
209
* and instead uses the alias balance on the child chain directly.
177
210
*/
178
- const depositAmount = parentToChildMessageGasParams . deposit . sub ( ethers . utils . parseEther ( '0.01' ) ) ;
211
+ const depositAmount = parentToChildMessageGasParams . deposit . sub (
212
+ ethers . utils . parseUnits ( '0.01' , nativeTokenDecimals ) ,
213
+ ) ;
179
214
180
215
console . log (
181
216
`Transfer funds txn needs ${ ethers . utils . formatEther (
@@ -186,16 +221,31 @@ const main = async () => {
186
221
/**
187
222
* Call the contract's method to transfer the funds from the alias to the address you set
188
223
*/
189
- const setTransferTx = await depositContract . moveFundsFromChildChainAliasToAnotherAddress (
190
- transferTo ,
191
- ethers . utils . parseEther ( '0.01' ) , // because we deposited 0.01 ether, so we also transfer 0.01 ether out here.
192
- parentToChildMessageGasParams . maxSubmissionCost ,
193
- parentToChildMessageGasParams . gasLimit ,
194
- gasPriceBid ,
195
- {
196
- value : depositAmount ,
197
- } ,
198
- ) ;
224
+ let setTransferTx ;
225
+ if ( isCustomGasTokenChain ) {
226
+ // We don't need to give allowance to the contract now since we already gave plenty in the
227
+ // previous step
228
+
229
+ setTransferTx = await depositContract . moveFundsFromChildChainAliasToAnotherAddress (
230
+ transferTo ,
231
+ ethers . utils . parseUnits ( '0.01' , nativeTokenDecimals ) , // because we deposited 0.01 ether, so we also transfer 0.01 ether out here.
232
+ parentToChildMessageGasParams . maxSubmissionCost ,
233
+ parentToChildMessageGasParams . gasLimit ,
234
+ gasPriceBid ,
235
+ depositAmount ,
236
+ ) ;
237
+ } else {
238
+ setTransferTx = await depositContract . moveFundsFromChildChainAliasToAnotherAddress (
239
+ transferTo ,
240
+ ethers . utils . parseEther ( '0.01' ) , // because we deposited 0.01 ether, so we also transfer 0.01 ether out here.
241
+ parentToChildMessageGasParams . maxSubmissionCost ,
242
+ parentToChildMessageGasParams . gasLimit ,
243
+ gasPriceBid ,
244
+ {
245
+ value : depositAmount ,
246
+ } ,
247
+ ) ;
248
+ }
199
249
const setTransferRec = await setTransferTx . wait ( ) ;
200
250
201
251
console . log (
0 commit comments