Skip to content

Commit 2948731

Browse files
author
Esau
committed
Add more
1 parent dfb2ffa commit 2948731

File tree

2 files changed

+67
-40
lines changed

2 files changed

+67
-40
lines changed

account-contract/README.md

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -97,60 +97,78 @@ Install TypeScript dependencies:
9797
yarn install
9898
```
9999

100-
## Usage
100+
Start the local network:
101101

102-
### 1. Deploy the Account Contract
102+
```bash
103+
aztec start --local-network
104+
```
103105

104-
```typescript
105-
import { PasswordAccountContract } from "./ts/password-account-entrypoint";
106-
import { Fr } from "@aztec/foundation/fields";
106+
Deploy the account contract to the local network:
107107

108-
// Create account contract with password
109-
const password = new Fr(123456789);
110-
const accountContract = new PasswordAccountContract(password);
108+
```bash
109+
npx tsx deploy-account-contract.ts
110+
```
111111

112-
// Get artifact and initialization args
113-
const artifact = await accountContract.getContractArtifact();
114-
const { constructorName, constructorArgs } =
115-
await accountContract.getInitializationFunctionAndArgs();
112+
### Use the account contract as normal
116113

117-
// Deploy using DeployMethod
118-
// See ts/deploy-account-contract.ts for full example
119-
```
114+
## Security Considerations
120115

121-
### 2. Create Transactions
116+
- The password is hashed using Poseidon2 before storage
117+
- Password is required for every transaction (no caching)
118+
- Password is included in transaction data (encrypted in private state)
119+
- This is a demonstration contract - production use should consider additional security measures
120+
- Consider using signature-based accounts for most production use cases
122121

123-
The account contract authenticates transactions by verifying the password hash:
122+
## Important Considerations
124123

125-
```typescript
126-
// Transactions automatically include the password in the entrypoint call
127-
// The password is hashed with Poseidon2 and compared to stored hash
128-
```
124+
When implementing custom account contracts in Aztec, be aware of these critical points:
129125

130-
### 3. Authorization Witnesses
126+
### All Execution Starts in Private
131127

132-
For cross-contract calls requiring authorization:
128+
**This is the most important gotcha**: In Aztec, all transaction execution begins in the private context, even if your contract only has public functions. The account contract's `entrypoint` function always executes in private first.
133129

134-
```typescript
135-
// The account can authorize actions for other contracts
136-
// Password is used to verify the authorization
137-
```
130+
- Your `entrypoint` function must be a `private` or `unconstrained private` function
131+
- Even when calling public functions on other contracts, the call originates from private execution
132+
- Authentication logic in the entrypoint runs in the private context
133+
- If you need to validate anything on-chain, you must enqueue public calls and handle them accordingly
138134

139-
## Fee Payment Methods
135+
### Password/Secret Storage
140136

141-
The contract supports three fee payment options:
137+
- **Never store passwords in plain text**: Always hash sensitive data before storage (like we do with Poseidon2)
138+
- The `hashed_password` is stored in `PublicImmutable` storage, meaning it's visible on-chain but cannot be changed
139+
- Consider whether your authentication secret should be changeable (would require mutable storage)
142140

143-
1. **EXTERNAL (0)**: Another contract pays the fee
144-
2. **PREEXISTING_FEE_JUICE (1)**: Account pays with existing FeeJuice balance
145-
3. **FEE_JUICE_WITH_CLAIM (2)**: Account pays with FeeJuice claimed in same transaction
141+
### Entrypoint Function Signature
146142

147-
## Security Considerations
143+
- The entrypoint must match the expected signature for account contracts
144+
- It receives the payload (functions to call) and fee payment options
148145

149-
- The password is hashed using Poseidon2 before storage
150-
- Password is required for every transaction (no caching)
151-
- Password is included in transaction data (encrypted in private state)
152-
- This is a demonstration contract - production use should consider additional security measures
153-
- Consider using signature-based accounts for most production use cases
146+
### State Management
147+
148+
- Private state is encrypted and only visible to those with the viewing key
149+
- Public state is visible to everyone on-chain
150+
- Choose storage types carefully: `PublicImmutable`, `PublicMutable`, `PrivateImmutable`, `PrivateMutable`, `PrivateSet`, etc.
151+
- Changing storage types after deployment requires a new contract deployment
152+
153+
### Transaction Construction
154+
155+
- Account contracts need TypeScript integration for proper transaction construction
156+
- You must implement the `AccountContract`, `AccountInterface`, and custom entrypoint classes
157+
- The entrypoint class handles encoding your authentication mechanism into the transaction payload
158+
- Mismatches between Noir and TypeScript implementations will cause authentication failures
159+
160+
### Testing and Debugging
161+
162+
- Private execution errors can be harder to debug since execution details aren't always visible
163+
- Test thoroughly with different fee payment methods
164+
- Ensure your authentication mechanism works for both direct calls and authwit flows
165+
166+
### Gas and Fee Considerations
167+
168+
- Account contracts are responsible for paying transaction fees
169+
- You must handle the fee payment method selection properly
170+
- Failed fee payments will cause the entire transaction to fail
171+
- Consider how users will fund their account contracts with Fee Asset
154172

155173
## Dependencies
156174

account-contract/ts/deploy-account-contract.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { AztecAddress } from '@aztec/stdlib/aztec-address';
33
import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee';
44
import { getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
5+
import { CardGameContract } from '@aztec/noir-contracts.js/CardGame';
56
import { SponsoredFPCContractArtifact } from '@aztec/noir-contracts.js/SponsoredFPC';
67
import { SPONSORED_FPC_SALT } from '@aztec/constants';
78
import { Fr } from '@aztec/foundation/fields';
@@ -61,7 +62,7 @@ const wallet = await TestWallet.create(createAztecNodeClient('http://localhost:8
6162

6263
await wallet.registerContract(await getSponsoredPFCContract(), SponsoredFPCContractArtifact);
6364

64-
const hello = new DeployMethod(
65+
const accountContractDeployMethod = new DeployMethod(
6566
publicKeys,
6667
wallet,
6768
artifact,
@@ -70,7 +71,15 @@ const hello = new DeployMethod(
7071
constructorName,
7172
)
7273

73-
const { estimatedGas, stats } = await hello.simulate(deployAccountOpts);
74+
const { estimatedGas, stats } = await accountContractDeployMethod.simulate(deployAccountOpts);
7475

7576
console.log(estimatedGas);
7677
console.log(stats);
78+
79+
const deployedAccountContract = await accountContractDeployMethod.send(deployAccountOpts).wait();
80+
81+
await wallet.createAccount({ secret: Fr.random(), contract: passwordAccountContract, salt: Fr.random() });
82+
83+
const cardGameContract = await CardGameContract.deploy(wallet).send({ from: deployedAccountContract.contract.address }).deployed();
84+
85+
console.log(cardGameContract)

0 commit comments

Comments
 (0)