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

8961 vaults acceptance #9954

Closed
wants to merge 6 commits into from
Closed
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
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,14 @@ typings/
# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity
# Yarn (https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored)
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# dotenv environment variables file
.env
Expand Down
213 changes: 213 additions & 0 deletions a3p-integration/proposals/z:acceptance/lib/vaults.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/* eslint-disable @jessie.js/safe-await-separator */
/* eslint-env node */

import { strict as assert } from 'node:assert';

import {
addUser,
agops,
agoric,
ATOM_DENOM,
executeOffer,
GOV1ADDR,
GOV2ADDR,
GOV3ADDR,
provisionSmartWallet,
waitForBlock,
} from '@agoric/synthetic-chain';

const govAccounts = [GOV1ADDR, GOV2ADDR, GOV3ADDR];

export const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 }

const DEFAULT_TIMEOUT = 65000;

const proposeNewAuctionParams = async (
address: string,
startFequency: any,
clockStep: any,
priceLockPeriod: any,
) => {
const charterAcceptOfferId = await agops.ec(
'find-continuing-id',
'--for',
`${'charter\\ member\\ invitation'}`,
'--from',
address,
);

return executeOffer(
address,
agops.auctioneer(
'proposeParamChange',
'--charterAcceptOfferId',
charterAcceptOfferId,
'--start-frequency',
startFequency,
'--clock-step',
clockStep,
'--price-lock-period',
priceLockPeriod,
),
);
};

const voteForNewParams = (accounts: string[], position: number) => {
console.log('ACTIONS voting for position', position, 'using', accounts);
return Promise.all(
accounts.map((account: string) =>
agops.ec('vote', '--forPosition', position, '--send-from', account),
),
);
};

const paramChangeOfferGeneration = async (
previousOfferId: string,
voteDur: number,
debtLimit: number | bigint,
) => {
const voteDurSec = BigInt(voteDur);
const debtLimitValue = BigInt(debtLimit) * ISTunit;
const toSec = (ms: number) => BigInt(Math.round(ms / 1000));

const id = `propose-${Date.now()}`;
const deadline = toSec(Date.now()) + voteDurSec;

const zip = (xs: any[], ys: { [x: string]: any }) =>
xs.map((x: any, i: string | number) => [x, ys[i]]);
const fromSmallCapsEntries = (txt: string) => {
const { body, slots } = JSON.parse(txt);
const theEntries = zip(JSON.parse(body.slice(1)), slots).map(
([[name, ref], boardID]) => {
const iface = ref.replace(/^\$\d+\./, '');
return [name, { iface, boardID }];
},
);
return Object.fromEntries(theEntries);
};

const slots = [] as string[]; // XXX global mutable state
const smallCaps = {
Nat: (n: any) => `+${n}`,
// XXX mutates obj
ref: (obj: { ix: string; boardID: any; iface: any }) => {
if (obj.ix) return obj.ix;
const ix = slots.length;
slots.push(obj.boardID);
obj.ix = `$${ix}.Alleged: ${obj.iface}`;
return obj.ix;
},
};

const instance = fromSmallCapsEntries(
await agoric.follow('-lF', ':published.agoricNames.instance', '-o', 'text'),
);
assert(instance.VaultFactory);

const brand = fromSmallCapsEntries(
await agoric.follow('-lF', ':published.agoricNames.brand', '-o', 'text'),
);
assert(brand.IST);
assert(brand.ATOM);

const body = {
method: 'executeOffer',
offer: {
id,
invitationSpec: {
invitationMakerName: 'VoteOnParamChange',
previousOffer: previousOfferId,
source: 'continuing',
},
offerArgs: {
deadline: smallCaps.Nat(deadline),
instance: smallCaps.ref(instance.VaultFactory),
params: {
DebtLimit: {
brand: smallCaps.ref(brand.IST),
value: smallCaps.Nat(debtLimitValue),
},
},
path: {
paramPath: {
key: {
collateralBrand: smallCaps.ref(brand.ATOM),
},
},
},
},
proposal: {},
},
};

const capData = { body: `#${JSON.stringify(body)}`, slots };
return JSON.stringify(capData);
};
export const provisionWallet = async (user: string) => {
const userAddress = await addUser(user);

await provisionSmartWallet(
userAddress,
`20000000ubld,100000000${ATOM_DENOM}`,
);
await waitForBlock();
};

export const implementNewAuctionParams = async (
address: string,
oracles: { address: string; id: string }[],
startFequency: number,
clockStep: number,
priceLockPeriod: number,
) => {
await waitForBlock(3);

await proposeNewAuctionParams(
address,
startFequency,
clockStep,
priceLockPeriod,
);

console.log('ACTIONS voting for new auction params');
await voteForNewParams(govAccounts, 0);

console.log('ACTIONS wait for the vote deadline to pass');
await new Promise(r => setTimeout(r, DEFAULT_TIMEOUT));
};

export const proposeNewDebtCeiling = async (
address: string,
debtLimit: number | bigint,
) => {
const charterAcceptOfferId = await agops.ec(
'find-continuing-id',
'--for',
`${'charter\\ member\\ invitation'}`,
'--from',
address,
);

const offer = await paramChangeOfferGeneration(
charterAcceptOfferId,
30,
debtLimit,
);

console.log('ACTIONS proposing new debt ceiling', offer);

return executeOffer(address, offer);
};

export const setDebtLimit = async (
address: string,
debtLimit: number | bigint,
) => {
console.log('ACTIONS Setting debt limit');

await proposeNewDebtCeiling(address, debtLimit);
await voteForNewParams(govAccounts, 0);

console.log('ACTIONS wait for the vote to pass');
await new Promise(r => setTimeout(r, DEFAULT_TIMEOUT));
};
10 changes: 7 additions & 3 deletions a3p-integration/proposals/z:acceptance/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"agoricProposal": {
"type": "/cosmos.params.v1beta1.ParameterChangeProposal"
"type": "/agoric.swingset.CoreEvalProposal"
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/synthetic-chain": "^0.1.0",
"ava": "^6.1.2"
"ava": "^6.1.2",
"tsx": "^4.17.0"
},
"ava": {
"concurrency": 1,
Expand All @@ -18,5 +19,8 @@
"scripts": {
"agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops"
},
"packageManager": "yarn@4.2.2"
"packageManager": "yarn@4.2.2",
"devDependencies": {
"typescript": "^5.5.4"
}
}
83 changes: 83 additions & 0 deletions a3p-integration/proposals/z:acceptance/scripts/test-vaults.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env tsx
/* eslint-disable @jessie.js/safe-await-separator */

import {
adjustVault,
agops,
agoric,
closeVault,
getUser,
GOV1ADDR,
GOV2ADDR,
newOfferId,
openVault,
} from '@agoric/synthetic-chain';
import assert from 'node:assert/strict';
import {
implementNewAuctionParams,
ISTunit,
provisionWallet,
setDebtLimit,
} from '../lib/vaults.mjs';

const START_FREQUENCY = 600; // StartFrequency: 600s (auction runs every 10m)
const CLOCK_STEP = 20; // ClockStep: 20s (ensures auction completes in time)
const PRICE_LOCK_PERIOD = 300;
const oraclesAddresses = [GOV1ADDR, GOV2ADDR];

const oracles = [] as { address: string; id: string }[];
for (const oracle of oraclesAddresses) {
const offerId = await newOfferId();
oracles.push({ address: oracle, id: offerId });
}

// console.log('Ensure user2 provisioned');
// await provisionWallet('user2');

// console.log('Ensure auction params have changed');
// await implementNewAuctionParams(
// GOV1ADDR,
// oracles,
// START_FREQUENCY,
// CLOCK_STEP,
// PRICE_LOCK_PERIOD,
// );

// const govParams = await agoric.follow('-lF', ':published.auction.governance');
// assert.equal(govParams.current.ClockStep.value.relValue, CLOCK_STEP.toString());
// assert.equal(
// govParams.current.StartFrequency.value.relValue,
// START_FREQUENCY.toString(),
// );

console.log('Ensure debt ceiling changes');
const limit = 45_000_000n;
await setDebtLimit(GOV1ADDR, limit);
const params = await agoric.follow(
'-lF',
':published.vaultFactory.managers.manager0.governance',
);
assert.equal(params.current.DebtLimit.value.value, String(limit * ISTunit));

console.log('Open Vaults');
const currentVaults = await agops.vaults('list', '--from', GOV1ADDR);
assert.equal(currentVaults.length, 0);

const vaults = [
{ mint: 5.0, collateral: 9.0 },
{ mint: 6.0, collateral: 10.0 },
];

for (const vault of vaults) {
await openVault(GOV1ADDR, vault.mint, vault.collateral);
}

await adjustVault(GOV1ADDR, 'vault0', { wantCollateral: 1.0 });
await adjustVault(GOV1ADDR, 'vault0', { wantMinted: 1.0 });
await closeVault(GOV1ADDR, 'vault1', 6.06);

const user2 = await getUser('user2');
await openVault(user2, 7, 11);
await adjustVault(user2, 'vault2', { giveMinted: 1.5 });
await adjustVault(user2, 'vault2', { giveCollateral: 2.0 });
await closeVault(user2, 'vault2', 5.75);
12 changes: 8 additions & 4 deletions a3p-integration/proposals/z:acceptance/test.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash

set -ueo pipefail
# Place here any test that should be executed using the executed proposal.
# The effects of this step are not persisted in further proposal layers.

Expand All @@ -10,7 +10,11 @@ yarn ava initial.test.js
GLOBIGNORE=initial.test.js
yarn ava ./*.test.js

./create-kread-item-test.sh
npm install -g tsx
scripts/test-vaults.mts

# DEBUGGING
# ./create-kread-item-test.sh

./state-sync-snapshots-test.sh
./genesis-test.sh
# ./state-sync-snapshots-test.sh
# ./genesis-test.sh
7 changes: 5 additions & 2 deletions a3p-integration/proposals/z:acceptance/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
"compilerOptions": {
"noEmit": true,
"target": "esnext",
"module": "esnext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowJs": true,
"checkJs": true,
"strict": false,
"strictNullChecks": true,
"noImplicitThis": true
"noImplicitThis": true,
// XXX synthetic-chain has some errors
"skipLibCheck": true,
}
}
Loading
Loading