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: Native erc20 contract fixes #68

Merged
merged 25 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
47 changes: 20 additions & 27 deletions core/tests/ts-integration/src/context-owner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,10 @@ export class TestContextOwner {
async setupContext(): Promise<TestContext> {
try {
if (this.env.nativeErc20Testing) {
this.reporter.message('Using native ERC20 implementation');
this.reporter.startAction('Setting up the context for NATIVE TOKEN IMPLEMENTATION');
} else {
this.reporter.startAction('Setting up the context');
}
this.reporter.startAction('Setting up the context');
await this.cancelPendingTxs();
this.wallets = await this.prepareWallets();
this.reporter.finishAction();
Expand Down Expand Up @@ -241,25 +242,23 @@ 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
const depositHandle = await 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);
this.reporter.debug(`Sent ETH deposit. Nonce ${tx.nonce}, amount: ${amount}, hash: ${tx.hash}`);
tx.wait();
});

// Add this promise to the list of L1 tx promises.
l1TxPromises.push(depositHandle);
}

// Define values for handling ERC20 transfers/deposits.
Expand Down Expand Up @@ -341,23 +340,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
17 changes: 16 additions & 1 deletion core/tests/ts-integration/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export async function waitForServer() {
*/
export async function loadTestEnvironment(): Promise<TestEnvironment> {
const network = process.env.CHAIN_ETH_NETWORK || 'localhost';
const nativeErc20Testing = process.env.CONTRACTS_L1_NATIVE_ERC20_TOKEN_ADDR ? true : false; // if set, we assume user wants to test native erc20 tokens
// const nativeErc20Testing = process.env.CONTRACTS_L1_NATIVE_ERC20_TOKEN_ADDR ? true : false; // if set, we assume user wants to test native erc20 tokens
const nativeErc20Testing = true; // if set, we assume user wants to test native erc20 tokens

let mainWalletPK;
if (nativeErc20Testing) {
Expand Down Expand Up @@ -103,6 +104,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 +132,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
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* 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 l2TokenAddress = await (
await alice.getL1BridgeContracts()
).erc20['l2TokenAddress(address)'](tokenAddress);
const initiall2BalanceThroughL1Bridge = await alice.getBalance(l2TokenAddress);

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);

/// Try through alice.l2TokenAddress
const aliceL2TokenAddress = await alice.l2TokenAddress(tokenAddress);
const aliceBalanceThroughAliceL2TokenAddress = await alice.getBalance(aliceL2TokenAddress);

/// Try through l1ERC20Bridge.l2TokenAddress call
const l2BalanceThroughL1Bridge = await alice.getBalance(l2TokenAddress);

expect(initialTokenBalance.sub(finalTokenBalance)).toEqual(BigNumber.from(amount));
expect(l2BalanceThroughL1Bridge.sub(initiall2BalanceThroughL1Bridge)).toEqual(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
31 changes: 25 additions & 6 deletions infrastructure/zk/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,25 @@ export async function initializeGovernance(args: any[] = []) {
await utils.spawn(`${baseCommandL1} initialize-governance ${args.join(' ')} | tee initializeGovernance.log`);
}

export async function initializeWethToken(args: any[] = []) {
export async function initializeWethToken(args: any[] = [], nativeToken?: boolean) {
await utils.confirmAction();

const isLocalSetup = process.env.ZKSYNC_LOCAL_SETUP;
const baseCommandL1 = isLocalSetup ? `yarn --cwd /contracts/l1-contracts` : `yarn l1-contracts`;

await utils.spawn(
`${baseCommandL1} initialize-l2-weth-token instant-call ${args.join(' ')} | tee initializeWeth.log`
`${baseCommandL1} initialize-l2-weth-token ${nativeToken ? ' --native-erc20' : ''} instant-call ${args.join(
' '
)} | tee initializeWeth.log`
);
}

export async function deployL2(args: any[] = [], includePaymaster?: boolean, includeWETH?: boolean) {
export async function deployL2(
args: any[] = [],
includePaymaster?: boolean,
includeWETH?: boolean,
nativeToken?: boolean
) {
await utils.confirmAction();

const isLocalSetup = process.env.ZKSYNC_LOCAL_SETUP;
Expand All @@ -75,10 +82,18 @@ export async function deployL2(args: any[] = [], includePaymaster?: boolean, inc
// Skip compilation for local setup, since we already copied artifacts into the container.
await utils.spawn(`${baseCommandL2} build`);

await utils.spawn(`${baseCommandL1} initialize-bridges ${args.join(' ')} | tee deployL2.log`);
await utils.spawn(
`${baseCommandL1} initialize-bridges ${nativeToken ? ' --native-erc20' : ''} ${args.join(
' '
)} | tee deployL2.log`
);

if (includePaymaster) {
await utils.spawn(`${baseCommandL2} deploy-testnet-paymaster ${args.join(' ')} | tee -a deployL2.log`);
await utils.spawn(
`${baseCommandL2} deploy-testnet-paymaster ${nativeToken ? ' --native-erc20' : ''} ${args.join(
' '
)} | tee -a deployL2.log`
);
}

if (includeWETH) {
Expand All @@ -98,7 +113,11 @@ export async function deployL2(args: any[] = [], includePaymaster?: boolean, inc
updateContractsEnv(l2DeployLog, l2DeploymentEnvVars);

if (includeWETH) {
await utils.spawn(`${baseCommandL1} initialize-weth-bridges ${args.join(' ')} | tee -a deployL1.log`);
await utils.spawn(
`${baseCommandL1} initialize-weth-bridges ${nativeToken ? ' --native-erc20' : ''} ${args.join(
' '
)} | tee -a deployL1.log`
);
}

const l1DeployLog = fs.readFileSync('deployL1.log').toString();
Expand Down
14 changes: 12 additions & 2 deletions infrastructure/zk/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) {
nativeERC20
} = initArgs;

if (nativeERC20) {
process.env.NATIVE_ERC20 = 'true';
} else {
process.env.NATIVE_ERC20 = 'false';
}

if (!process.env.CI && !skipEnvSetup) {
await announced('Pulling images', docker.pull());
await announced('Checking environment', checkEnv());
Expand Down Expand Up @@ -71,12 +77,16 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) {
contract.deployL2(
deployerL2ContractInput.args,
deployerL2ContractInput.includePaymaster,
deployerL2ContractInput.includeL2WETH
deployerL2ContractInput.includeL2WETH,
nativeERC20
)
);

if (deployerL2ContractInput.includeL2WETH) {
await announced('Initializing L2 WETH token', contract.initializeWethToken(governorPrivateKeyArgs));
await announced(
'Initializing L2 WETH token',
contract.initializeWethToken(governorPrivateKeyArgs, nativeERC20)
);
}
await announced('Initializing governance', contract.initializeGovernance(governorPrivateKeyArgs));
}
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
Loading
Loading