Skip to content
This repository has been archived by the owner on Jul 3, 2024. It is now read-only.

Commit

Permalink
test: add integration test for ApprovalBased paymaster
Browse files Browse the repository at this point in the history
  • Loading branch information
danijelTxFusion authored and danijelTxFusion committed Oct 20, 2023
1 parent a89208c commit e1c5ce6
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 7 deletions.
11 changes: 7 additions & 4 deletions src/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import {
REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT,
scaleGasLimit,
undoL1ToL2Alias,
NONCE_HOLDER_ADDRESS
NONCE_HOLDER_ADDRESS,
} from "./utils";
import {
IERC20__factory,
IL1Bridge,
IL1Bridge__factory,
IL2Bridge,
IL2Bridge__factory, INonceHolder__factory,
IL2Bridge__factory,
INonceHolder__factory,
IZkSync,
IZkSync__factory,
} from "../typechain";
Expand Down Expand Up @@ -727,8 +728,10 @@ export function AdapterL2<TBase extends Constructor<TxSender>>(Base: TBase) {
}

async getDeploymentNonce(): Promise<bigint> {
return await INonceHolder__factory.connect(NONCE_HOLDER_ADDRESS, this._signerL2())
.getDeploymentNonce(await this.getAddress());
return await INonceHolder__factory.connect(
NONCE_HOLDER_ADDRESS,
this._signerL2(),
).getDeploymentNonce(await this.getAddress());
}

async getL2BridgeContracts(): Promise<{ erc20: IL2Bridge }> {
Expand Down
2 changes: 1 addition & 1 deletion src/paymaster-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BytesLike, ethers } from "ethers";
import {PAYMASTER_FLOW_ABI} from "./utils";
import { PAYMASTER_FLOW_ABI } from "./utils";

import {
Address,
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as chai from "chai";
import "../custom-matchers";
import { Provider, types, utils, Wallet, ContractFactory } from "../../src";
import { Provider, types, Wallet, ContractFactory } from "../../src";
import { ethers } from "ethers";
import { TOKENS } from "../const.test";

const { expect } = chai;

describe("Wallet", () => {
describe("ContractFactory", () => {
const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";

const provider = Provider.getDefaultProvider(types.Network.Localhost);
Expand Down
101 changes: 101 additions & 0 deletions tests/integration/paymaster.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import * as chai from "chai";
import "../custom-matchers";
import { Provider, types, utils, Wallet, ContractFactory } from "../../src";
import { Contract, ethers, Typed } from "ethers";

const { expect } = chai;

describe("Paymaster", () => {
const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";

const provider = Provider.getDefaultProvider(types.Network.Localhost);
const wallet = new Wallet(PRIVATE_KEY, provider);

const tokenPath = "../files/Token.json";
const paymasterPath = "../files/Paymaster.json";

describe("#ApprovalBased", () => {
it("use ERC20 token to pay transaction fee", async () => {
const INIT_MINT_AMOUNT = 10;
const MINT_AMOUNT = 3;
const MINIMAL_ALLOWANCE = 1;

const abi = require(tokenPath).abi;
const bytecode: string = require(tokenPath).bytecode;
const factory = new ContractFactory(abi, bytecode, wallet);
const tokenContract = await factory.deploy("Ducat", "Ducat", 18);
const tokenAddress = await tokenContract.getAddress();
const token = new Contract(tokenAddress, abi, wallet);

// mint tokens to wallet, so it could pay fee with tokens
await token.mint(Typed.address(await wallet.getAddress()), Typed.uint256(INIT_MINT_AMOUNT));

const paymasterAbi = require(paymasterPath).abi;
const paymasterBytecode = require(paymasterPath).bytecode;
const accountFactory = new ContractFactory(
paymasterAbi,
paymasterBytecode,
wallet,
"createAccount",
);
const paymasterContract = await accountFactory.deploy(tokenAddress);
const paymasterAddress = await paymasterContract.getAddress();

// transfer ETH to paymaster so it could pay fee
const faucetTx = await wallet.transfer({
token: utils.ETH_ADDRESS,
to: paymasterAddress,
amount: ethers.parseEther("0.01"),
});
await faucetTx.wait();

const paymasterBalanceBeforeTx = await provider.getBalance(paymasterAddress);
const paymasterTokenBalanceBeforeTx = await provider.getBalance(
paymasterAddress,
"latest",
tokenAddress,
);
const walletBalanceBeforeTx = await wallet.getBalance();
const walletTokenBalanceBeforeTx = await wallet.getBalance(tokenAddress);

// perform tx using paymaster
const tokenAbi = new ethers.Interface(require(tokenPath).abi);
const tx = await wallet.sendTransaction({
to: tokenAddress,
data: tokenAbi.encodeFunctionData("mint", [await wallet.getAddress(), MINT_AMOUNT]),
customData: {
gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
paymasterParams: utils.getPaymasterParams(paymasterAddress, {
type: "ApprovalBased",
token: tokenAddress,
minimalAllowance: MINIMAL_ALLOWANCE,
innerInput: new Uint8Array(),
}),
},
});
await tx.wait();

const paymasterBalanceAfterTx = await provider.getBalance(paymasterAddress);
const paymasterTokenBalanceAfterTx = await provider.getBalance(
paymasterAddress,
"latest",
tokenAddress,
);
const walletBalanceAfterTx = await wallet.getBalance();
const walletTokenBalanceAfterTx = await wallet.getBalance(tokenAddress);

expect(paymasterTokenBalanceBeforeTx == BigInt(0)).to.be.true;
expect(walletTokenBalanceBeforeTx == BigInt(INIT_MINT_AMOUNT)).to.be.true;

expect(paymasterBalanceBeforeTx - paymasterBalanceAfterTx >= BigInt(0)).to.be.true;
expect(paymasterTokenBalanceAfterTx === BigInt(MINT_AMOUNT) - BigInt(MINIMAL_ALLOWANCE)).to
.be.true;

expect(walletBalanceBeforeTx - walletBalanceAfterTx >= BigInt(0)).to.be.true;
expect(
walletTokenBalanceAfterTx ==
walletTokenBalanceBeforeTx - BigInt(MINIMAL_ALLOWANCE) + BigInt(MINT_AMOUNT),
).to.be.true;
}).timeout(20_000);
});
});

0 comments on commit e1c5ce6

Please sign in to comment.