Skip to content

Commit

Permalink
feat(fast-usdc): operator attest cli command
Browse files Browse the repository at this point in the history
using a LegibleCapData blob arg
  • Loading branch information
dckc committed Dec 4, 2024
1 parent 5d4f84c commit 448aa3a
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 5 deletions.
38 changes: 33 additions & 5 deletions packages/fast-usdc/src/cli/operator-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
* @import {Command} from 'commander';
* @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
* @import {ExecuteOfferAction} from '@agoric/smart-wallet/src/smartWallet.js';
* @import {OperatorKit} from '../exos/operator-kit.js';
*/

import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
import { mustMatch } from '@agoric/internal';
import { INVITATION_MAKERS_DESC } from '../exos/transaction-feed.js';
import { CctpTxEvidenceShape } from '../type-guards.js';
import { outputActionAndHint } from './bridge-action.js';
import { fromExternalConfig } from '../utils/config-marshal.js';

/** @param {string} arg */
const parseCCTPEvidence = arg => {
const evidence = fromExternalConfig(JSON.parse(arg), {});
mustMatch(evidence, CctpTxEvidenceShape);
return evidence;
};

/**
* @param {Command} program
Expand Down Expand Up @@ -64,11 +75,28 @@ export const addOperatorCommands = (
.command('attest')
.description('Attest to an observed Fast USDC transfer')
.requiredOption('--previousOfferId <string>', 'Offer id', String)
.action(async options => {
const { previousOfferId } = options;
console.error(
'TODO: Implement attest logic for request:',
previousOfferId,
.requiredOption('--evidence <json>', 'CCTP evidence', parseCCTPEvidence)
.option('--offerId <string>', 'Offer id', String, `operatorAttest-${now()}`)
.action(async opts => {
const { previousOfferId, evidence } = opts;

/** @type {OfferSpec} */
const offer = {
id: opts.offerId,
invitationSpec: {
source: 'continuing',
previousOffer: previousOfferId,
/** @type {string & keyof OperatorKit['invitationMakers'] } */
invitationMakerName: 'SubmitEvidence',
/** @type {Parameters<OperatorKit['invitationMakers']['SubmitEvidence']> } */
invitationArgs: [evidence],
},
proposal: {},
};

outputActionAndHint(
{ method: 'executeOffer', offer },
{ stderr, stdout },
);
});

Expand Down
96 changes: 96 additions & 0 deletions packages/fast-usdc/test/cli/operator-commands.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import test from 'ava';
import { Command } from 'commander';
import type { Passable } from '@endo/pass-style';
import { addOperatorCommands } from '../../src/cli/operator-commands.js';
import { MockCctpTxEvidences } from '../fixtures.js';
import { toExternalConfig } from '../../src/utils/config-marshal.js';

export const flags = (
record: Record<string, string | number | undefined>,
): string[] => {
// @ts-expect-error undefined is filtered out
const skipUndef: [string, string][] = Object.entries(record).filter(
([_k, v]) => v !== undefined,
);
return skipUndef.map(([k, v]) => [`--${k}`, v]).flat();
};

test('fast-usdc operator attest sub-command', async t => {
const evidence = harden(
MockCctpTxEvidences.AGORIC_PLUS_DYDX(),
) as unknown as Passable;
const argv = [
...`node fast-usdc operator attest`.split(' '),
...flags({
previousOfferId: 123,
evidence: JSON.stringify(toExternalConfig(evidence, {})),
}),
];
const program = new Command();
program.exitOverride();
const out = [] as string[];
const err = [] as string[];

addOperatorCommands(program, {
fetch: null as unknown as Window['fetch'],
stdout: {
write: txt => {
out.push(txt);
return true;
},
} as unknown as typeof process.stdout,
stderr: {
write: txt => {
err.push(txt);
return true;
},
} as unknown as typeof process.stderr,
env: {},
now: () => 1234,
});

await program.parseAsync(argv);

t.deepEqual(out, [
JSON.stringify({
body: `#${JSON.stringify({
method: 'executeOffer',
offer: {
id: 'operatorAttest-1234',
invitationSpec: {
invitationArgs: [
{
aux: {
forwardingChannel: 'channel-21',
recipientAddress:
'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
},
blockHash:
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee699',
blockNumber: '+21037669',
blockTimestamp: '+1730762099',
chainId: 1,
tx: {
amount: '+300000000',
forwardingAddress:
'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelktz',
},
txHash:
'0xd81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799',
},
],
invitationMakerName: 'SubmitEvidence',
previousOffer: '123',
source: 'continuing',
},
proposal: {},
},
})}`,
slots: [],
}),
'\n',
]);
t.deepEqual(err, [
'Now use `agoric wallet send ...` to sign and broadcast the offer.\n',
]);
});

0 comments on commit 448aa3a

Please sign in to comment.