Skip to content

Commit

Permalink
refactor: remove native token (#2280)
Browse files Browse the repository at this point in the history
Fixes #2277.
  • Loading branch information
LHerskind authored Sep 15, 2023
1 parent fe2f314 commit 4032d01
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 515 deletions.
4 changes: 2 additions & 2 deletions docs/docs/dev_docs/dapps/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ We can have private transactions that work fine locally, but are dropped by the

#### A public call fails locally

Public function calls can be caught failing locally similar to how we catch private function calls. For this example, we use a [`NativeTokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr) instead of a private one.
Public function calls can be caught failing locally similar to how we catch private function calls. For this example, we use a [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr) instead of a private one.

:::info
Keep in mind that public function calls behave as in EVM blockchains, in that they are executed by the sequencer and not locally. Local simulation helps alert the user of a potential failure, but the actual execution path of a public function call will depend on when it gets mined.
Expand Down Expand Up @@ -141,7 +141,7 @@ We can query the RPC server for all notes encrypted for a given user in a contra

#### Querying public state

[Public state](../../concepts/foundation/state_model.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`NativeTokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 4.
[Public state](../../concepts/foundation/state_model.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 6.

#include_code public-storage /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript

Expand Down
1 change: 0 additions & 1 deletion yarn-project/end-to-end/src/cli_docs_sandbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ EscrowContractAbi
ImportTestContractAbi
LendingContractAbi
MultiTransferContractAbi
NativeTokenContractAbi
NonNativeTokenContractAbi
ParentContractAbi
PendingCommitmentsContractAbi
Expand Down
140 changes: 91 additions & 49 deletions yarn-project/end-to-end/src/guides/dapp_testing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import {
CheatCodes,
Fr,
L2BlockL2Logs,
computeMessageSecretHash,
createAccount,
createAztecRpcClient,
getSandboxAccountsWallets,
waitForSandbox,
} from '@aztec/aztec.js';
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
import { NativeTokenContract, PrivateTokenContract, TestContract } from '@aztec/noir-contracts/types';
import { TestContract, TokenContract } from '@aztec/noir-contracts/types';

const { SANDBOX_URL = 'http://localhost:8080', ETHEREUM_HOST = 'http://localhost:8545' } = process.env;

describe('guides/dapp/testing', () => {
describe('on in-proc sandbox', () => {
Expand All @@ -20,86 +23,91 @@ describe('guides/dapp/testing', () => {
let stop: () => Promise<void>;
let owner: AccountWallet;
let recipient: AccountWallet;
let token: PrivateTokenContract;
let token: TokenContract;

beforeAll(async () => {
// docs:start:in-proc-sandbox
({ rpcServer: rpc, stop } = await createSandbox());
// docs:end:in-proc-sandbox
owner = await createAccount(rpc);
recipient = await createAccount(rpc);
token = await PrivateTokenContract.deploy(owner, 100n, owner.getAddress()).send().deployed();
token = await TokenContract.deploy(owner).send().deployed();
await token.methods._initialize({ address: owner.getAddress() }).send().wait();
}, 60_000);

// docs:start:stop-in-proc-sandbox
afterAll(() => stop());
// docs:end:stop-in-proc-sandbox

it('increases recipient funds on transfer', async () => {
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(0n);
await token.methods.transfer(20n, recipient.getAddress()).send().wait();
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(20n);
it('increases recipient funds on mint', async () => {
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(0n);
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
await token.methods.mint_private(20n, secretHash).send().wait();
await token.methods.redeem_shield({ address: recipient.getAddress() }, 20n, secret).send().wait();
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(20n);
});
});
});

describe('on local sandbox', () => {
beforeAll(async () => {
const { SANDBOX_URL = 'http://localhost:8080' } = process.env;
const rpc = createAztecRpcClient(SANDBOX_URL);
await waitForSandbox(rpc);
});

// docs:start:sandbox-example
describe('private token contract', () => {
const { SANDBOX_URL = 'http://localhost:8080' } = process.env;

let rpc: AztecRPC;
let owner: AccountWallet;
let recipient: AccountWallet;
let token: PrivateTokenContract;
let token: TokenContract;

beforeEach(async () => {
rpc = createAztecRpcClient(SANDBOX_URL);
owner = await createAccount(rpc);
recipient = await createAccount(rpc);
token = await PrivateTokenContract.deploy(owner, 100n, owner.getAddress()).send().deployed();
token = await TokenContract.deploy(owner).send().deployed();
await token.methods._initialize({ address: owner.getAddress() }).send().wait();
}, 30_000);

it('increases recipient funds on transfer', async () => {
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(0n);
await token.methods.transfer(20n, recipient.getAddress()).send().wait();
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(20n);
it('increases recipient funds on mint', async () => {
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(0n);
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
await token.methods.mint_private(20n, secretHash).send().wait();
await token.methods.redeem_shield({ address: recipient.getAddress() }, 20n, secret).send().wait();
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(20n);
});
});
// docs:end:sandbox-example

describe('private token contract with initial accounts', () => {
const { SANDBOX_URL = 'http://localhost:8080' } = process.env;

let rpc: AztecRPC;
let owner: AccountWallet;
let recipient: AccountWallet;
let token: PrivateTokenContract;
let token: TokenContract;

beforeEach(async () => {
// docs:start:use-existing-wallets
rpc = createAztecRpcClient(SANDBOX_URL);
[owner, recipient] = await getSandboxAccountsWallets(rpc);
token = await PrivateTokenContract.deploy(owner, 100n, owner.getAddress()).send().deployed();
token = await TokenContract.deploy(owner).send().deployed();
await token.methods._initialize({ address: owner.getAddress() }).send().wait();
// docs:end:use-existing-wallets
}, 30_000);

it('increases recipient funds on transfer', async () => {
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(0n);
await token.methods.transfer(20n, recipient.getAddress()).send().wait();
expect(await token.methods.getBalance(recipient.getAddress()).view()).toEqual(20n);
it('increases recipient funds on mint', async () => {
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(0n);
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
await token.methods.mint_private(20n, secretHash).send().wait();
await token.methods.redeem_shield({ address: recipient.getAddress() }, 20n, secret).send().wait();
expect(await token.methods.balance_of_private({ address: recipient.getAddress() }).view()).toEqual(20n);
});
});

describe('cheats', () => {
const { SANDBOX_URL = 'http://localhost:8080', ETHEREUM_HOST = 'http://localhost:8545' } = process.env;

let rpc: AztecRPC;
let owner: AccountWallet;
let testContract: TestContract;
Expand All @@ -122,29 +130,32 @@ describe('guides/dapp/testing', () => {
});

describe('assertions', () => {
const { SANDBOX_URL = 'http://localhost:8080', ETHEREUM_HOST = 'http://localhost:8545' } = process.env;

let rpc: AztecRPC;
let owner: AccountWallet;
let recipient: AccountWallet;
let token: PrivateTokenContract;
let nativeToken: NativeTokenContract;
let testContract: TestContract;
let token: TokenContract;
let cheats: CheatCodes;
let ownerSlot: Fr;

beforeAll(async () => {
rpc = createAztecRpcClient(SANDBOX_URL);
owner = await createAccount(rpc);
recipient = await createAccount(rpc);
token = await PrivateTokenContract.deploy(owner, 100n, owner.getAddress()).send().deployed();
nativeToken = await NativeTokenContract.deploy(owner, 100n, owner.getAddress()).send().deployed();
testContract = await TestContract.deploy(owner).send().deployed();
token = await TokenContract.deploy(owner).send().deployed();
await token.methods._initialize({ address: owner.getAddress() }).send().wait();
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
await token.methods.mint_private(100n, secretHash).send().wait();
await token.methods.redeem_shield({ address: owner.getAddress() }, 100n, secret).send().wait();

// docs:start:calc-slot
cheats = await CheatCodes.create(ETHEREUM_HOST, rpc);
// The balances mapping is defined on storage slot 1 and is indexed by user address
ownerSlot = cheats.aztec.computeSlotInMap(1n, owner.getAddress());
// The balances mapping is defined on storage slot 3 and is indexed by user address
ownerSlot = cheats.aztec.computeSlotInMap(3n, owner.getAddress());
// docs:end:calc-slot
}, 30_000);
}, 60_000);

it('checks private storage', async () => {
// docs:start:private-storage
Expand All @@ -157,40 +168,61 @@ describe('guides/dapp/testing', () => {

it('checks public storage', async () => {
// docs:start:public-storage
await nativeToken.methods.owner_mint_pub(owner.getAddress(), 100n).send().wait();
const ownerPublicBalanceSlot = cheats.aztec.computeSlotInMap(4n, owner.getAddress());
const balance = await rpc.getPublicStorageAt(nativeToken.address, ownerPublicBalanceSlot);
await token.methods.mint_public({ address: owner.getAddress() }, 100n).send().wait();
const ownerPublicBalanceSlot = cheats.aztec.computeSlotInMap(6n, owner.getAddress());
const balance = await rpc.getPublicStorageAt(token.address, ownerPublicBalanceSlot);
expect(toBigIntBE(balance!)).toEqual(100n);
// docs:end:public-storage
});

it('checks unencrypted logs', async () => {
it('checks unencrypted logs, [Kinda broken with current implementation]', async () => {
// docs:start:unencrypted-logs
const tx = await nativeToken.methods.owner_mint_pub(owner.getAddress(), 100n).send().wait();
const value = Fr.fromString('ef'); // Only 1 bytes will make its way in there :( so no larger stuff
const tx = await testContract.methods.emit_unencrypted(value).send().wait();
const logs = await rpc.getUnencryptedLogs(tx.blockNumber!, 1);
const textLogs = L2BlockL2Logs.unrollLogs(logs).map(log => log.toString('ascii'));
expect(textLogs).toEqual(['Coins minted']);
const log = L2BlockL2Logs.unrollLogs(logs)[0];
expect(Fr.fromBuffer(log)).toEqual(value);
// docs:end:unencrypted-logs
});

it('asserts a local transaction simulation fails by calling simulate', async () => {
// docs:start:local-tx-fails
const call = token.methods.transfer(200n, recipient.getAddress());
const call = token.methods.transfer(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
200n,
0,
);
await expect(call.simulate()).rejects.toThrowError(/Balance too low/);
// docs:end:local-tx-fails
});

it('asserts a local transaction simulation fails by calling send', async () => {
// docs:start:local-tx-fails-send
const call = token.methods.transfer(200n, recipient.getAddress());
const call = token.methods.transfer(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
200n,
0,
);
await expect(call.send().wait()).rejects.toThrowError(/Balance too low/);
// docs:end:local-tx-fails-send
});

it('asserts a transaction is dropped', async () => {
// docs:start:tx-dropped
const call1 = token.methods.transfer(80n, recipient.getAddress());
const call2 = token.methods.transfer(50n, recipient.getAddress());
const call1 = token.methods.transfer(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
80n,
0,
);
const call2 = token.methods.transfer(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
50n,
0,
);

await call1.simulate();
await call2.simulate();
Expand All @@ -202,14 +234,24 @@ describe('guides/dapp/testing', () => {

it('asserts a simulation for a public function call fails', async () => {
// docs:start:local-pub-fails
const call = nativeToken.methods.transfer_pub(recipient.getAddress(), 1000n);
await expect(call.simulate()).rejects.toThrowError(/Balance too low/);
const call = token.methods.transfer_public(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
1000n,
0,
);
await expect(call.simulate()).rejects.toThrowError(/Underflow/);
// docs:end:local-pub-fails
});

it('asserts a transaction with a failing public call is dropped (until we get public reverts)', async () => {
// docs:start:pub-dropped
const call = nativeToken.methods.transfer_pub(recipient.getAddress(), 1000n);
const call = token.methods.transfer_public(
{ address: owner.getAddress() },
{ address: recipient.getAddress() },
1000n,
0,
);
await expect(call.send({ skipPublicSimulation: true }).wait()).rejects.toThrowError(/dropped/);
// docs:end:pub-dropped
});
Expand Down
1 change: 0 additions & 1 deletion yarn-project/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ members = [
"src/contracts/import_test_contract",
"src/contracts/lending_contract",
"src/contracts/multi_transfer_contract",
"src/contracts/native_token_contract",
"src/contracts/non_native_token_contract",
"src/contracts/parent_contract",
"src/contracts/pending_commitments_contract",
Expand Down

This file was deleted.

Loading

0 comments on commit 4032d01

Please sign in to comment.