Skip to content
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
36 changes: 36 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,42 @@ Or pass version to sync:
aztec_sync_repos({ version: "v4.0.0-devnet.2-patch.1", force: true })
```

## ⚠️ Critical: Simulate Before Send

**Always call `.simulate()` before `.send()` for every state-changing transaction.**

Without simulation, failing transactions hang for up to 600 seconds with opaque errors. `.simulate()` surfaces revert reasons instantly.

```typescript
// Standard method call
await contract.methods.myMethod(args).simulate({ from: account.address });
const tx = await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
wait: { timeout: 600 }
});

// Contract deployment (break the chain)
const deployRequest = MyContract.deploy(wallet, admin);
await deployRequest.simulate({ from: admin });
const contract = await deployRequest.send({
from: admin, fee: { paymentMethod }, wait: { timeout, returnReceipt: true }
});

// Account deployment (break the chain)
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO, fee: { paymentMethod }, wait: { timeout }
});
```

**Key rules:**
- `.simulate()` only needs `from` — no `fee`, `wait`, or `authWitnesses`
- For deploy chains, break into a variable first, then simulate, then send
- For error tests, use `.simulate()` instead of `.send()` to catch reverts
- View/read-only calls already use `.simulate()` — skip those

## Useful Resources

- Aztec Documentation: https://docs.aztec.network
Expand Down
4 changes: 3 additions & 1 deletion skills/aztec-accounts/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const account = await wallet.createSchnorrAccount(secretKey, salt, signingKey);
console.log(`Account address: ${account.address}`);

// Deploy account (required before use)
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod: sponsoredPaymentMethod },
wait: { timeout: 120000 }
Expand Down
5 changes: 4 additions & 1 deletion skills/aztec-accounts/account-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ async function useRecoveredAccount() {
// Use account for transactions
const contract = MyContract.at(contractAddress, wallet);

await contract.methods.myMethod(args).simulate({ from: account.address });
await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down Expand Up @@ -191,7 +192,9 @@ const isDeployed = await isAccountDeployed(wallet, account);

if (!isDeployed) {
console.log('Account not yet deployed, deploying...');
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: 120000 }
Expand Down
11 changes: 9 additions & 2 deletions skills/aztec-accounts/schnorr-accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const paymentMethod = new SponsoredFeePaymentMethod(sponsoredFPC.address);
const deployMethod = await account.getDeployMethod();

// Deploy
await deployMethod.simulate({ from: AztecAddress.ZERO });
const tx = await deployMethod.send({
from: AztecAddress.ZERO, // No sender for account deployment
fee: { paymentMethod },
Expand Down Expand Up @@ -101,6 +102,7 @@ export async function createAndDeployAccount(

// Deploy account
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
const tx = await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
Expand Down Expand Up @@ -137,7 +139,9 @@ async function createTestAccounts(wallet: EmbeddedWallet, count: number) {

const account = await wallet.createSchnorrAccount(secretKey, salt, signingKey);

await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: 120000 }
Expand Down Expand Up @@ -181,7 +185,9 @@ export async function generateSchnorrAccounts(

// Step 2: Deploy all accounts (sends transactions)
for (const account of accounts) {
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: 120000 }
Expand All @@ -207,6 +213,7 @@ After deployment, register accounts for transaction sending:
await wallet.registerSender(account.address);

// Now the wallet can send transactions from this account
await contract.methods.myMethod(args).simulate({ from: account.address });
await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down
4 changes: 3 additions & 1 deletion skills/aztec-deploy/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ async function main() {
const account = await deploySchnorrAccount(wallet);

// 4. Deploy contract
const { contract } = await MyContract.deploy(wallet, account.address).send({
const deployRequest = MyContract.deploy(wallet, account.address);
await deployRequest.simulate({ from: account.address });
const { contract } = await deployRequest.send({
from: account.address,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout, returnReceipt: true }
Expand Down
3 changes: 3 additions & 0 deletions skills/aztec-deploy/deploy-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ async function main() {

// Deploy account
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
const accountTx = await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod: sponsoredPaymentMethod },
Expand All @@ -82,6 +83,7 @@ async function main() {
const contractDeployMethod = MyContract.deploy(wallet, ...constructorArgs);

logger.info('Waiting for deployment transaction to be mined...');
await contractDeployMethod.simulate({ from: account.address });
const { contract } = await contractDeployMethod.send({
from: account.address,
fee: { paymentMethod: sponsoredPaymentMethod },
Expand Down Expand Up @@ -191,6 +193,7 @@ export async function deploySchnorrAccount(wallet?: EmbeddedWallet): Promise<Acc

// Deploy account
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
const tx = await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod: sponsoredPaymentMethod },
Expand Down
10 changes: 8 additions & 2 deletions skills/aztec-deploy/fee-payment.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,25 @@ const paymentMethod = new SponsoredFeePaymentMethod(sponsoredFPC.address);

```typescript
// Deploy account with sponsored fees
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO, // No sender for account deployment
fee: { paymentMethod },
wait: { timeout: 120000 }
});

// Deploy contract with sponsored fees
const { contract } = await MyContract.deploy(wallet, args).send({
const deployRequest = MyContract.deploy(wallet, args);
await deployRequest.simulate({ from: account.address });
const { contract } = await deployRequest.send({
from: account.address,
fee: { paymentMethod },
wait: { timeout: 120000, returnReceipt: true }
});

// Call contract method with sponsored fees
await contract.methods.myMethod(args).simulate({ from: account.address });
await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down Expand Up @@ -139,6 +144,7 @@ interface SendMethodOptions {

```typescript
try {
await contract.methods.myMethod(args).simulate({ from: account.address });
const tx = await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down
9 changes: 7 additions & 2 deletions skills/aztec-e2e-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,26 @@ describe("MyContract", () => {
const signingKey = GrumpkinScalar.random();
const salt = Fr.random();
account = await wallet.createSchnorrAccount(secretKey, salt, signingKey);
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
});

// Deploy contract
contract = await MyContract.deploy(wallet, account.address).send({
const deployRequest = MyContract.deploy(wallet, account.address);
await deployRequest.simulate({ from: account.address });
contract = await deployRequest.send({
from: account.address,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
}).deployed();
}, 600000);

it("should perform an action", async () => {
await contract.methods.myMethod(args).simulate({ from: account.address });
const tx = await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down
12 changes: 9 additions & 3 deletions skills/aztec-e2e-testing/jest-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ describe("MyContract", () => {
const salt = Fr.random();
account = await wallet.createSchnorrAccount(secretKey, salt, signingKey);

await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod: sponsoredPaymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand All @@ -140,7 +142,9 @@ describe("MyContract", () => {
await wallet.registerSender(account.address);

// 4. Deploy contract
contract = await MyContract.deploy(wallet, account.address).send({
const deployRequest = MyContract.deploy(wallet, account.address);
await deployRequest.simulate({ from: account.address });
contract = await deployRequest.send({
from: account.address,
fee: { paymentMethod: sponsoredPaymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand Down Expand Up @@ -198,7 +202,9 @@ export async function createTestContext(accountCount: number = 1): Promise<TestC
const salt = Fr.random();

const account = await wallet.createSchnorrAccount(secretKey, salt, signingKey);
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand Down
22 changes: 17 additions & 5 deletions skills/aztec-e2e-testing/sponsored-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ beforeAll(async () => {

```typescript
// Deploy account with sponsored fees (no sender required)
await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO, // ZERO address for account deployment
fee: { paymentMethod: sponsoredPaymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand All @@ -42,7 +44,9 @@ await (await account.getDeployMethod()).send({

```typescript
// Deploy contract with sponsored fees
const contract = await MyContract.deploy(wallet, admin).send({
const deployRequest = MyContract.deploy(wallet, admin);
await deployRequest.simulate({ from: admin });
const contract = await deployRequest.send({
from: admin,
fee: { paymentMethod: sponsoredPaymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand All @@ -53,6 +57,7 @@ const contract = await MyContract.deploy(wallet, admin).send({

```typescript
// Execute transaction with sponsored fees
await contract.methods.myMethod(args).simulate({ from: account.address });
await contract.methods.myMethod(args).send({
from: account.address,
fee: { paymentMethod: sponsoredPaymentMethod },
Expand Down Expand Up @@ -98,7 +103,9 @@ describe("MyContract with Sponsored Fees", () => {
GrumpkinScalar.random()
);

await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand All @@ -107,7 +114,9 @@ describe("MyContract with Sponsored Fees", () => {
await wallet.registerSender(account.address);

// 4. Deploy contract
contract = await MyContract.deploy(wallet, account.address).send({
const deployRequest = MyContract.deploy(wallet, account.address);
await deployRequest.simulate({ from: account.address });
contract = await deployRequest.send({
from: account.address,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand All @@ -116,6 +125,7 @@ describe("MyContract with Sponsored Fees", () => {
}, 600000);

it("should perform action with sponsored fees", async () => {
await contract.methods.myAction(args).simulate({ from: account.address });
const tx = await contract.methods.myAction(args).send({
from: account.address,
fee: { paymentMethod },
Expand Down Expand Up @@ -187,7 +197,9 @@ async function createSponsoredAccount(
GrumpkinScalar.random()
);

await (await account.getDeployMethod()).send({
const deployMethod = await account.getDeployMethod();
await deployMethod.simulate({ from: AztecAddress.ZERO });
await deployMethod.send({
from: AztecAddress.ZERO,
fee: { paymentMethod },
wait: { timeout: getTimeouts().deployTimeout },
Expand Down
Loading