Skip to content

Commit

Permalink
add more unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rahul-kothari committed Sep 18, 2023
1 parent 80f3375 commit 8ff0425
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 21 deletions.
109 changes: 101 additions & 8 deletions yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Fr, FunctionSelector } from '@aztec/circuits.js';
import { EthAddress } from '@aztec/foundation/eth-address';
import { DebugLogger } from '@aztec/foundation/log';
import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types';
import { AztecRPC } from '@aztec/types';
import { AztecRPC, TxStatus } from '@aztec/types';

import { CrossChainTestHarness } from './fixtures/cross_chain_test_harness.js';
import { delay, hashPayload, setup } from './fixtures/utils.js';
Expand All @@ -15,7 +15,8 @@ describe('e2e_cross_chain_messaging', () => {
let aztecRpcServer: AztecRPC;
let logger: DebugLogger;

let wallet: AccountWallet;
let user1Wallet: AccountWallet;
let user2Wallet: AccountWallet;
let ethAccount: EthAddress;
let ownerAddress: AztecAddress;

Expand All @@ -30,7 +31,7 @@ describe('e2e_cross_chain_messaging', () => {
aztecRpcServer: aztecRpcServer_,
deployL1ContractsValues,
accounts,
wallet: wallet_,
wallets,
logger: logger_,
cheatCodes,
} = await setup(2);
Expand All @@ -39,7 +40,7 @@ describe('e2e_cross_chain_messaging', () => {
aztecRpcServer_,
deployL1ContractsValues,
accounts,
wallet_,
wallets[0],
logger_,
cheatCodes,
);
Expand All @@ -50,7 +51,8 @@ describe('e2e_cross_chain_messaging', () => {
ownerAddress = crossChainTestHarness.ownerAddress;
outbox = crossChainTestHarness.outbox;
aztecRpcServer = crossChainTestHarness.aztecRpcServer;
wallet = wallet_;
user1Wallet = wallets[0];
user2Wallet = wallets[1];
logger = logger_;
logger('Successfully deployed contracts and initialized portal');
}, 100_000);
Expand All @@ -63,7 +65,7 @@ describe('e2e_cross_chain_messaging', () => {
await crossChainTestHarness?.stop();
});

it('Milestone 2: Deposit funds from L1 -> L2 and withdraw back to L1', async () => {
it.skip('Milestone 2: Deposit funds from L1 -> L2 and withdraw back to L1', async () => {
// Generate a claim secret using pedersen
const l1TokenBalance = 1000000n;
const bridgeAmount = 100n;
Expand Down Expand Up @@ -117,7 +119,7 @@ describe('e2e_cross_chain_messaging', () => {
new Fr(withdrawAmount),
nonce,
]);
await wallet.createAuthWitness(burnMessageHash);
await user1Wallet.createAuthWitness(burnMessageHash);

// 5. Withdraw owner's funds from L2 to L1
const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount);
Expand All @@ -132,5 +134,96 @@ describe('e2e_cross_chain_messaging', () => {
expect(await outbox.read.contains([entryKey.toString(true)])).toBeFalsy();
}, 120_000);

// TODO: Failure cases!
// Unit tests for TokenBridge's private methods.
it('Someone else can mint funds to me on my behalf (privately)', async () => {
const l1TokenBalance = 1000000n;
const bridgeAmount = 100n;
const [secretForL2MessageConsumption, secretHashForL2MessageConsumption] =
await crossChainTestHarness.generateClaimSecret();
const [secretForRedeemingMintedNotes, secretHashForRedeemingMintedNotes] =
await crossChainTestHarness.generateClaimSecret();

await crossChainTestHarness.mintTokensOnL1(l1TokenBalance);
const messageKey = await crossChainTestHarness.sendTokensToPortalPrivate(
bridgeAmount,
secretHashForL2MessageConsumption,
secretHashForRedeemingMintedNotes,
);
expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount);

// Wait for the archiver to process the message
await delay(5000); /// waiting 5 seconds.

// Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens.
const unrelatedMintAmount = 99n;
await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount);

// 3. Consume L1-> L2 message and mint private tokens on L2

// Sending wrong secret hashes should fail:
await expect(
l2Bridge
.withWallet(user2Wallet)
.methods.claim_private(
bridgeAmount,
messageKey,
secretForL2MessageConsumption,
secretHashForL2MessageConsumption,
{
address: ethAccount.toField(),
},
)
.simulate(),
).rejects.toThrowError("Cannot satisfy constraint 'l1_to_l2_message_data.message.content == content");

// send the right one -
const consumptionTx = l2Bridge
.withWallet(user2Wallet)
.methods.claim_private(
bridgeAmount,
messageKey,
secretForL2MessageConsumption,
secretHashForRedeemingMintedNotes,
{
address: ethAccount.toField(),
},
)
.send();
const consumptionReceipt = await consumptionTx.wait();
expect(consumptionReceipt.status).toBe(TxStatus.MINED);

// Now user1 can claim the notes that user2 minted on their behalf.
await crossChainTestHarness.redeemShieldPrivatelyOnL2(bridgeAmount, secretForRedeemingMintedNotes);
await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, bridgeAmount);
}, 50_000);

it("Bridge can't withdraw my funds if I don't give approval", async () => {
const mintAmountToUser1 = 100n;
await crossChainTestHarness.mintTokensPublicOnL2(mintAmountToUser1);

const withdrawAmount = 9n;
const nonce = Fr.random();
const expectedBurnMessageHash = await hashPayload([
l2Bridge.address.toField(),
l2Token.address.toField(),
FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(),
user1Wallet.getAddress().toField(),
new Fr(withdrawAmount),
nonce,
]);
// Should fail as owner has not given approval to bridge burn their funds.
await expect(
l2Bridge
.withWallet(user1Wallet)
.methods.exit_to_l1_private(
{ address: l2Token.address },
withdrawAmount,
{ address: ethAccount.toField() },
{ address: EthAddress.ZERO.toField() },
nonce,
)
.simulate(),
).rejects.toThrowError(`Unknown auth witness for message hash 0x${expectedBurnMessageHash.toString('hex')}`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Fr, FunctionSelector } from '@aztec/circuits.js';
import { EthAddress } from '@aztec/foundation/eth-address';
import { DebugLogger } from '@aztec/foundation/log';
import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types';
import { AztecRPC } from '@aztec/types';
import { AztecRPC, TxStatus } from '@aztec/types';

import { CrossChainTestHarness } from './fixtures/cross_chain_test_harness.js';
import { delay, hashPayload, setup } from './fixtures/utils.js';
Expand All @@ -15,8 +15,9 @@ describe('e2e_public_cross_chain_messaging', () => {
let aztecRpcServer: AztecRPC;
let logger: DebugLogger;

let wallet: AccountWallet;
let ethAccount: EthAddress;
let ownerWallet: AccountWallet;
let user2Wallet: AccountWallet;
let ownerEthAddress: EthAddress;
let ownerAddress: AztecAddress;

let crossChainTestHarness: CrossChainTestHarness;
Expand All @@ -30,7 +31,7 @@ describe('e2e_public_cross_chain_messaging', () => {
aztecRpcServer: aztecRpcServer_,
deployL1ContractsValues,
accounts,
wallet: wallet_,
wallets,
logger: logger_,
cheatCodes,
} = await setup(2);
Expand All @@ -39,19 +40,20 @@ describe('e2e_public_cross_chain_messaging', () => {
aztecRpcServer_,
deployL1ContractsValues,
accounts,
wallet_,
wallets[0],
logger_,
cheatCodes,
);

l2Token = crossChainTestHarness.l2Token;
l2Bridge = crossChainTestHarness.l2Bridge;
ethAccount = crossChainTestHarness.ethAccount;
ownerEthAddress = crossChainTestHarness.ethAccount;
ownerAddress = crossChainTestHarness.ownerAddress;
outbox = crossChainTestHarness.outbox;
aztecRpcServer = crossChainTestHarness.aztecRpcServer;
aztecNode = aztecNode_;
wallet = wallet_;
ownerWallet = wallets[0];
user2Wallet = wallets[1];

logger = logger_;
logger('Successfully deployed contracts and initialized portal');
Expand All @@ -77,7 +79,7 @@ describe('e2e_public_cross_chain_messaging', () => {

// 2. Deposit tokens to the TokenPortal
const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash);
expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount);
expect(await crossChainTestHarness.getL1BalanceOf(ownerEthAddress)).toBe(l1TokenBalance - bridgeAmount);

// Wait for the archiver to process the message
await delay(5000); /// waiting 5 seconds.
Expand Down Expand Up @@ -107,20 +109,86 @@ describe('e2e_public_cross_chain_messaging', () => {
new Fr(withdrawAmount),
nonce,
]);
await wallet.setPublicAuth(burnMessageHash, true).send().wait();
await ownerWallet.setPublicAuth(burnMessageHash, true).send().wait();

// 5. Withdraw owner's funds from L2 to L1
const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount);
await crossChainTestHarness.withdrawPublicFromAztecToL1(withdrawAmount, nonce);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, afterBalance - withdrawAmount);

// Check balance before and after exit.
expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount);
expect(await crossChainTestHarness.getL1BalanceOf(ownerEthAddress)).toBe(l1TokenBalance - bridgeAmount);
await crossChainTestHarness.withdrawFundsFromBridgeOnL1(withdrawAmount, entryKey);
expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount + withdrawAmount);
expect(await crossChainTestHarness.getL1BalanceOf(ownerEthAddress)).toBe(
l1TokenBalance - bridgeAmount + withdrawAmount,
);

expect(await outbox.read.contains([entryKey.toString(true)])).toBeFalsy();
}, 120_000);

// TODO: Failure cases!
// Unit tests for TokenBridge's public methods.

it('Someone else can mint funds to me on my behalf (publicly)', async () => {
// Generate a claim secret using pedersen
const l1TokenBalance = 1000000n;
const bridgeAmount = 100n;

const [secret, secretHash] = await crossChainTestHarness.generateClaimSecret();

await crossChainTestHarness.mintTokensOnL1(l1TokenBalance);
const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash);
expect(await crossChainTestHarness.getL1BalanceOf(ownerEthAddress)).toBe(l1TokenBalance - bridgeAmount);

// Wait for the archiver to process the message
await delay(5000); /// waiting 5 seconds.

// Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens.
const unrelatedMintAmount = 99n;
await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount);

// user2 tries to consume this message and minting to itself -> should fail since the message is intended to be consumed only by owner.
await expect(
l2Bridge
.withWallet(user2Wallet)
.methods.claim_public({ address: user2Wallet.getAddress() }, bridgeAmount, messageKey, secret, {
address: ownerEthAddress.toField(),
})
.simulate(),
).rejects.toThrow();

// user2 consumes owner's L1-> L2 message on bridge contract and mints public tokens on L2
logger("user2 consumes owner's message on L2 Publicly");
const tx = l2Bridge
.withWallet(user2Wallet)
.methods.claim_public({ address: ownerAddress }, bridgeAmount, messageKey, secret, {
address: ownerEthAddress.toField(),
})
.send();
const receipt = await tx.wait();
expect(receipt.status).toBe(TxStatus.MINED);
// ensure funds are gone to owner and not user2.
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount + unrelatedMintAmount);
await crossChainTestHarness.expectPublicBalanceOnL2(user2Wallet.getAddress(), 0n);
}, 60_000);

it("Bridge can't withdraw my funds if I don't give approval", async () => {
const mintAmountToOwner = 100n;
await crossChainTestHarness.mintTokensPublicOnL2(mintAmountToOwner);

const withdrawAmount = 9n;
const nonce = Fr.random();
// Should fail as owner has not given approval to bridge burn their funds.
await expect(
l2Bridge
.withWallet(ownerWallet)
.methods.exit_to_l1_public(
withdrawAmount,
{ address: ownerEthAddress.toField() },
{ address: EthAddress.ZERO.toField() },
nonce,
)
.simulate(),
).rejects.toThrowError('Assertion failed: Message not authorized by account');
});
});
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_sandbox_example.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,5 @@ describe('e2e_sandbox_example', () => {

expect(aliceBalance).toBe(initialSupply - transferQuantity);
expect(bobBalance).toBe(transferQuantity + mintQuantity);
}, 60_000);
}, 70_000);
});

0 comments on commit 8ff0425

Please sign in to comment.