Skip to content

Commit

Permalink
feat: Token standard (#2069)
Browse files Browse the repository at this point in the history
Fixes #1743.

See #2199 for extensions that is required with generators etc to not
collide with payloads.
  • Loading branch information
LHerskind authored Sep 13, 2023
1 parent 7db21b0 commit 5e8fbf2
Show file tree
Hide file tree
Showing 22 changed files with 2,813 additions and 50 deletions.
15 changes: 15 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,19 @@ jobs:
command: ./scripts/cond_run_script end-to-end $JOB_NAME ./scripts/run_tests_local e2e_lending_contract.test.ts
working_directory: yarn-project/end-to-end

e2e-token-contract:
machine:
image: ubuntu-2004:202010-01
resource_class: large
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: ./scripts/cond_run_script end-to-end $JOB_NAME ./scripts/run_tests_local e2e_token_contract.test.ts
working_directory: yarn-project/end-to-end


e2e-private-token-contract:
machine:
image: ubuntu-2004:202010-01
Expand Down Expand Up @@ -1427,6 +1440,7 @@ workflows:
- e2e-2-rpc-servers: *e2e_test
- e2e-deploy-contract: *e2e_test
- e2e-lending-contract: *e2e_test
- e2e-token-contract: *e2e_test
- e2e-private-token-contract: *e2e_test
- e2e-sandbox-example: *e2e_test
- e2e-multi-transfer-contract: *e2e_test
Expand Down Expand Up @@ -1461,6 +1475,7 @@ workflows:
- e2e-2-rpc-servers
- e2e-deploy-contract
- e2e-lending-contract
- e2e-token-contract
- e2e-private-token-contract
- e2e-sandbox-example
- e2e-multi-transfer-contract
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/acir-simulator/src/client/private_execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,16 @@ export class PrivateFunctionExecution {
return Promise.resolve(ZERO_ACVM_FIELD);
},
enqueuePublicFunctionCall: async ([acvmContractAddress], [acvmFunctionSelector], [acvmArgsHash]) => {
const selector = FunctionSelector.fromField(fromACVMField(acvmFunctionSelector));
const enqueuedRequest = await this.enqueuePublicFunctionCall(
frToAztecAddress(fromACVMField(acvmContractAddress)),
FunctionSelector.fromField(fromACVMField(acvmFunctionSelector)),
selector,
this.context.packedArgsCache.unpack(fromACVMField(acvmArgsHash)),
this.callContext,
);

this.log(
`Enqueued call to public function (with side-effect counter #${enqueuedRequest.sideEffectCounter}) ${acvmContractAddress}:${acvmFunctionSelector}`,
`Enqueued call to public function (with side-effect counter #${enqueuedRequest.sideEffectCounter}) ${acvmContractAddress}:${selector}`,
);
enqueuedPublicFunctionCalls.push(enqueuedRequest);
return toAcvmEnqueuePublicFunctionResult(enqueuedRequest);
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/acir-simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ export class PublicExecutor {
},
callPublicFunction: async ([address], [functionSelector], [argsHash]) => {
const args = packedArgs.unpack(fromACVMField(argsHash));
this.log(`Public function call: addr=${address} selector=${functionSelector} args=${args.join(',')}`);
const selector = FunctionSelector.fromField(fromACVMField(functionSelector));
this.log(`Public function call: addr=${address} selector=${selector} args=${args.join(',')}`);
const childExecutionResult = await this.callPublicFunction(
frToAztecAddress(fromACVMField(address)),
FunctionSelector.fromField(fromACVMField(functionSelector)),
selector,
args,
execution.callContext,
globalVariables,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-rpc/src/simulator_oracle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class SimulatorOracle implements DBOracle {

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

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,50 @@ import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from '../../utils/defaults.js';
import { buildPayload, hashPayload } from './entrypoint_payload.js';
import { Entrypoint } from './index.js';

/**
* An extended interface for entrypoints that support signing and adding auth witnesses.
*/
export interface IAuthWitnessAccountEntrypoint extends Entrypoint {
/**
* Sign a message hash with the private key.
* @param message - The message hash to sign.
* @returns The signature as a Buffer.
*/
sign(message: Buffer): Buffer;

/**
* Creates an AuthWitness witness for the given message. In this case, witness is the public key, the signature
* and the partial address, to be used for verification.
* @param message - The message hash to sign.
* @param opts - Options.
* @returns [publicKey, signature, partialAddress] as Fr[].
*/
createAuthWitness(message: Buffer): Promise<Fr[]>;

/**
* Returns the transaction request and the auth witness for the given function calls.
* Returning the witness here as a nonce is generated in the buildPayload action.
* @param executions - The function calls to execute
* @param opts - The options
* @returns The TxRequest, the auth witness to insert in db and the message signed
*/
createTxExecutionRequestWithWitness(executions: FunctionCall[]): Promise<{
/** The transaction request */
txRequest: TxExecutionRequest;
/** The auth witness */
witness: Fr[];
/** The message signed */
message: Buffer;
}>;
}

/**
* Account contract implementation that uses a single key for signing and encryption. This public key is not
* stored in the contract, but rather verified against the contract address. Note that this approach is not
* secure and should not be used in real use cases.
* The entrypoint is extended to support signing and creating eip1271-like witnesses.
*/
export class AuthWitnessAccountEntrypoint implements Entrypoint {
export class AuthWitnessAccountEntrypoint implements IAuthWitnessAccountEntrypoint {
constructor(
private address: AztecAddress,
private partialAddress: PartialAddress,
Expand All @@ -25,21 +62,10 @@ export class AuthWitnessAccountEntrypoint implements Entrypoint {
private version: number = DEFAULT_VERSION,
) {}

/**
* Sign a message hash with the private key.
* @param message - The message hash to sign.
* @returns The signature as a Buffer.
*/
public sign(message: Buffer): Buffer {
return this.signer.constructSignature(message, this.privateKey).toBuffer();
}

/**
* Creates an AuthWitness witness for the given message. In this case, witness is the public key, the signature
* and the partial address, to be used for verification.
* @param message - The message hash to sign.
* @returns [publicKey, signature, partialAddress] as Fr[].
*/
async createAuthWitness(message: Buffer): Promise<Fr[]> {
const signature = this.sign(message);
const publicKey = await generatePublicKey(this.privateKey);
Expand Down
25 changes: 23 additions & 2 deletions yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
TxReceipt,
} from '@aztec/types';

import { AuthWitnessAccountEntrypoint, Entrypoint } from '../account/entrypoint/index.js';
import { Entrypoint, IAuthWitnessAccountEntrypoint } from '../account/entrypoint/index.js';
import { CompleteAddress } from '../index.js';

/**
Expand Down Expand Up @@ -121,7 +121,7 @@ export class EntrypointWallet extends BaseWallet {
* to provide authentication data to the contract during execution.
*/
export class AuthWitnessEntrypointWallet extends BaseWallet {
constructor(rpc: AztecRPC, protected accountImpl: AuthWitnessAccountEntrypoint) {
constructor(rpc: AztecRPC, protected accountImpl: IAuthWitnessAccountEntrypoint, protected address: CompleteAddress) {
super(rpc);
}

Expand Down Expand Up @@ -151,12 +151,33 @@ export class AuthWitnessEntrypointWallet extends BaseWallet {
* This is useful for signing messages that are not directly part of the transaction payload, such as
* approvals .
* @param messageHash - The message hash to sign
* @param opts - The options.
*/
async signAndAddAuthWitness(messageHash: Buffer): Promise<void> {
const witness = await this.accountImpl.createAuthWitness(messageHash);
await this.rpc.addAuthWitness(Fr.fromBuffer(messageHash), witness);
return Promise.resolve();
}

/**
* Signs the `messageHash` and adds the witness to the RPC.
* This is useful for signing messages that are not directly part of the transaction payload, such as
* approvals .
* @param messageHash - The message hash to sign
*/
async signAndGetAuthWitness(messageHash: Buffer): Promise<Fr[]> {
return await this.accountImpl.createAuthWitness(messageHash);
}

/** Returns the complete address of the account that implements this wallet. */
public getCompleteAddress() {
return this.address;
}

/** Returns the address of the account that implements this wallet. */
public getAddress() {
return this.address.address;
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions yarn-project/end-to-end/src/cli_docs_sandbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ SchnorrAuthWitnessAccountContractAbi
SchnorrHardcodedAccountContractAbi
SchnorrSingleKeyAccountContractAbi
TestContractAbi
TokenContractAbi
UniswapContractAbi
// docs:end:example-contracts
`;
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_account_contracts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ describe('e2e_account_contracts', () => {
await tx.wait();
}
const entryPoint = (await account.getEntrypoint()) as unknown as AuthWitnessAccountEntrypoint;
const wallet = new AuthWitnessEntrypointWallet(rpc, entryPoint);
const wallet = new AuthWitnessEntrypointWallet(rpc, entryPoint, await account.getCompleteAddress());
return { account, wallet };
},
);
Expand Down
23 changes: 13 additions & 10 deletions yarn-project/end-to-end/src/e2e_lending_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { AztecRPCServer } from '@aztec/aztec-rpc';
import {
Account,
AuthWitnessAccountContract,
AuthWitnessAccountEntrypoint,
AuthWitnessEntrypointWallet,
AztecAddress,
CheatCodes,
Fr,
IAuthWitnessAccountEntrypoint,
computeMessageSecretHash,
} from '@aztec/aztec.js';
import { CircuitsWasm, CompleteAddress, FunctionSelector, GeneratorIndex, GrumpkinScalar } from '@aztec/circuits.js';
Expand Down Expand Up @@ -82,15 +82,18 @@ describe('e2e_lending_contract', () => {
beforeEach(async () => {
({ aztecNode, aztecRpcServer, logger, cheatCodes: cc } = await setup(0));

const privateKey = GrumpkinScalar.random();
const account = new Account(aztecRpcServer, privateKey, new AuthWitnessAccountContract(privateKey));
const entryPoint = (await account.getEntrypoint()) as unknown as AuthWitnessAccountEntrypoint;

const deployTx = await account.deploy();
await deployTx.wait({ interval: 0.1 });

wallet = new AuthWitnessEntrypointWallet(aztecRpcServer, entryPoint);
accounts = await wallet.getAccounts();
{
const privateKey = GrumpkinScalar.random();
const account = new Account(aztecRpcServer, privateKey, new AuthWitnessAccountContract(privateKey));
const deployTx = await account.deploy();
await deployTx.wait({ interval: 0.1 });
wallet = new AuthWitnessEntrypointWallet(
aztecRpcServer,
(await account.getEntrypoint()) as unknown as IAuthWitnessAccountEntrypoint,
await account.getCompleteAddress(),
);
accounts = await wallet.getAccounts();
}
}, 100_000);

afterEach(async () => {
Expand Down
Loading

0 comments on commit 5e8fbf2

Please sign in to comment.