Skip to content

Commit

Permalink
feat!: wallet authwit management (#8128)
Browse files Browse the repository at this point in the history
Added the ability of authorizing actions to be performed on behalf of
our accounts, both in public and private. Also revamped tests so they're
easier to follow and read their results.

## New commands

For private authwits

- `create-authwit [options] <functionName> <caller>`: Creates an
authorization witness that can be privately sent to a caller so they can
perform an action on behalf of the provided account.
- `add-authwit [options] <authwit> <authorizer>`: Adds an authorization
witness to the provided account, granting PXE access to the notes of the
authorizer so that it can be verified

Test showcasing usage
`./yarn-project/cli-wallet/test/flows/private_authwit_transfer.sh`

For public authwits

- `authorize-action [options] <functionName> <caller>`: Authorizes a
public call on the caller, so they can perform an action on behalf of
the provided account

Test showcasing usage
`./yarn-project/cli-wallet/test/flows/public_authwit_transfer.sh`

## Breaking changes

- `add-note` command now uses `-t, --transaction-hash` instead of `-h`
to not confuse it with the `--help` option. (thanks for the heads up,
@signorecello!)

## Other changes

- `bridge-fee-juice` now allows a `--no-wait` option to avoid polling
the network for the L2 messages to appear, and alternatively an
`--interval <seconds>` option to set polling interval (60s by default).

---------

Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com>
  • Loading branch information
Thunkar and sklppy88 authored Aug 27, 2024
1 parent ae37b09 commit f6362ea
Show file tree
Hide file tree
Showing 21 changed files with 532 additions and 106 deletions.
4 changes: 4 additions & 0 deletions yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export abstract class BaseWallet implements Wallet {
this.scopes = scopes;
}

getScopes() {
return this.scopes;
}

getAddress() {
return this.getCompleteAddress().address;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ export class EcdsaSignature implements Signature {
public v: Buffer,
) {
if (r.length != 32) {
throw new Error(`Invalid length of 'r' in ECDSA signature`);
throw new Error(`Invalid length of 'r' in ECDSA signature. Expected 32, got ${s.length}`);
}
if (s.length != 32) {
throw new Error(`Invalid length of 's' in ECDSA signature`);
throw new Error(`Invalid length of 's' in ECDSA signature. Expected 32, got ${r.length}`);
}
if (v.length != 1) {
throw new Error(`Invalid length of '1' in ECDSA signature`);
throw new Error(`Invalid length of 'v' in ECDSA signature. Expected 1, got ${v.length}`);
}
}

Expand Down
13 changes: 13 additions & 0 deletions yarn-project/cli-wallet/src/cmds/add_authwit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { type AccountWalletWithSecretKey, type AuthWitness, type AztecAddress } from '@aztec/aztec.js';
import { type LogFn } from '@aztec/foundation/log';

export async function addAuthwit(
wallet: AccountWalletWithSecretKey,
authwit: AuthWitness,
authorizer: AztecAddress,
log: LogFn,
) {
await wallet.addAuthWitness(authwit);

log(`Added authorization witness from ${authorizer}`);
}
35 changes: 35 additions & 0 deletions yarn-project/cli-wallet/src/cmds/authorize_action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type AccountWalletWithSecretKey, type AztecAddress, Contract } from '@aztec/aztec.js';
import { prepTx } from '@aztec/cli/utils';
import { type LogFn } from '@aztec/foundation/log';

export async function authorizeAction(
wallet: AccountWalletWithSecretKey,
functionName: string,
caller: AztecAddress,
functionArgsIn: any[],
contractArtifactPath: string,
contractAddress: AztecAddress,
log: LogFn,
) {
const { functionArgs, contractArtifact, isPrivate } = await prepTx(
contractArtifactPath,
functionName,
functionArgsIn,
log,
);

if (isPrivate) {
throw new Error(
'Cannot authorize private function. To allow a third party to call a private function, please create an authorization witness via the create-authwit command',
);
}

const contract = await Contract.at(contractAddress, contractArtifact, wallet);
const action = contract.methods[functionName](...functionArgs);

const witness = await wallet.setPublicAuthWit({ caller, action }, true).send().wait();

log(`Authorized action ${functionName} on contract ${contractAddress} for caller ${caller}`);

return witness;
}
40 changes: 31 additions & 9 deletions yarn-project/cli-wallet/src/cmds/bridge_fee_juice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export async function bridgeL1FeeJuice(
mnemonic: string,
mint: boolean,
json: boolean,
wait: boolean,
interval = 60_000,
log: LogFn,
debugLogger: DebugLogger,
) {
Expand Down Expand Up @@ -47,18 +49,38 @@ export async function bridgeL1FeeJuice(
}
log(`claimAmount=${claimAmount},claimSecret=${claimSecret},messageHash=${messageHash}\n`);
log(`Note: You need to wait for two L2 blocks before pulling them from the L2 side`);
log(`This command will now continually poll every minute for the inclusion of the newly created L1 to L2 message`);
if (wait) {
log(
`This command will now continually poll every ${
interval / 1000
}s for the inclusion of the newly created L1 to L2 message`,
);
}
}

const interval = setInterval(async () => {
const witness = await client.getL1ToL2MembershipWitness(feeJuiceAddress, Fr.fromString(messageHash), claimSecret);
if (witness) {
log(`Your bridged fee juice is now available. You can claim it like this:
aztec send claim_public --args ${recipient} ${amount} ${claimSecret} ${witness[0]} -ca ${feeJuiceAddress} -c FeeJuice -sk $SECRET_KEY
`);
clearInterval(interval);
if (wait) {
const delayedCheck = (delay: number) => {
return new Promise(resolve => {
setTimeout(async () => {
const witness = await client.getL1ToL2MembershipWitness(
feeJuiceAddress,
Fr.fromString(messageHash),
claimSecret,
);
resolve(witness);
}, delay);
});
};

let witness;

while (!witness) {
witness = await delayedCheck(interval);
if (!witness) {
log(`No L1 to L2 message found yet, checking again in ${interval / 1000}s`);
}
}
}, 60_000);
}

return claimSecret;
}
35 changes: 35 additions & 0 deletions yarn-project/cli-wallet/src/cmds/create_authwit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type AccountWalletWithSecretKey, type AztecAddress, Contract } from '@aztec/aztec.js';
import { prepTx } from '@aztec/cli/utils';
import { type LogFn } from '@aztec/foundation/log';

export async function createAuthwit(
wallet: AccountWalletWithSecretKey,
functionName: string,
caller: AztecAddress,
functionArgsIn: any[],
contractArtifactPath: string,
contractAddress: AztecAddress,
log: LogFn,
) {
const { functionArgs, contractArtifact, isPrivate } = await prepTx(
contractArtifactPath,
functionName,
functionArgsIn,
log,
);

if (!isPrivate) {
throw new Error(
'Cannot create an authwit for a public function. To allow a third party to call a public function, please authorize the action via the authorize-action command',
);
}

const contract = await Contract.at(contractAddress, contractArtifact, wallet);
const action = contract.methods[functionName](...functionArgs);

const witness = await wallet.createAuthWit({ caller, action });

log(`Created authorization witness for action ${functionName} on contract ${contractAddress} for caller ${caller}`);

return witness;
}
Loading

0 comments on commit f6362ea

Please sign in to comment.