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

test(a3p-integration): Update "swap into IST" to force the default gas limit #10451

Merged
1 change: 1 addition & 0 deletions a3p-integration/proposals/z:acceptance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@endo/far": "^1.1.5",
"@endo/init": "^1.1.4",
"@endo/marshal": "^1.5.3",
"agoric": "dev",
"ava": "^6.1.2",
"execa": "^9.3.1",
"tsx": "^4.17.0"
Expand Down
5 changes: 3 additions & 2 deletions a3p-integration/proposals/z:acceptance/psm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
initializeNewUser,
maxMintBelowLimit,
psmSwap,
sendOfferAgd,
} from './test-lib/psm-lib.js';
import { getBalances } from './test-lib/utils.js';

Expand Down Expand Up @@ -128,7 +129,7 @@ test.serial('initialize new user', async t => {
t.pass();
});

test.serial('swap into IST', async t => {
test.serial('swap into IST using agd with default gas', async t => {
const {
newUser: { name },
anchor,
Expand Down Expand Up @@ -161,7 +162,7 @@ test.serial('swap into IST', async t => {
'--feePct',
wantMintedFeeVal,
],
psmSwapIo,
{ ...psmSwapIo, sendOffer: sendOfferAgd },
);

await checkSwapSucceeded(t, metricsBefore, balancesBefore, {
Expand Down
128 changes: 113 additions & 15 deletions a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-env node */

import { execa } from 'execa';
import { getNetworkConfig } from 'agoric/src/helpers.js';
import {
boardSlottingMarshaller,
makeFromBoard,
Expand All @@ -26,6 +28,22 @@ import fsp from 'node:fs/promises';
import { NonNullish } from './errors.js';
import { getBalances } from './utils.js';

/** @import {Result as ExecaResult, ExecaError} from 'execa'; */
/**
* @typedef {ExecaResult & { all: string } & (
* | { failed: false }
* | Pick<
* ExecaError & { failed: true },
* 'failed',
* | 'shortMessage'
* | 'cause'
* | 'exitCode'
* | 'signal'
* | 'signalDescription'
* >
* )} SendOfferResult
*/

// Export these from synthetic-chain?
const USDC_DENOM = NonNullish(process.env.USDC_DENOM);
const PSM_PAIR = NonNullish(process.env.PSM_PAIR).replace('.', '-');
Expand Down Expand Up @@ -356,46 +374,126 @@ export const initializeNewUser = async (name, fund, io) => {
};

/**
* Similar to https://github.com/Agoric/agoric-3-proposals/blob/422b163fecfcf025d53431caebf6d476778b5db3/packages/synthetic-chain/src/lib/commonUpgradeHelpers.ts#L123-L139
* However, in the case where "address" is not provisioned "agoric wallet send" is needed because
* "agops perf satisfaction" tries to follow ":published.wallet.${address}" which blocks the execution because no such path exists in
* vstorage. In situations like this "agoric wallet send" seems a better choice as it doesn't depend on following user's vstorage wallet path
* Similar to
* https://github.com/Agoric/agoric-3-proposals/blob/422b163fecfcf025d53431caebf6d476778b5db3/packages/synthetic-chain/src/lib/commonUpgradeHelpers.ts#L123-L139
* However, for an address that is not provisioned, `agoric wallet send` is
* needed because `agops perf satisfaction` hangs when trying to follow
* nonexistent vstorage path ":published.wallet.${address}".
*
* @param {string} address
* @param {Promise<string>} offerPromise
* @returns {Promise<SendOfferResult>}
*/
export const sendOfferAgoric = async (address, offerPromise) => {
const offerPath = await mkTemp('agops.XXX');
const offer = await offerPromise;
await fsp.writeFile(offerPath, offer);

await agoric.wallet(
'--keyring-backend=test',
'send',
'--offer',
offerPath,
'--from',
address,
const [settlement] = await Promise.allSettled([
execa({
all: true,
})`agoric wallet --keyring-backend=test send --offer ${offerPath} --from ${address} --verbose`,
]);
return settlement.status === 'fulfilled'
? settlement.value
: settlement.reason;
};

/**
* A variant of {@link sendOfferAgoric} that uses `agd` directly to e.g.
* control gas calculation.
*
* @param {string} address
* @param {Promise<string>} offerPromise
* @returns {Promise<SendOfferResult>}
*/
export const sendOfferAgd = async (address, offerPromise) => {
const offer = await offerPromise;
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
const { chainName, rpcAddrs } = networkConfig;
const args = [].concat(
[`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`],
[`--keyring-backend=test`, `--from=${address}`],
['tx', 'swingset', 'wallet-action', '--allow-spend', offer],
'--yes',
'-bblock',
'-ojson',
);

const [settlement] = await Promise.allSettled([
execa('agd', args, { all: true }),
]);

// Upon successful exit, verify that the *output* also indicates success.
// cf. https://github.com/Agoric/agoric-sdk/blob/master/packages/agoric-cli/src/lib/wallet.js
if (settlement.status === 'fulfilled') {
const result = settlement.value;
try {
const tx = JSON.parse(result.stdout);
if (tx.code !== 0) {
return { ...result, failed: true, shortMessage: `code ${tx.code}` };
}
} catch (err) {
return {
...result,
failed: true,
shortMessage: 'unexpected output',
cause: err,
};
}
}

return settlement.status === 'fulfilled'
? settlement.value
: settlement.reason;
};

/**
* @param {string} address
* @param {Array<any>} params
* @param {{
* follow: (...params: string[]) => Promise<object>;
* sendOffer?: (address: string, offerPromise: Promise<string>) => Promise<SendOfferResult>;
* setTimeout: typeof global.setTimeout;
* now: () => number
* }} io
*/
export const psmSwap = async (address, params, io) => {
const now = io.now();
const offerId = `${address}-psm-swap-${now}`;
const { now, sendOffer = sendOfferAgoric, ...waitIO } = io;
const offerId = `${address}-psm-swap-${now()}`;
const newParams = ['psm', ...params, '--offerId', offerId];
const offerPromise = executeCommand(agopsLocation, newParams);
await sendOfferAgoric(address, offerPromise);
const sendResult = await sendOffer(address, offerPromise);
if (sendResult.failed) {
const {
command,
durationMs,
shortMessage,
cause,
exitCode,
signal,
signalDescription,
all: output,
} = sendResult;
const summary = {
command,
durationMs,
shortMessage,
cause,
exitCode,
signal,
signalDescription,
output,
};
console.error('psmSwap tx send failed', summary);
throw Error(
`psmSwap tx send failed: ${JSON.stringify({ exitCode, signal, signalDescription })}`,
{ cause },
);
}
console.log('psmSwap tx send results', sendResult.all);

await waitUntilOfferResult(address, offerId, true, io, {
await waitUntilOfferResult(address, offerId, true, waitIO, {
errorMessage: `${offerId} not succeeded`,
});
};
Expand Down
Loading
Loading