Skip to content

Commit 5e8fbf2

Browse files
authored
feat: Token standard (#2069)
Fixes #1743. See #2199 for extensions that is required with generators etc to not collide with payloads.
1 parent 7db21b0 commit 5e8fbf2

File tree

22 files changed

+2813
-50
lines changed

22 files changed

+2813
-50
lines changed

.circleci/config.yml

+15
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,19 @@ jobs:
712712
command: ./scripts/cond_run_script end-to-end $JOB_NAME ./scripts/run_tests_local e2e_lending_contract.test.ts
713713
working_directory: yarn-project/end-to-end
714714

715+
e2e-token-contract:
716+
machine:
717+
image: ubuntu-2004:202010-01
718+
resource_class: large
719+
steps:
720+
- *checkout
721+
- *setup_env
722+
- run:
723+
name: "Test"
724+
command: ./scripts/cond_run_script end-to-end $JOB_NAME ./scripts/run_tests_local e2e_token_contract.test.ts
725+
working_directory: yarn-project/end-to-end
726+
727+
715728
e2e-private-token-contract:
716729
machine:
717730
image: ubuntu-2004:202010-01
@@ -1427,6 +1440,7 @@ workflows:
14271440
- e2e-2-rpc-servers: *e2e_test
14281441
- e2e-deploy-contract: *e2e_test
14291442
- e2e-lending-contract: *e2e_test
1443+
- e2e-token-contract: *e2e_test
14301444
- e2e-private-token-contract: *e2e_test
14311445
- e2e-sandbox-example: *e2e_test
14321446
- e2e-multi-transfer-contract: *e2e_test
@@ -1461,6 +1475,7 @@ workflows:
14611475
- e2e-2-rpc-servers
14621476
- e2e-deploy-contract
14631477
- e2e-lending-contract
1478+
- e2e-token-contract
14641479
- e2e-private-token-contract
14651480
- e2e-sandbox-example
14661481
- e2e-multi-transfer-contract

yarn-project/acir-simulator/src/client/private_execution.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,16 @@ export class PrivateFunctionExecution {
135135
return Promise.resolve(ZERO_ACVM_FIELD);
136136
},
137137
enqueuePublicFunctionCall: async ([acvmContractAddress], [acvmFunctionSelector], [acvmArgsHash]) => {
138+
const selector = FunctionSelector.fromField(fromACVMField(acvmFunctionSelector));
138139
const enqueuedRequest = await this.enqueuePublicFunctionCall(
139140
frToAztecAddress(fromACVMField(acvmContractAddress)),
140-
FunctionSelector.fromField(fromACVMField(acvmFunctionSelector)),
141+
selector,
141142
this.context.packedArgsCache.unpack(fromACVMField(acvmArgsHash)),
142143
this.callContext,
143144
);
144145

145146
this.log(
146-
`Enqueued call to public function (with side-effect counter #${enqueuedRequest.sideEffectCounter}) ${acvmContractAddress}:${acvmFunctionSelector}`,
147+
`Enqueued call to public function (with side-effect counter #${enqueuedRequest.sideEffectCounter}) ${acvmContractAddress}:${selector}`,
147148
);
148149
enqueuedPublicFunctionCalls.push(enqueuedRequest);
149150
return toAcvmEnqueuePublicFunctionResult(enqueuedRequest);

yarn-project/acir-simulator/src/public/executor.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,11 @@ export class PublicExecutor {
124124
},
125125
callPublicFunction: async ([address], [functionSelector], [argsHash]) => {
126126
const args = packedArgs.unpack(fromACVMField(argsHash));
127-
this.log(`Public function call: addr=${address} selector=${functionSelector} args=${args.join(',')}`);
127+
const selector = FunctionSelector.fromField(fromACVMField(functionSelector));
128+
this.log(`Public function call: addr=${address} selector=${selector} args=${args.join(',')}`);
128129
const childExecutionResult = await this.callPublicFunction(
129130
frToAztecAddress(fromACVMField(address)),
130-
FunctionSelector.fromField(fromACVMField(functionSelector)),
131+
selector,
131132
args,
132133
execution.callContext,
133134
globalVariables,

yarn-project/aztec-rpc/src/simulator_oracle/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class SimulatorOracle implements DBOracle {
4848

4949
async getAuthWitness(messageHash: Fr): Promise<Fr[]> {
5050
const witness = await this.db.getAuthWitness(messageHash);
51-
if (!witness) throw new Error(`Unknown auth witness for message hash ${messageHash.toString()}`);
51+
if (!witness) throw new Error(`Unknown auth witness for message hash ${messageHash.toString(true)}`);
5252
return witness;
5353
}
5454

yarn-project/aztec.js/src/abis/schnorr_auth_witness_account_contract.json

+541-2
Large diffs are not rendered by default.

yarn-project/aztec.js/src/account/entrypoint/auth_witness_account_entrypoint.ts

+38-12
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,50 @@ import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from '../../utils/defaults.js';
99
import { buildPayload, hashPayload } from './entrypoint_payload.js';
1010
import { Entrypoint } from './index.js';
1111

12+
/**
13+
* An extended interface for entrypoints that support signing and adding auth witnesses.
14+
*/
15+
export interface IAuthWitnessAccountEntrypoint extends Entrypoint {
16+
/**
17+
* Sign a message hash with the private key.
18+
* @param message - The message hash to sign.
19+
* @returns The signature as a Buffer.
20+
*/
21+
sign(message: Buffer): Buffer;
22+
23+
/**
24+
* Creates an AuthWitness witness for the given message. In this case, witness is the public key, the signature
25+
* and the partial address, to be used for verification.
26+
* @param message - The message hash to sign.
27+
* @param opts - Options.
28+
* @returns [publicKey, signature, partialAddress] as Fr[].
29+
*/
30+
createAuthWitness(message: Buffer): Promise<Fr[]>;
31+
32+
/**
33+
* Returns the transaction request and the auth witness for the given function calls.
34+
* Returning the witness here as a nonce is generated in the buildPayload action.
35+
* @param executions - The function calls to execute
36+
* @param opts - The options
37+
* @returns The TxRequest, the auth witness to insert in db and the message signed
38+
*/
39+
createTxExecutionRequestWithWitness(executions: FunctionCall[]): Promise<{
40+
/** The transaction request */
41+
txRequest: TxExecutionRequest;
42+
/** The auth witness */
43+
witness: Fr[];
44+
/** The message signed */
45+
message: Buffer;
46+
}>;
47+
}
48+
1249
/**
1350
* Account contract implementation that uses a single key for signing and encryption. This public key is not
1451
* stored in the contract, but rather verified against the contract address. Note that this approach is not
1552
* secure and should not be used in real use cases.
1653
* The entrypoint is extended to support signing and creating eip1271-like witnesses.
1754
*/
18-
export class AuthWitnessAccountEntrypoint implements Entrypoint {
55+
export class AuthWitnessAccountEntrypoint implements IAuthWitnessAccountEntrypoint {
1956
constructor(
2057
private address: AztecAddress,
2158
private partialAddress: PartialAddress,
@@ -25,21 +62,10 @@ export class AuthWitnessAccountEntrypoint implements Entrypoint {
2562
private version: number = DEFAULT_VERSION,
2663
) {}
2764

28-
/**
29-
* Sign a message hash with the private key.
30-
* @param message - The message hash to sign.
31-
* @returns The signature as a Buffer.
32-
*/
3365
public sign(message: Buffer): Buffer {
3466
return this.signer.constructSignature(message, this.privateKey).toBuffer();
3567
}
3668

37-
/**
38-
* Creates an AuthWitness witness for the given message. In this case, witness is the public key, the signature
39-
* and the partial address, to be used for verification.
40-
* @param message - The message hash to sign.
41-
* @returns [publicKey, signature, partialAddress] as Fr[].
42-
*/
4369
async createAuthWitness(message: Buffer): Promise<Fr[]> {
4470
const signature = this.sign(message);
4571
const publicKey = await generatePublicKey(this.privateKey);

yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
TxReceipt,
1717
} from '@aztec/types';
1818

19-
import { AuthWitnessAccountEntrypoint, Entrypoint } from '../account/entrypoint/index.js';
19+
import { Entrypoint, IAuthWitnessAccountEntrypoint } from '../account/entrypoint/index.js';
2020
import { CompleteAddress } from '../index.js';
2121

2222
/**
@@ -121,7 +121,7 @@ export class EntrypointWallet extends BaseWallet {
121121
* to provide authentication data to the contract during execution.
122122
*/
123123
export class AuthWitnessEntrypointWallet extends BaseWallet {
124-
constructor(rpc: AztecRPC, protected accountImpl: AuthWitnessAccountEntrypoint) {
124+
constructor(rpc: AztecRPC, protected accountImpl: IAuthWitnessAccountEntrypoint, protected address: CompleteAddress) {
125125
super(rpc);
126126
}
127127

@@ -151,12 +151,33 @@ export class AuthWitnessEntrypointWallet extends BaseWallet {
151151
* This is useful for signing messages that are not directly part of the transaction payload, such as
152152
* approvals .
153153
* @param messageHash - The message hash to sign
154+
* @param opts - The options.
154155
*/
155156
async signAndAddAuthWitness(messageHash: Buffer): Promise<void> {
156157
const witness = await this.accountImpl.createAuthWitness(messageHash);
157158
await this.rpc.addAuthWitness(Fr.fromBuffer(messageHash), witness);
158159
return Promise.resolve();
159160
}
161+
162+
/**
163+
* Signs the `messageHash` and adds the witness to the RPC.
164+
* This is useful for signing messages that are not directly part of the transaction payload, such as
165+
* approvals .
166+
* @param messageHash - The message hash to sign
167+
*/
168+
async signAndGetAuthWitness(messageHash: Buffer): Promise<Fr[]> {
169+
return await this.accountImpl.createAuthWitness(messageHash);
170+
}
171+
172+
/** Returns the complete address of the account that implements this wallet. */
173+
public getCompleteAddress() {
174+
return this.address;
175+
}
176+
177+
/** Returns the address of the account that implements this wallet. */
178+
public getAddress() {
179+
return this.address.address;
180+
}
160181
}
161182

162183
/**

yarn-project/end-to-end/src/cli_docs_sandbox.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ SchnorrAuthWitnessAccountContractAbi
104104
SchnorrHardcodedAccountContractAbi
105105
SchnorrSingleKeyAccountContractAbi
106106
TestContractAbi
107+
TokenContractAbi
107108
UniswapContractAbi
108109
// docs:end:example-contracts
109110
`;

yarn-project/end-to-end/src/e2e_account_contracts.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ describe('e2e_account_contracts', () => {
128128
await tx.wait();
129129
}
130130
const entryPoint = (await account.getEntrypoint()) as unknown as AuthWitnessAccountEntrypoint;
131-
const wallet = new AuthWitnessEntrypointWallet(rpc, entryPoint);
131+
const wallet = new AuthWitnessEntrypointWallet(rpc, entryPoint, await account.getCompleteAddress());
132132
return { account, wallet };
133133
},
134134
);

yarn-project/end-to-end/src/e2e_lending_contract.test.ts

+13-10
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { AztecRPCServer } from '@aztec/aztec-rpc';
33
import {
44
Account,
55
AuthWitnessAccountContract,
6-
AuthWitnessAccountEntrypoint,
76
AuthWitnessEntrypointWallet,
87
AztecAddress,
98
CheatCodes,
109
Fr,
10+
IAuthWitnessAccountEntrypoint,
1111
computeMessageSecretHash,
1212
} from '@aztec/aztec.js';
1313
import { CircuitsWasm, CompleteAddress, FunctionSelector, GeneratorIndex, GrumpkinScalar } from '@aztec/circuits.js';
@@ -82,15 +82,18 @@ describe('e2e_lending_contract', () => {
8282
beforeEach(async () => {
8383
({ aztecNode, aztecRpcServer, logger, cheatCodes: cc } = await setup(0));
8484

85-
const privateKey = GrumpkinScalar.random();
86-
const account = new Account(aztecRpcServer, privateKey, new AuthWitnessAccountContract(privateKey));
87-
const entryPoint = (await account.getEntrypoint()) as unknown as AuthWitnessAccountEntrypoint;
88-
89-
const deployTx = await account.deploy();
90-
await deployTx.wait({ interval: 0.1 });
91-
92-
wallet = new AuthWitnessEntrypointWallet(aztecRpcServer, entryPoint);
93-
accounts = await wallet.getAccounts();
85+
{
86+
const privateKey = GrumpkinScalar.random();
87+
const account = new Account(aztecRpcServer, privateKey, new AuthWitnessAccountContract(privateKey));
88+
const deployTx = await account.deploy();
89+
await deployTx.wait({ interval: 0.1 });
90+
wallet = new AuthWitnessEntrypointWallet(
91+
aztecRpcServer,
92+
(await account.getEntrypoint()) as unknown as IAuthWitnessAccountEntrypoint,
93+
await account.getCompleteAddress(),
94+
);
95+
accounts = await wallet.getAccounts();
96+
}
9497
}, 100_000);
9598

9699
afterEach(async () => {

0 commit comments

Comments
 (0)