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

test: Non native tokens integration test #76

Closed
2 changes: 1 addition & 1 deletion contracts
37 changes: 16 additions & 21 deletions core/tests/ts-integration/src/context-owner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,17 @@ export class TestContextOwner {
const gasPrice = await scaledGasPrice(this.mainEthersWallet);

// Deposit L2 tokens (if needed). Depositing ETH with current native implementation is not supported.
if (!l2ETHAmountToDeposit.isZero() && !this.env.nativeErc20Testing) {
if (!l2ETHAmountToDeposit.isZero()) {
// Given that we've already sent a number of transactions,
// we have to correctly send nonce.
const depositHandle = this.mainSyncWallet
.deposit({
to: this.mainEthersWallet.address,
approveERC20: true,
token: this.env.erc20Token.l1Address,
token: zksync.utils.ETH_ADDRESS,
amount: l2ETHAmountToDeposit,
refundRecipient: this.mainEthersWallet.address
overrides: {
nonce: nonce++,
gasPrice
}
})
.then((tx) => {
const amount = ethers.utils.formatEther(l2ETHAmountToDeposit);
Expand Down Expand Up @@ -341,23 +342,17 @@ export class TestContextOwner {
this.reporter.startAction(`Distributing tokens on L2`);
let l2startNonce = await this.mainSyncWallet.getTransactionCount();

// All the promises we send in this function.
const l2TxPromises: Promise<any>[] = [];

// ETH transfers.
if (!this.env.nativeErc20Testing) {
const ethPromises = await sendTransfers(
zksync.utils.ETH_ADDRESS,
this.mainSyncWallet,
wallets,
L2_ETH_PER_ACCOUNT,
l2startNonce,
undefined,
this.reporter
);
l2startNonce += l2TxPromises.length;
l2TxPromises.push(...ethPromises);
}
const l2TxPromises = await sendTransfers(
zksync.utils.ETH_ADDRESS,
this.mainSyncWallet,
wallets,
L2_ETH_PER_ACCOUNT,
l2startNonce,
undefined,
this.reporter
);
l2startNonce += l2TxPromises.length;

// ERC20 transfers.
const l2TokenAddress = await this.mainSyncWallet.l2TokenAddress(this.env.erc20Token.l1Address);
Expand Down
14 changes: 14 additions & 0 deletions core/tests/ts-integration/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ export async function loadTestEnvironment(): Promise<TestEnvironment> {
ethers.getDefaultProvider(l1NodeUrl)
).l2TokenAddress(weth.address);

const nonNativeToken = tokens.find((token: { symbol: string }) => token.symbol == 'MLTT')!;
const nonNativeTokenL2Address = await new zksync.Wallet(
mainWalletPK,
new zksync.Provider(l2NodeUrl),
ethers.getDefaultProvider(l1NodeUrl)
).l2TokenAddress(nonNativeToken.address);

return {
network,
mainWalletPK,
Expand All @@ -124,6 +131,13 @@ export async function loadTestEnvironment(): Promise<TestEnvironment> {
l1Address: weth.address,
l2Address: l2WethAddress
},
nonNativeToken: {
name: nonNativeToken.name,
symbol: nonNativeToken.symbol,
decimals: nonNativeToken.decimals,
l1Address: nonNativeToken.address,
l2Address: nonNativeTokenL2Address
},
nativeErc20Testing
};
}
Expand Down
4 changes: 4 additions & 0 deletions core/tests/ts-integration/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export interface TestEnvironment {
* Flag indicating whether the tests are being run against the native ERC20 implementation.
*/
nativeErc20Testing: boolean;
/**
* Non native ERC20 token.
*/
nonNativeToken: Token;
}

/**
Expand Down
124 changes: 124 additions & 0 deletions core/tests/ts-integration/tests/non-native-erc20-deposit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* This suite contains tests checking default ERC-20 contract behavior.
*/

import { TestMaster } from '../src/index';
import { Token } from '../src/types';
import { shouldChangeTokenBalances, shouldOnlyTakeFee } from '../src/modifiers/balance-checker';

import * as zksync from 'zksync-web3';
import { BigNumber, utils as etherUtils } from 'ethers';
import * as ethers from 'ethers';
import { scaledGasPrice, waitUntilBlockFinalized } from '../src/helpers';
import { L2_ETH_PER_ACCOUNT } from '../src/context-owner';

describe('ERC20 contract checks', () => {
let testMaster: TestMaster;
let alice: zksync.Wallet;
let bob: zksync.Wallet;
let tokenDetails: Token;
let nonNativeToken: Token;
let aliceErc20: zksync.Contract;

beforeAll(async () => {
testMaster = TestMaster.getInstance(__filename);
alice = testMaster.mainAccount();
bob = testMaster.newEmptyAccount();

tokenDetails = testMaster.environment().erc20Token;
nonNativeToken = testMaster.environment().nonNativeToken;
aliceErc20 = new zksync.Contract(tokenDetails.l2Address, zksync.utils.IERC20, alice);
});

test('Can perform a deposit', async () => {
const tokenAddress = nonNativeToken.l1Address;
// const tokenAddress = tokenDetails.l1Address;
const amount = BigNumber.from(555);
const gasPrice = scaledGasPrice(alice);
const nativeToken = '0xD47a77a7A93c099a451a2c269ea5fB35238dC52c'

// The non native token address should be different than the native token address.
expect(tokenAddress != tokenDetails.l1Address);

// L1 Deposit
const initialTokenBalance = await alice.getBalanceL1(tokenAddress);
const deposit = await alice.deposit({
token: tokenAddress,
amount,
to: alice.address,
approveERC20: true,
approveOverrides: {
gasPrice
},
overrides: {
gasPrice
}
},
nativeToken);

await deposit.waitFinalize();

const finalTokenBalance = await alice.getBalanceL1(tokenAddress);
console.log('initialTokenBalance', initialTokenBalance.toString());
console.log('finalTokenBalance', finalTokenBalance.toString());

// L2 Deposit Finalize
const l2ERC20Bridge = (await alice.getL2BridgeContracts()).erc20;
const finalizeDeposit = await l2ERC20Bridge['finalizeDeposit(address,address,address,uint256,bytes)'](
alice.address,
alice.address,
tokenAddress,
amount,
'0x'
);

const finalizeDepositWait = await finalizeDeposit.wait();
console.log('finalizeDepositWait', finalizeDepositWait);

// Token amount should be deposited to the account in the L2 side.
console.log('l2BridgeAddress', l2ERC20Bridge.address);

/// Try through alice.l2TokenAddress
const aliceL2TokenAddress = await alice.l2TokenAddress(tokenAddress);
console.log('[ADDRESS] aliceL2TokenAddress', aliceL2TokenAddress);
const aliceBalanceThroughAliceL2TokenAddress = await alice.getBalance(aliceL2TokenAddress);
console.log(
'[BALANCE] aliceBalanceThroughAliceL2TokenAddress',
aliceBalanceThroughAliceL2TokenAddress.toString()
);

/// Try through l2ERC20Bridge.l2TokenAddress call opt 1
// const l2TokenAddressL2Bridge = await (
// await alice.getL2BridgeContracts()
// ).erc20['l2TokenAddress(address)'](tokenAddress);
// const l2BalanceThroughL2Bridge = await alice.getBalance(l2TokenAddressL2Bridge);
// console.log('[ADDRESS] l2BalanceThroughL2Bridge with l1 address', l2BalanceThroughL2Bridge.toString());
// console.log('[BALANCE] l2BalanceThroughL2Bridge with l1 address', l2BalanceThroughL2Bridge.toString());

/// Try through l2ERC20Bridge.l2TokenAddress call opt 2
// // L2 balance with address trough l2 bridge address
// const l2TokenAddressWithL2Bridge = await l2ERC20Bridge.l2TokenAddress(tokenAddress, {});
// const l2BalanceThroughL2Bridge = await alice.getBalance(l2TokenAddressWithL2Bridge);
// console.log('[ADDRESS] l2TokenAddressWithL2Bridge: ', l2TokenAddressWithL2Bridge);
// console.log('[BALANCE] l2BalanceThroughL2Bridge with l2 bridge address', l2BalanceThroughL2Bridge.toString());

/// Try through l1ERC20Bridge.l2TokenAddress call
const l2TokenAddress = await (
await alice.getL1BridgeContracts()
).erc20['l2TokenAddress(address)'](tokenAddress);
const l2BalanceThroughL1Bridge = await alice.getBalance(l2TokenAddress);
console.log('[ADDRESS] l2BalanceThroughL1Bridge with l1 address', l2BalanceThroughL1Bridge.toString());
console.log('[BALANCE] l2BalanceThroughL1Bridge with l1 address', l2BalanceThroughL1Bridge.toString());

/// Try through same address than L1 call
const l2Balance = await alice.getBalance(tokenAddress);
console.log('[ADDRESS] l2Balance with l1 address', tokenAddress.toString());
console.log('[BALANCE] l2Balance with l1 address', l2Balance.toString());

expect(initialTokenBalance.sub(finalTokenBalance)).toEqual(BigNumber.from(amount));
});

afterAll(async () => {
await testMaster.deinitialize();
});
});
2 changes: 1 addition & 1 deletion infrastructure/local-setup-preparation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ async function depositWithRichAccounts() {
// deposit method from wallet requires a running server
contract.requestL2Transaction(
wallet.address,
0,
AMOUNT_TO_DEPOSIT,
overrides.value,
'0x',
DEPOSIT_L2_GAS_LIMIT,
utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT,
Expand Down
2 changes: 1 addition & 1 deletion sdk/zksync-rs/src/ethereum/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ impl<S: EthereumSigner> EthereumProvider<S> {
(
contract_address,
l2_value,
0,
value,
calldata,
gas_limit,
L1_TO_L2_GAS_PER_PUBDATA,
Expand Down