Skip to content

Commit

Permalink
chore(acceptance): add tests for PSM to z:acceptance
Browse files Browse the repository at this point in the history
Refs: Agoric/BytePitchPartnerEng#23

fix(acceptance-psm): address change requests
  • Loading branch information
anilhelvaci committed Oct 25, 2024
1 parent 823c8d1 commit d50ed58
Show file tree
Hide file tree
Showing 6 changed files with 1,252 additions and 364 deletions.
3 changes: 2 additions & 1 deletion a3p-integration/proposals/z:acceptance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/internal": "0.3.3-dev-5676146.0",
"@agoric/ertp": "dev",
"@agoric/internal": "dev",
"@agoric/synthetic-chain": "^0.3.0",
"@endo/errors": "^1.2.2",
"@endo/far": "^1.1.5",
Expand Down
274 changes: 274 additions & 0 deletions a3p-integration/proposals/z:acceptance/psm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
/* eslint-env node */
/**
* @file The goal of this file is to implement a set of tests to make sure PSM works properly
*
* Here are the steps we want to take;
* 1 - Change swap fees and mint limit according to "psmTestSpecs" below
* 2 - Create a new user using agd.keys
* 3 - Fund new user with a stable coin from the VALIDATOR
* - Do not provision manually
* 4 - Make sure new user is able to mint IST from PSM (fees are applied)
* 5 - Make sure new user can pay their debt and get their anchor (fees are applied)
* 6 - Make sure mint limit is adhered
*/

import test from 'ava';
import {
getUser,
GOV1ADDR,
GOV2ADDR,
GOV3ADDR,
waitForBlock,
} from '@agoric/synthetic-chain';
import {
adjustBalancesIfNotProvisioned,
agopsPsm,
bankSend,
checkGovParams,
checkSwapExceedMintLimit,
checkSwapSucceeded,
checkUserInitializedSuccessfully,
getPsmMetrics,
implementPsmGovParamChange,
initializeNewUser,
maxMintBelowLimit,
} from './test-lib/psm-lib.js';
import { getBalances } from './test-lib/utils.js';

// Export these from synthetic-chain?
export const USDC_DENOM = process.env.USDC_DENOM
? process.env.USDC_DENOM
: 'no-denom';
export const PSM_PAIR = process.env.PSM_PAIR?.replace('.', '-');

const psmTestSpecs = {
govParams: {
giveMintedFeeVal: 10n, // in %
wantMintedFeeVal: 10n, // in %
mintLimit: 500n * 1_000_000n, // in IST
deadline: 1, // in minutes
},
psmInstance: `psm-${PSM_PAIR}`,
// @ts-expect-error we assume PSM_PAIR is set because of synthetic-chain environment
anchor: PSM_PAIR.split('-')[1],
newUser: {
name: 'new-psm-trader',
fund: {
denom: USDC_DENOM,
value: '300000000', // 300 USDC_axl
},
},
otherUser: {
name: 'gov1',
fund: {
denom: USDC_DENOM,
value: '1000000000', // 1000 USDC_axl
},
toIst: {
value: 500, // in IST
},
},
toIst: {
value: 50, // in IST
},
fromIst: {
value: 50, // in USDC_axl
},
};

test.serial('change gov params', async t => {
await implementPsmGovParamChange(
{
address: GOV1ADDR,
instanceName: psmTestSpecs.psmInstance,
newParams: psmTestSpecs.govParams,
deadline: psmTestSpecs.govParams.deadline,
},
{ committeeAddrs: [GOV1ADDR, GOV2ADDR, GOV3ADDR], position: 0 },
);

// Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in
await waitForBlock(3);
await checkGovParams(
t,
{
GiveMintedFee: {
type: 'ratio',
value: {
numerator: { value: psmTestSpecs.govParams.giveMintedFeeVal * 100n }, // convert to bps
},
},
WantMintedFee: {
type: 'ratio',
value: {
numerator: { value: psmTestSpecs.govParams.wantMintedFeeVal * 100n }, // convert to bps
},
},
MintLimit: {
type: 'amount',
value: {
value: psmTestSpecs.govParams.mintLimit,
},
},
},
psmTestSpecs.psmInstance.split('-')[2],
);
});

test.serial('initialize new user', async t => {
const {
newUser: { name, fund },
} = psmTestSpecs;

await initializeNewUser(name, fund);
// Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in
await waitForBlock(3);

await checkUserInitializedSuccessfully(name, fund);
t.pass();
});

test.serial('swap into IST', async t => {
const {
newUser: { name },
anchor,
toIst,
govParams: { wantMintedFeeVal },
} = psmTestSpecs;

const psmTrader = await getUser(name);

const [metricsBefore, balances] = await Promise.all([
getPsmMetrics(anchor),
getBalances([psmTrader]),
]);

const balancesBefore = await adjustBalancesIfNotProvisioned(
balances,
psmTrader,
);
t.log('METRICS', metricsBefore);
t.log('BALANCES', balancesBefore);

await agopsPsm(psmTrader, [
'swap',
'--pair',
process.env.PSM_PAIR,
'--wantMinted',
toIst.value,
'--feePct',
wantMintedFeeVal,
]);
await waitForBlock(5);

await checkSwapSucceeded(t, metricsBefore, balancesBefore, {
wantMinted: toIst.value,
trader: psmTrader,
fee: Number(wantMintedFeeVal) / 100, // fee has to be between 0 and 1
anchor,
});
});

test.serial('swap out of IST', async t => {
const {
newUser: { name },
anchor,
fromIst,
govParams: { giveMintedFeeVal },
} = psmTestSpecs;

const psmTrader = await getUser(name);

const [metricsBefore, balancesBefore] = await Promise.all([
getPsmMetrics(anchor),
getBalances([psmTrader]),
]);

t.log('METRICS', metricsBefore);
t.log('BALANCES', balancesBefore);

await agopsPsm(psmTrader, [
'swap',
'--pair',
process.env.PSM_PAIR,
'--giveMinted',
fromIst.value,
'--feePct',
giveMintedFeeVal,
]);
await waitForBlock(5);

await checkSwapSucceeded(t, metricsBefore, balancesBefore, {
giveMinted: fromIst.value,
trader: psmTrader,
fee: Number(giveMintedFeeVal) / 100, // fee has to be between 0 and 1
anchor,
});
});

test.serial('mint limit is adhered', async t => {
const {
otherUser: {
fund: { denom, value },
name,
},
govParams,
anchor,
} = psmTestSpecs;

// Fund other user
const otherAddr = await getUser(name);
await bankSend(otherAddr, `${value}${denom}`);

// Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in
await waitForBlock(3);

const [metricsBefore, balancesBefore] = await Promise.all([
getPsmMetrics(anchor),
getBalances([otherAddr]),
]);

t.log('METRICS', metricsBefore);
t.log('BALANCES', balancesBefore);

const { maxMintableValue, wantFeeValue } = await maxMintBelowLimit(anchor);
const maxMintFeesAccounted = Math.floor(
maxMintableValue * (1 - wantFeeValue),
);
t.log({ maxMintableValue, wantFeeValue, maxMintFeesAccounted });

// Send a swap, should fail because mint limit is exceeded
await agopsPsm(otherAddr, [
'swap',
'--pair',
process.env.PSM_PAIR,
'--wantMinted',
maxMintFeesAccounted / 1000000 + 2, // Make sure we exceed the limit
'--feePct',
govParams.wantMintedFeeVal,
]);
await waitForBlock(5);

// Now check if failed with correct error message
await checkSwapExceedMintLimit(t, otherAddr, metricsBefore);

// Send another swap offer, this time should succeed
await agopsPsm(otherAddr, [
'swap',
'--pair',
process.env.PSM_PAIR,
'--wantMinted',
maxMintFeesAccounted / 1000000,
'--feePct',
govParams.wantMintedFeeVal,
]);
await waitForBlock(5);

// Make sure swap succeeded
await checkSwapSucceeded(t, metricsBefore, balancesBefore, {
wantMinted: maxMintFeesAccounted / 1000000,
trader: otherAddr,
fee: Number(govParams.wantMintedFeeVal) / 100, // fee has to be between 0 and 1
anchor,
});
});
Loading

0 comments on commit d50ed58

Please sign in to comment.