Skip to content

Commit

Permalink
Batch subsidy integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
StanislavBreadless committed Dec 3, 2021
1 parent 314092f commit 8f2d96a
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 14 deletions.
13 changes: 10 additions & 3 deletions core/tests/ts-tests/tests/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,18 @@ describe(`ZkSync integration tests (token: ${token}, transport: ${transport}, pr
return;
}

const wallet = await tester.create2Wallet();
await tester.testTransfer(alice, wallet, token, TX_AMOUNT);
const wallet1 = await tester.create2Wallet();
await tester.testTransfer(alice, wallet1, token, TX_AMOUNT);

await tester.testSubsidyForCREATE2ChangePubKey(
wallet,
wallet1,
token
);

const wallet2 = await tester.create2Wallet();
await tester.testTransfer(alice, wallet2, token, TX_AMOUNT);
await tester.testSubsidyForBatch(
wallet2,
token
);
});
Expand Down
126 changes: 115 additions & 11 deletions core/tests/ts-tests/tests/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import {
numberToBytesBE
} from 'zksync/build/utils';
import { HTTPTransport } from 'zksync/build/transport';
import { assert } from 'console';
import exp from 'constants';

type TokenLike = types.TokenLike;

Expand All @@ -41,6 +39,7 @@ declare module './tester' {
): Promise<void>;
testBackwardCompatibleEthMessages(from: Wallet, to: Wallet, token: TokenLike, amount: BigNumber): Promise<void>;
testSubsidyForCREATE2ChangePubKey(create2Wallet: Wallet, token: TokenLike): Promise<void>;
testSubsidyForBatch(create2Wallet: Wallet, token: TokenLike): Promise<void>;
}
}

Expand Down Expand Up @@ -286,19 +285,26 @@ Tester.prototype.testBackwardCompatibleEthMessages = async function (
this.runningFee = this.runningFee.add(totalFee);
};

Tester.prototype.testSubsidyForCREATE2ChangePubKey = async function (create2Wallet: Wallet, token: TokenLike) {
// Unfortunately due to different rounds and precision lost
// the price might differ from the expected one
const ACCEPTED_SCALED_DIFFERENCE = 10; // 10^-5 USD

// This function is needed to emulate the CF-Connecting-IP header being set by the
// Cloudflare Proxy. In production, this header is set by Cloudflare Proxy and can not be manually
// set by the client.
const subsidyAxiosConfig = () => {
const subsidizedIps = process.env.FEE_TICKER_SUBSIDIZED_IPS?.split(',')!;
const subsidizedCpkPriceScaled = BigNumber.from(process.env.FEE_TICKER_SUBSIDY_CPK_PRICE_USD_SCALED)!;

const config = {
headers: {
'CF-Connecting-IP': subsidizedIps[0]
}
};
return config;
}

Tester.prototype.testSubsidyForCREATE2ChangePubKey = async function (create2Wallet: Wallet, token: TokenLike) {
// Unfortunately due to different rounds and precision lost
// the price might differ from the expected one
const ACCEPTED_SCALED_DIFFERENCE = 10; // 10^-5 USD

const subsidizedCpkPriceScaled = BigNumber.from(process.env.FEE_TICKER_SUBSIDY_CPK_PRICE_USD_SCALED)!;

const transport = new HTTPTransport('http://127.0.0.1:3030');
const weiInEth = BigNumber.from(10).pow(18);
Expand All @@ -314,7 +320,7 @@ Tester.prototype.testSubsidyForCREATE2ChangePubKey = async function (create2Wall
ethers.constants.AddressZero,
token
],
config
subsidyAxiosConfig()
);
const totalFee = BigNumber.from(transactionFee.totalFee);
const totalFeeUSDScaled = totalFee.mul(scaledTokenPrice).div(weiInEth);
Expand Down Expand Up @@ -343,7 +349,7 @@ Tester.prototype.testSubsidyForCREATE2ChangePubKey = async function (create2Wall
const create2data = (create2Wallet.ethSigner as Create2WalletSigner).create2WalletData;
const cpkTx = await create2Wallet.getChangePubKey({
feeToken: token,
fee: BigNumber.from(transactionFee.totalFee),
fee: totalFee,
nonce: 0,
validFrom: 0,
validUntil: MAX_TIMESTAMP,
Expand All @@ -360,7 +366,105 @@ Tester.prototype.testSubsidyForCREATE2ChangePubKey = async function (create2Wall
}
expect(failed).to.be.true;

await transport.request('tx_submit', [cpkTx, null], config);
// The transaction is submitted successfully
await transport.request('tx_submit', [cpkTx, null], subsidyAxiosConfig());
};

Tester.prototype.testSubsidyForBatch = async function (create2Wallet: Wallet, token: TokenLike) {
// Unfortunately due to different rounds and precision lost
// the price might differ from the expected one
const ACCEPTED_SCALED_DIFFERENCE = 10; // 10^-5 USD

const subsidizedCpkPriceScaled = BigNumber.from(process.env.FEE_TICKER_SUBSIDY_CPK_PRICE_USD_SCALED)!;

const transport = new HTTPTransport('http://127.0.0.1:3030');
const weiInEth = BigNumber.from(10).pow(18);
const scaledTokenPrice = BigNumber.from(Math.round(1000000 * (await this.syncProvider.getTokenPrice(token))));

// Check that the subsidized fee is returned when requested with appropriate headers

const transferFee = (await this.syncProvider.getTransactionFee('Transfer', create2Wallet.address(), token)).totalFee;
const transferFeeUsdScaled = transferFee.mul(scaledTokenPrice).div(weiInEth);

const subsidyFee = await transport.request(
'get_txs_batch_fee_in_wei',
[
[
{
ChangePubKey: 'CREATE2'
},
'Transfer'
],
[
create2Wallet.address(),
create2Wallet.address(),
],
token,
],
subsidyAxiosConfig()
);
const totalFee = BigNumber.from(subsidyFee.totalFee);
const totalFeeUSDScaled = totalFee.mul(scaledTokenPrice).div(weiInEth);
expect(totalFeeUSDScaled.sub(subsidizedCpkPriceScaled).sub(transferFeeUsdScaled).abs().lte(ACCEPTED_SCALED_DIFFERENCE)).to.be.true;

// However, without the necessary headers, the API should return the normal fee
const normalFee = await transport.request('get_txs_batch_fee_in_wei', [
[
{
ChangePubKey: 'CREATE2'
},
'Transfer'
],
[
create2Wallet.address(),
create2Wallet.address(),
],
token,
]);
const normalTotalFee = BigNumber.from(normalFee.totalFee);
const normalTotalFeeUSDScaled = normalTotalFee.mul(scaledTokenPrice).div(weiInEth);

// The difference is huge (at least 5x times tolerated difference)
expect(
normalTotalFeeUSDScaled
.sub(subsidizedCpkPriceScaled)
.abs()
.gte(5 * ACCEPTED_SCALED_DIFFERENCE)
).to.be.true;

// Now we submit the CREATE2 ChangePubKey
const create2data = (create2Wallet.ethSigner as Create2WalletSigner).create2WalletData;
const cpkTx = await create2Wallet.getChangePubKey({
feeToken: token,
fee: BigNumber.from(0),
nonce: 0,
validFrom: 0,
validUntil: MAX_TIMESTAMP,
ethAuthData: {
type: 'CREATE2',
...create2data
}
});
const transferTx = await create2Wallet.getTransfer({
token,
fee: totalFee,
nonce: 0,
validFrom: 0,
validUntil: MAX_TIMESTAMP,
amount: BigNumber.from('1'),
to: create2Wallet.address(),
});
const txs = [{ tx: cpkTx }, { tx: transferTx }];

let failed = false;
try {
await transport.request('submit_txs_batch', [txs, []]);
} catch (e) {
failed = true;
}
expect(failed).to.be.true;

await transport.request('submit_txs_batch', [txs, []], subsidyAxiosConfig());
};

export function serializeOldTransfer(transfer: Transfer): Uint8Array {
Expand Down

0 comments on commit 8f2d96a

Please sign in to comment.