-
Notifications
You must be signed in to change notification settings - Fork 292
/
Copy pathexec.js
179 lines (159 loc) · 6.83 KB
/
exec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
const { ethers } = require('hardhat');
const { BigNumber, providers, Wallet } = require('ethers');
const { getArbitrumNetwork, ParentToChildMessageStatus, Erc20Bridger } = require('@arbitrum/sdk');
const {
arbLog,
requireEnvVariables,
addCustomNetworkFromFile,
} = require('arb-shared-dependencies');
const { expect } = require('chai');
require('dotenv').config();
requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']);
/**
* Set up: instantiate wallets connected to providers
*/
const walletPrivateKey = process.env.PRIVATE_KEY;
const parentChainProvider = new providers.JsonRpcProvider(process.env.PARENT_CHAIN_RPC);
const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC);
const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider);
const childChainWallet = new Wallet(walletPrivateKey, childChainProvider);
/**
* Set the amount of token to be transferred to the child chain
*/
const tokenAmount = BigNumber.from(50);
const main = async () => {
await arbLog('Deposit token using Arbitrum SDK');
/**
* Add the custom network configuration to the SDK if present
*/
addCustomNetworkFromFile();
/**
* For the purpose of our tests, here we deploy an standard ERC-20 token (DappToken) to the parent chain
* It sends its deployer (us) the initial supply of 1000
*/
console.log('Deploying the test DappToken to the parent chain:');
const DappToken = (await ethers.getContractFactory('DappToken')).connect(parentChainWallet);
const dappToken = await DappToken.deploy(1000);
await dappToken.deployed();
console.log(`DappToken is deployed to the parent chain at ${dappToken.address}`);
/**
* Use childChainNetwork to create an Arbitrum SDK Erc20Bridger instance
* We'll use Erc20Bridger for its convenience methods around transferring token to the child chain
*/
const childChainNetwork = await getArbitrumNetwork(childChainProvider);
const erc20Bridger = new Erc20Bridger(childChainNetwork);
/**
* We get the address of the parent-chain gateway for our DappToken,
* which will later help us get the initial token balance of the bridge (before deposit)
*/
const tokenAddress = dappToken.address;
const expectedGatewayAddress = await erc20Bridger.getParentGatewayAddress(
tokenAddress,
parentChainProvider,
);
const initialBridgeTokenBalance = await dappToken.balanceOf(expectedGatewayAddress);
/**
* Because the token might have decimals, we update the amount to deposit taking into account those decimals
*/
const tokenDecimals = await dappToken.decimals();
const tokenDepositAmount = tokenAmount.mul(BigNumber.from(10).pow(tokenDecimals));
/**
* The StandardGateway contract will ultimately be making the token transfer call; thus, that's the contract we need to approve.
* erc20Bridger.approveToken handles this approval
* Arguments required are:
* (1) parentSigner: address of the account on the parent chain transferring tokens to the child chain
* (2) erc20ParentAddress: address on the parent chain of the ERC-20 token to be depositted to the child chain
*/
console.log('Approving:');
const approveTransaction = await erc20Bridger.approveToken({
parentSigner: parentChainWallet,
erc20ParentAddress: tokenAddress,
});
const approveTransactionReceipt = await approveTransaction.wait();
console.log(
`You successfully allowed the Arbitrum Bridge to spend DappToken ${approveTransactionReceipt.transactionHash}`,
);
/**
* The next function initiates the deposit of DappToken to the child chain using erc20Bridger.
* This will escrow funds in the gateway contract on the parent chain, and send a message to mint tokens on the child chain.
*
* The erc20Bridge.deposit method handles computing the necessary fees for automatic-execution of retryable tickets — maxSubmission cost and (gas price * gas)
* and will automatically forward the fees to the child chain as callvalue.
*
* Also note that since this is the first DappToken deposit onto the child chain, a standard Arb ERC-20 contract will automatically be deployed.
* Arguments required are:
* (1) amount: The amount of tokens to be transferred to the child chain
* (2) erc20ParentAddress: address on the parent chain of the ERC-20 token to be depositted to the child chain
* (3) parentSigner: address of the account on the parent chain transferring tokens to the child chain
* (4) childProvider: A provider for the child chain
*/
console.log('Transferring DappToken to the child chain:');
const depositTransaction = await erc20Bridger.deposit({
amount: tokenDepositAmount,
erc20ParentAddress: tokenAddress,
parentSigner: parentChainWallet,
childProvider: childChainProvider,
});
/**
* Now we wait for both the parent-chain and child-chain sides of transactions to be confirmed
*/
console.log(
`Deposit initiated: waiting for execution of the retryable ticket on the child chain (takes 10-15 minutes; current time: ${new Date().toTimeString()}) `,
);
const depositTransactionReceipt = await depositTransaction.wait();
const childTransactionReceipt = await depositTransactionReceipt.waitForChildTransactionReceipt(
childChainProvider,
);
/**
* The `complete` boolean tells us if the parent-to-child message was successful
*/
if (childTransactionReceipt.complete) {
console.log(
`Message was successfully executed on the child chain: status: ${
ParentToChildMessageStatus[childTransactionReceipt.status]
}`,
);
} else {
throw new Error(
`Message failed to be executed on the child chain: status ${
ParentToChildMessageStatus[childTransactionReceipt.status]
}`,
);
}
/**
* Get the Bridge token balance
*/
const finalBridgeTokenBalance = await dappToken.balanceOf(expectedGatewayAddress);
/**
* Check if Bridge balance has been updated correctly
*/
expect(
initialBridgeTokenBalance.add(tokenDepositAmount).eq(finalBridgeTokenBalance),
'Bridge balance was not updated after the token deposit transaction',
).to.be.true;
/**
* Check if our balance of DappToken on the child chain has been updated correctly
* To do so, we use erc20Bridge to get the token address and contract on the child chain
*/
const childChainTokenAddress = await erc20Bridger.getChildErc20Address(
tokenAddress,
parentChainProvider,
);
const childChainToken = erc20Bridger.getChildTokenContract(
childChainProvider,
childChainTokenAddress,
);
const testWalletBalanceOnChildChain = (
await childChainToken.functions.balanceOf(childChainWallet.address)
)[0];
expect(
testWalletBalanceOnChildChain.eq(tokenDepositAmount),
'wallet balance on the child chain was not updated after deposit',
).to.be.true;
};
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});