Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client support for Fast USDC #10735

Merged
merged 9 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion multichain-testing/test/fast-usdc/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IBCChannelID } from '@agoric/vats';
import type { FeedPolicy } from '@agoric/fast-usdc/src/types.js';
import type { FeedPolicy } from '@agoric/fast-usdc';

export const oracleMnemonics = {
oracle1:
Expand Down
2 changes: 1 addition & 1 deletion multichain-testing/tools/noble-tools.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IBCChannelID } from '@agoric/vats';
import type { ExecSync } from './agd-lib.js';
import type { ChainAddress } from '@agoric/orchestration';
import type { NobleAddress } from '@agoric/fast-usdc/src/types.js';
import type { NobleAddress } from '@agoric/fast-usdc';

const kubectlBinary = 'kubectl';
const noblePod = 'noblelocal-genesis-0';
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/src/controller/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export async function makeSwingsetController(
*
* The first `controller.run()` after this call will delete all
* the old vat's state at once, unless you use a
* [`runPolicy`](../docs/run-policy.md) to rate-limit cleanups.
* [`runPolicy`](../../docs/run-policy.md) to rate-limit cleanups.
*
* @param {VatID} vatID
* @param {SwingSetCapData} reasonCD
Expand Down
47 changes: 15 additions & 32 deletions packages/boot/test/fast-usdc/fast-usdc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { TestFn } from 'ava';
import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import { configurations } from '@agoric/fast-usdc/src/utils/deploy-config.js';
import { MockCctpTxEvidences } from '@agoric/fast-usdc/test/fixtures.js';
import { Offers } from '@agoric/fast-usdc/src/clientSupport.js';
import { documentStorageSchema } from '@agoric/governance/tools/storageDoc.js';
import { BridgeId, NonNullish } from '@agoric/internal';
import { unmarshalFromVstorage } from '@agoric/internal/src/marshal.js';
Expand Down Expand Up @@ -217,22 +218,13 @@ test.serial('LP deposits', async t => {
},
});

await lp.sendOffer({
id: 'deposit-lp-1',
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeDepositInvitation', []]],
},
proposal: {
give: {
USDC: { brand: usdc, value: 150_000_000n },
},
want: {
PoolShare: { brand: fastLP, value: 150_000_000n },
},
},
});
await lp.sendOffer(
Offers.fastUsdc.Deposit(agoricNamesRemotes, {
offerId: 'deposit-lp-1',
fastLPAmount: 150_000_000n,
usdcAmount: 150_000_000n,
}),
);
await eventLoopIteration();

const { getOutboundMessages } = t.context.bridgeUtils;
Expand Down Expand Up @@ -486,22 +478,13 @@ test.serial('LP withdraws', async t => {
},
});

await lp.sendOffer({
id: 'withdraw-lp-1',
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeWithdrawInvitation', []]],
},
proposal: {
give: {
PoolShare: { brand: fastLP, value: 369_000n },
},
want: {
USDC: { brand: usdc, value: 369_000n },
},
},
});
await lp.sendOffer(
Offers.fastUsdc.Withdraw(agoricNamesRemotes, {
offerId: 'withdraw-lp-1',
fastLPAmount: 369_000n,
usdcAmount: 369_000n,
}),
);
await eventLoopIteration();

const { denom: usdcDenom } = agoricNamesRemotes.vbankAsset.USDC;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { makeHelpers } from '@agoric/deploy-script-support';
/**
* @import {CoreEvalBuilder, DeployScriptFunction} from '@agoric/deploy-script-support/src/externalTypes.js'
* @import {ParseArgsConfig} from 'node:util'
* @import {FastUSDCConfig} from '@agoric/fast-usdc/src/types.js'
* @import {FastUSDCConfig} from '@agoric/fast-usdc';
*/

/** @type {ParseArgsConfig['options']} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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 {FastUSDCConfig, FeedPolicy} from '@agoric/fast-usdc';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: there's a semicolon here but not for the lines above. I wonder if eslint/prettier should have a rule for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think ESlint has a linter for it. There's a Prettier plugin for JSDoc but it's quite buggy

*/

const { keys } = Object;
Expand Down
11 changes: 10 additions & 1 deletion packages/client-utils/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
CurrentWalletRecord,
UpdateRecord,
} from '@agoric/smart-wallet/src/smartWallet.js';
import type { ContractRecord, PoolMetrics } from '@agoric/fast-usdc';

// For static string key types. String template matching has to be in the ternary below.
type PublishedTypeMap = {
Expand All @@ -34,4 +35,12 @@ export type TypedPublished<T extends string> = T extends keyof PublishedTypeMap
? OutcomeRecord
: T extends `vaultFactory.managers.manager${number}.metrics`
? VaultManagerMetrics
: unknown;
: T extends 'agoricNames.instance'
? Array<[string, Instance]>
: T extends 'agoricNames.brand'
? Array<[string, Brand]>
Comment on lines +38 to +41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of the relevant code expects not just a Brand but a Brand<'nat'> or Brand<'set'>.

const { USDC, FastLP } = await agoricNamesQ(vstorageClient).brands('nat');

const { Invitation } = await agoricNamesQ(vsc).brands('set');

I suppose one can add as Brand<'nat'>, but it almost defeats the point. It's also helpful to reassemble the entries into a record. Do you want to add helpers for this sort of thing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed this is low value because you'll often want the kind of brand. It's still true tho so I think it's worth having here.

: T extends 'fastUsdc'
? ContractRecord
: T extends 'fastUsdc.poolMetrics'
? PoolMetrics
Comment on lines +42 to +45
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still feels strange for client-utils to depend on fast-usdc. Should it depend on dapp-offer-up and dapp-agoric-basics likewise?

It seems like fast-usdc should extend the type from client-utils.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is weird but ok for now. We'll have to solve it for #10811

: unknown;
1 change: 1 addition & 0 deletions packages/fast-usdc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"src",
"tools"
],
"main": "src/main.js",
"bin": {
"fast-usdc": "./src/cli/bin.js"
},
Expand Down
55 changes: 11 additions & 44 deletions packages/fast-usdc/src/cli/lp-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '@agoric/zoe/src/contractSupport/ratio.js';
import { InvalidArgumentError } from 'commander';
import { outputActionAndHint } from './bridge-action.js';
import { Offers } from '../clientSupport.js';

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

Expand Down Expand Up @@ -96,31 +97,14 @@ export const addLPCommands = (

const usdcAmount = parseUSDCAmount(opts.amount, usdc);

/** @type {import('../types.js').PoolMetrics} */
// @ts-expect-error it treats this as "unknown"
const metrics = await swk.readPublished('fastUsdc.poolMetrics');
const fastLPAmount = floorDivideBy(usdcAmount, metrics.shareWorth);

/** @type {USDCProposalShapes['deposit']} */
const proposal = {
give: {
USDC: usdcAmount,
},
want: {
PoolShare: fastLPAmount,
},
};

/** @type {OfferSpec} */
const offer = {
id: opts.offerId,
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeDepositInvitation', []]],
},
proposal,
};
const offer = Offers.fastUsdc.Deposit(swk.agoricNames, {
offerId: opts.offerId,
fastLPAmount: fastLPAmount.value,
usdcAmount: usdcAmount.value,
});

/** @type {ExecuteOfferAction} */
const bridgeAction = {
Expand Down Expand Up @@ -156,31 +140,14 @@ export const addLPCommands = (

const usdcAmount = parseUSDCAmount(opts.amount, usdc);

/** @type {import('../types.js').PoolMetrics} */
// @ts-expect-error it treats this as "unknown"
const metrics = await swk.readPublished('fastUsdc.poolMetrics');
const fastLPAmount = ceilDivideBy(usdcAmount, metrics.shareWorth);

/** @type {USDCProposalShapes['withdraw']} */
const proposal = {
give: {
PoolShare: fastLPAmount,
},
want: {
USDC: usdcAmount,
},
};

/** @type {OfferSpec} */
const offer = {
id: opts.offerId,
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeWithdrawInvitation', []]],
},
proposal,
};
const offer = Offers.fastUsdc.Withdraw(swk.agoricNames, {
offerId: opts.offerId,
fastLPAmount: fastLPAmount.value,
usdcAmount: usdcAmount.value,
});

outputActionAndHint(
{ method: 'executeOffer', offer },
Expand Down
98 changes: 98 additions & 0 deletions packages/fast-usdc/src/clientSupport.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to also add functions for accepting the operator invitation and submitting evidence?

Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// @ts-check
import { assertAllDefined } from '@agoric/internal';

/**
* @import {USDCProposalShapes} from './pool-share-math.js';
*/

/**
* @param {Pick<
* import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's please stop using BoardRemote and hence AgoricNamesRemotes. Just use the ordinary types like Brand.

ref

Copy link
Member Author

@turadg turadg Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree eventually but can you accept that as being out of scope? The inter-protocol clientSupport uses AgoricNamesRemotes and I think if we're going to change it we should do both. #10491 looks like a good issue to schedule that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we're going to change it we should do both.

I prefer the "platform is fixed" idea where fast-usdc is independent of inter-protocol. But I can live with this.

* 'brand'
* >} agoricNames
* @param {object} opts
* @param {string} opts.offerId
* @param {bigint} opts.fastLPAmount
* @param {bigint} opts.usdcAmount
* @returns {import('@agoric/smart-wallet/src/offers.js').OfferSpec}
*/
const makeDepositOffer = ({ brand }, { offerId, fastLPAmount, usdcAmount }) => {
assertAllDefined({ offerId, fastLPAmount, usdcAmount });

return {
id: offerId,
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeDepositInvitation']],
},
/** @type {USDCProposalShapes['deposit']} */
// @ts-expect-error https://github.com/Agoric/agoric-sdk/issues/10491
proposal: {
give: {
USDC: {
brand: brand.USDC,
value: usdcAmount,
},
},
want: {
PoolShare: {
brand: brand.FastLP,
value: fastLPAmount,
},
},
},
};
};

/**
* @param {Pick<
* import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes,
* 'brand'
* >} agoricNames
* @param {object} opts
* @param {string} opts.offerId
* @param {bigint} opts.fastLPAmount
* @param {bigint} opts.usdcAmount
* @returns {import('@agoric/smart-wallet/src/offers.js').OfferSpec}
*/
const makeWithdrawOffer = (
{ brand },
{ offerId, fastLPAmount, usdcAmount },
) => ({
id: offerId,
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeWithdrawInvitation']],
},
proposal: {
give: {
PoolShare: {
// @ts-expect-error https://github.com/Agoric/agoric-sdk/issues/10491
brand: brand.FastLP,
value: fastLPAmount,
},
},
want: {
USDC: {
// @ts-expect-error https://github.com/Agoric/agoric-sdk/issues/10491
brand: brand.USDC,
value: usdcAmount,
},
},
},
});

/**
* @satisfies {Record<
* string,
* Record<string, import('@agoric/smart-wallet/src/types.js').OfferMaker>
* >}
*/
export const Offers = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason to export this Offers structure rather than the functions makeDepositOffer and such?

Copy link
Member Author

@turadg turadg Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have it handy but there was a PR for refactoring our tests to use these and it let you merge multiple of these into an Offers object with all the makers you needed.

Also this provides a way to enforce that they all satisfy OfferMaker.

fastUsdc: {
Deposit: makeDepositOffer,
Withdraw: makeWithdrawOffer,
},
};
2 changes: 1 addition & 1 deletion packages/fast-usdc/src/exos/advancer.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ export const prepareAdvancerKit = (
notifyFacet: M.remotable(),
borrowerFacet: M.remotable(),
poolAccount: M.remotable(),
settlementAddress: ChainAddressShape,
intermediateRecipient: M.opt(ChainAddressShape),
settlementAddress: M.opt(ChainAddressShape),
Comment on lines +294 to -295
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

What prompted it, I wonder?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't remember but I'm guessing some type feedback

}),
},
);
Expand Down
8 changes: 3 additions & 5 deletions packages/fast-usdc/src/fast-usdc.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const ADDRESSES_BAGGAGE_KEY = 'addresses';
* @import {Marshaller, StorageNode} from '@agoric/internal/src/lib-chainStorage.js'
* @import {Zone} from '@agoric/zone';
* @import {OperatorOfferResult} from './exos/transaction-feed.js';
* @import {CctpTxEvidence, FeeConfig, RiskAssessment} from './types.js';
* @import {OperatorKit} from './exos/operator-kit.js';
* @import {CctpTxEvidence, ContractRecord, FeeConfig} from './types.js';
*/

/**
Expand Down Expand Up @@ -75,10 +76,7 @@ const publishFeeConfig = async (node, marshaller, feeConfig) => {

/**
* @param {Remote<StorageNode>} contractNode
* @param {{
* poolAccount: ChainAddress['value'];
* settlementAccount: ChainAddress['value'];
* }} addresses
* @param {ContractRecord} addresses
*/
const publishAddresses = (contractNode, addresses) => {
return E(contractNode).setValue(JSON.stringify(addresses));
Expand Down
1 change: 1 addition & 0 deletions packages/fast-usdc/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './types.js';
6 changes: 6 additions & 0 deletions packages/fast-usdc/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export interface TransactionRecord extends CopyRecord {
status: TxStatus;
}

/** the record in vstorage at the path of the contract's node */
export interface ContractRecord extends CopyRecord {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name... does it refer to "the record you'll get from vstorage if you query the contract's node"?

docstring, please?

poolAccount: ChainAddress['value'];
settlementAccount: ChainAddress['value'];
}

export type LogFn = (...args: unknown[]) => void;

export interface PendingTx extends CctpTxEvidence {
Expand Down
2 changes: 1 addition & 1 deletion packages/fast-usdc/src/utils/deploy-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js';
import { ChainPolicies } from './chain-policies.js';

/**
* @import {FastUSDCConfig} from '@agoric/fast-usdc/src/types.js'
* @import {FastUSDCConfig} from '@agoric/fast-usdc';
* @import {Passable} from '@endo/marshal';
* @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration';
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/fast-usdc/test/cli/lp-commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ test('fast-usdc deposit command', async t => {
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeDepositInvitation', []]],
callPipe: [['makeDepositInvitation']],
},
proposal: {
give: {
Expand Down Expand Up @@ -106,7 +106,7 @@ test('fast-usdc withdraw command', async t => {
invitationSpec: {
source: 'agoricContract',
instancePath: ['fastUsdc'],
callPipe: [['makeWithdrawInvitation', []]],
callPipe: [['makeWithdrawInvitation']],
},
proposal: {
give: {
Expand Down
Loading
Loading