Skip to content

Commit

Permalink
test: add operators
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg committed Jan 14, 2025
1 parent 7191f0b commit da7c727
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 10 deletions.
1 change: 1 addition & 0 deletions a3p-integration/proposals/f:fast-usdc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add-operators
9 changes: 2 additions & 7 deletions a3p-integration/proposals/f:fast-usdc/deploy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@
/* eslint-env node */
import test from 'ava';
import '@endo/init/legacy.js'; // axios compat
import { makeSmartWalletKit } from '@agoric/client-utils';
import { LOCAL_CONFIG, makeSmartWalletKit } from '@agoric/client-utils';

const io = {
delay: ms => new Promise(resolve => setTimeout(() => resolve(undefined), ms)),
fetch: global.fetch,
};
const networkConfig = {
rpcAddrs: ['http://0.0.0.0:26657'],
chainName: 'agoriclocal',
};

test('fastUsdc is in agoricNames.instance', async t => {
const { agoricNames } = await makeSmartWalletKit(io, networkConfig);
const { agoricNames } = await makeSmartWalletKit(io, LOCAL_CONFIG);

t.log('agoricNames.instance keys', Object.keys(agoricNames.instance));
t.truthy(agoricNames.instance.fastUsdc);
Expand Down
78 changes: 78 additions & 0 deletions a3p-integration/proposals/f:fast-usdc/operators.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* eslint-env node */
import unknownTest from 'ava';

import '@endo/init/legacy.js'; // axios compat

import { LOCAL_CONFIG, makeVstorageKit } from '@agoric/client-utils';
import { evalBundles, waitForBlock } from '@agoric/synthetic-chain';

// XXX ~copied to not take a dependency on Zoe
/**
* @typedef {object} InvitationDetails
* @property {unknown} installation
* @property {unknown} instance
* @property {InvitationHandle} handle
* @property {string} description
* @property {Record<string, any>} [customDetails]
*/

/**
* @import {VstorageKit} from '@agoric/client-utils';
*/

const test = /** @type {import('ava').TestFn<{ vstorageKit: VstorageKit}>} */ (
unknownTest
);

const ADD_OPERATORS_DIR = 'add-operators';

/**
* @typedef {import('@agoric/ertp').NatAmount} NatAmount
* @typedef {{
* allocations: { Fee: NatAmount, USD_LEMONS: NatAmount },
* }} ReserveAllocations
*/

test.before(async t => {
const vstorageKit = makeVstorageKit({ fetch }, LOCAL_CONFIG);

t.context = {
vstorageKit,
};
});

test.serial('add operators', async t => {
const { vstorageKit } = t.context;

const walletPath =
// account mem3 in test of crabble-start proposal (64)
// This must match the oracleNew value in the add-operators builder argument
'wallet.agoric1hmdue96vs0p6zj42aa26x6zrqlythpxnvgsgpr.current';

const readInvitationsPurseBalance = async () => {
const curr = await vstorageKit.readPublished(walletPath);
return /** @type {InvitationDetails[]} */ (curr.purses[0].balance.value);
};

let numInvitationsBefore = 0;
{
const invBalance = await readInvitationsPurseBalance();
numInvitationsBefore = invBalance.length;
t.false(
invBalance.some(inv => inv.description === 'oracle operator invitation'),
);
}

await evalBundles(ADD_OPERATORS_DIR);
// give time for the invitations to be deposited
await waitForBlock(5);

{
const invBalance = await readInvitationsPurseBalance();
console.log('after', invBalance);
t.is(invBalance.length, numInvitationsBefore + 1);
t.true(
invBalance.some(inv => inv.description === 'oracle operator invitation'),
);
}
});
3 changes: 2 additions & 1 deletion a3p-integration/proposals/f:fast-usdc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"agoricProposal": {
"source": "subdir",
"sdk-generate": [
"fast-usdc/start-fast-usdc.build.js submission --net A3P_INTEGRATION --noNoble"
"fast-usdc/start-fast-usdc.build.js submission --net A3P_INTEGRATION --noNoble",
"fast-usdc/add-operators.build.js add-operators --oracle oracleNew:agoric1hmdue96vs0p6zj42aa26x6zrqlythpxnvgsgpr"
],
"type": "/agoric.swingset.CoreEvalProposal"
},
Expand Down
51 changes: 49 additions & 2 deletions packages/boot/test/fast-usdc/fast-usdc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ test.serial('restart contract', async t => {
test.serial('replace operators', async t => {
const {
agoricNamesRemotes,
buildProposal,
evalProposal,
storage,
runUtils: { EV },
walletFactoryDriver: wfd,
Expand Down Expand Up @@ -521,6 +523,51 @@ test.serial('replace operators', async t => {
}
}

// TODO test adding new operators
// The naive approach is failing under XS. A new CoreEval may be necessary.
if (defaultManagerType === 'xs-worker') {
// XXX for some reason the code after this when run under XS fails with:
// message: 'unsettled value for "kp2526"',
return;
}

// Add some new oracle operator
const {
// any one would do
oracles: { gov1: address },
} = configurations.A3P_INTEGRATION;
const wallet = await wfd.provideSmartWallet(address);

const addOperators = buildProposal(
'@agoric/builders/scripts/fast-usdc/add-operators.build.js',
['--oracle', `gov1a3p:${address}`],
);
await evalProposal(addOperators);

await wallet.sendOffer({
id: 'claim-oracle-invitation',
invitationSpec: {
source: 'purse',
instance: agoricNamesRemotes.instance.fastUsdc,
description: 'oracle operator invitation',
},
proposal: {},
});
console.log('accepted invitation');

await wallet.sendOffer({
id: 'submit',
invitationSpec: {
source: 'continuing',
previousOffer: 'claim-oracle-invitation',
invitationMakerName: 'SubmitEvidence',
invitationArgs: [evidence],
},
proposal: {},
});
console.log('submitted price');
t.like(wallet.getLatestUpdateRecord(), {
status: {
id: 'submit',
result: 'inert; nothing should be expected from this offer',
},
});
});
83 changes: 83 additions & 0 deletions packages/builders/scripts/fast-usdc/add-operators.build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// @ts-check
import { makeHelpers } from '@agoric/deploy-script-support';
import { getManifestForAddOperators } from '@agoric/fast-usdc/src/add-operators.core.js';
import { toExternalConfig } from '@agoric/fast-usdc/src/utils/config-marshal.js';
import { configurations } from '@agoric/fast-usdc/src/utils/deploy-config.js';
import { Far } from '@endo/far';
import { parseArgs } from 'node:util';

/**
* @import {CoreEvalBuilder, DeployScriptFunction} from '@agoric/deploy-script-support/src/externalTypes.js';
* @import {ParseArgsConfig} from 'node:util';
* @import {FastUSDCConfig, FeedPolicy} from '@agoric/fast-usdc/src/types.js';
* @import {FastUSDCOpts} from './start-fast-usdc.build.js';
*/

const { keys } = Object;

/** @type {ParseArgsConfig['options']} */
const options = {
net: { type: 'string' },
oracle: { type: 'string', multiple: true },
};
const oraclesUsage = 'use --oracle name:address ...';

const crossVatContext = /** @type {const} */ ({
/** @type {Brand<'nat'>} */
USDC: Far('USDC Brand'),
});

/** @type {CoreEvalBuilder} */
export const defaultProposalBuilder = async (
powers,
/** @type {FastUSDCConfig} */ config,
) => {
return harden({
sourceSpec: '@agoric/fast-usdc/src/add-operators.core.js',
/** @type {[string, Parameters<typeof getManifestForAddOperators>[1]]} */
getManifestCall: [
getManifestForAddOperators.name,
{
options: toExternalConfig(config, crossVatContext),
},
],
});
};

/** @type {DeployScriptFunction} */
export default async (homeP, endowments) => {
const { writeCoreEval } = await makeHelpers(homeP, endowments);
const { scriptArgs } = endowments;

/** @type {{ values: FastUSDCOpts }} */
// @ts-expect-error ensured by options
const {
values: { oracle: oracleArgs, net },
} = parseArgs({ args: scriptArgs, options });

const parseOracleArgs = () => {
if (net) {
if (!(net in configurations)) {
throw Error(`${net} not in ${keys(configurations)}`);
}
return configurations[net].oracles;
}
if (!oracleArgs) throw Error(oraclesUsage);
return Object.fromEntries(
oracleArgs.map(arg => {
const result = arg.match(/(?<name>[^:]+):(?<address>.+)/);
if (!(result && result.groups)) throw Error(oraclesUsage);
const { name, address } = result.groups;
return [name, address];
}),
);
};

const config = harden({
oracles: parseOracleArgs(),
});

await writeCoreEval('add-operators', utils =>
defaultProposalBuilder(utils, config),
);
};
63 changes: 63 additions & 0 deletions packages/fast-usdc/src/add-operators.core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { makeTracer } from '@agoric/internal';
import { inviteOracles } from './utils/core-eval.js';

/**
* @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js'
* @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js'
* @import {LegibleCapData} from './utils/config-marshal.js'
* @import {FastUSDCConfig} from './types.js'
* @import {FastUSDCCorePowers, FastUSDCKit} from './start-fast-usdc.core.js';
*/

const trace = makeTracer('FUSD-AddOperators', true);

/**
* @throws if oracle smart wallets are not yet provisioned
*
* @param {BootstrapPowers & FastUSDCCorePowers } powers
* @param {{ options: LegibleCapData<FastUSDCConfig> }} config
*/
export const addOperators = async (
{ consume: { namesByAddress, fastUsdcKit } },
config,
) => {
trace(addOperators.name);

const kit = await fastUsdcKit;

const { creatorFacet } = kit;

trace(config);

// @ts-expect-error XXX LegibleCapData typedef
const { oracles } = config.options.structure;

await inviteOracles({ creatorFacet, namesByAddress }, oracles);
};
harden(addOperators);

/**
* @param {{
* restoreRef: (b: ERef<ManifestBundleRef>) => Promise<Installation>;
* }} utils
* @param {{
* options: LegibleCapData<FastUSDCConfig>;
* }} param1
*/
export const getManifestForAddOperators = ({ restoreRef: _ }, { options }) => {
return {
/** @type {BootstrapManifest} */
manifest: {
[addOperators.name]: {
consume: {
fastUsdcKit: true,

// widely shared: name services
agoricNames: true,
namesByAddress: true,
},
},
},
options,
};
};

0 comments on commit da7c727

Please sign in to comment.