Skip to content

Commit

Permalink
feat(loadgen): Move Vault task to shared loadgen token
Browse files Browse the repository at this point in the history
  • Loading branch information
mhofman committed Mar 21, 2022
1 parent 234cb94 commit 52c735c
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 73 deletions.
115 changes: 66 additions & 49 deletions loadgen/contract/agent-create-vault.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
// @ts-check

import { E } from '@agoric/eventual-send';
import { Far } from '@agoric/marshal';
import { AmountMath } from '@agoric/ertp';
// import { allComparable } from '@agoric/same-structure';
import * as contractSupport from '@agoric/zoe/src/contractSupport/index.js';
import { pursePetnames, issuerPetnames } from './petnames.js';
import { disp } from './display.js';
import { allValues } from './allValues.js';
import { fallback } from './fallback.js';

const makeRatio = contractSupport.makeRatio;
const multiplyBy =
contractSupport.floorMultiplyBy || contractSupport.multiplyBy;

// This is loaded by the spawner into a new 'spawned' vat on the solo node.
// The default export function is called with some args.
contractSupport.floorMultiplyBy ||
// @ts-expect-error backwards compat
contractSupport.multiplyBy;

export default async function startAgent([key, home, collateralToken]) {
const { zoe, scratch, agoricNames, wallet } = home;

console.error(`create-vault: building tools`);
const {
runBrand,
collateralBrand,
runPurse,
collateralPurse,
treasuryInstance,
vaultFactoryInstance,
} = await allValues({
runBrand: E(agoricNames).lookup('brand', issuerPetnames.RUN),
collateralBrand: E(
E(wallet).getIssuer(issuerPetnames[collateralToken]),
).getBrand(),
runPurse: E(wallet).getPurse(pursePetnames.RUN),
collateralPurse: E(wallet).getPurse(pursePetnames[collateralToken]),
treasuryInstance: E(agoricNames)
.lookup('instance', 'Treasury')
.catch(() => {}),
vaultFactoryInstance: E(agoricNames)
.lookup('instance', 'VaultFactory')
.catch(() => {}),
});
/** @param {Purse} purse */
async function getPurseBalance(purse) {
return /** @type {Promise<Amount<'nat'>>} */ (E(purse).getCurrentAmount());
}

const treasuryPublicFacet = E(zoe).getPublicFacet(
vaultFactoryInstance || treasuryInstance,
);
/**
* This is loaded by the spawner into a new 'spawned' vat on the solo node.
* The default export function is called with some args.
*
* @param {startParam} param
* @typedef {Awaited<ReturnType<typeof startAgent>>} Agent
* @typedef { Pick<import('../types').NatAssetKit, 'brand' | 'purse' | 'displayInfo' | 'name'>} AssetKit
* @typedef {{
* runKit: AssetKit,
* tokenKit: AssetKit,
* vaultFactory: ERef<import('../types').VaultFactoryPublicFacet>,
* zoe: ERef<ZoeService>,
* }} startParam
*/
export default async function startAgent({
runKit: {
brand: runBrand,
purse: runPurse,
displayInfo: { decimalPlaces: runDecimalPlaces },
},
tokenKit: {
brand: collateralBrand,
purse: collateralPurse,
displayInfo: { decimalPlaces: collateralDecimalPlaces },
name: collateralToken,
},
vaultFactory,
zoe,
}) {
console.error(`create-vault: setting up tools`);

const collateralBalance = await E(collateralPurse).getCurrentAmount();
const collateralBalance = await getPurseBalance(collateralPurse);
if (AmountMath.isEmpty(collateralBalance)) {
throw Error(
`create-vault: getCurrentAmount(${collateralToken}) broken (says 0)`,
Expand All @@ -53,6 +59,7 @@ export default async function startAgent([key, home, collateralToken]) {
console.error(
`create-vault: initial balance: ${disp(
collateralBalance,
collateralDecimalPlaces,
)} ${collateralToken}`,
);
// put 1% into the vault
Expand All @@ -63,25 +70,26 @@ export default async function startAgent([key, home, collateralToken]) {

// we only withdraw half the value of the collateral, giving us 200%
// collateralization
const collaterals = await E(treasuryPublicFacet).getCollaterals();
const collaterals = await E(vaultFactory).getCollaterals();
const cdata = collaterals.find((c) => c.brand === collateralBrand);
const priceRate = cdata.marketPrice;
const half = makeRatio(BigInt(50), runBrand);
const wantedRun = multiplyBy(multiplyBy(collateralToLock, priceRate), half);

console.error(`create-vault: tools installed`);
console.error(`create-vault: tools ready`);

console.error(
`create-vault: collateralToLock=${disp(
collateralToLock,
)} ${collateralToken}, wantedRun=${disp(wantedRun)}`,
collateralDecimalPlaces,
)} ${collateralToken}, wantedRun=${disp(wantedRun, runDecimalPlaces)}`,
);

// we fix the 1% 'collateralToLock' value at startup, and use it for all cycles
// (we close over 'collateralToLock')
async function openVault() {
console.error('create-vault: openVault');
const openInvitationP = E(treasuryPublicFacet).makeLoanInvitation();
console.error('create-vault: cycle: openVault');
const openInvitationP = E(vaultFactory).makeLoanInvitation();
const proposal = harden({
give: {
Collateral: collateralToLock,
Expand All @@ -104,13 +112,16 @@ export default async function startAgent([key, home, collateralToken]) {
E(runPurse).deposit(runPayout),
]);
const offerResult = await E(seatP).getOfferResult();
console.error(`create-vault: vault opened`);
console.error(`create-vault: cycle: vault opened`);
return offerResult.vault;
}

async function closeVault(vault) {
console.error('create-vault: closeVault');
const runNeeded = await E(vault).getDebtAmount();
const runNeeded = await fallback(
E(vault).getCurrentDebt(),
E(vault).getDebtAmount(),
);
const closeInvitationP = E(vault).makeCloseInvitation();
const proposal = {
give: {
Expand All @@ -131,23 +142,29 @@ export default async function startAgent([key, home, collateralToken]) {
E(collateralPurse).deposit(collateralPayout),
E(seatP).getOfferResult(),
]);
console.error(`create-vault: vault closed`);
console.error(`create-vault: cycle: vault closed`);
}

const agent = Far('vault agent', {
async doVaultCycle() {
const vault = await openVault(collateralToLock);
const vault = await openVault();
await closeVault(vault);
const [newRunBalance, newCollateralBalance] = await Promise.all([
E(runPurse).getCurrentAmount(),
E(collateralPurse).getCurrentAmount(),
getPurseBalance(runPurse),
getPurseBalance(collateralPurse),
]);
console.error('create-vault: cycle done');
return [newRunBalance, newCollateralBalance];
console.error('create-vault: cycle: done');
return {
newRunBalanceDisplay: disp(newRunBalance, runDecimalPlaces),
newCollateralBalanceDisplay: disp(
newCollateralBalance,
collateralDecimalPlaces,
),
collateralToken,
};
},
});

await E(scratch).set(key, agent);
console.error('create-vault: ready for cycles');
return agent;
}
83 changes: 81 additions & 2 deletions loadgen/contract/agent-prepare-loadgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { AmountMath, AssetKind } from '@agoric/ertp';
import { E } from '@agoric/eventual-send';
import { makeAsyncIterableFromNotifier } from '@agoric/notifier';
import { makeRatio } from '@agoric/zoe/src/contractSupport';

import { pursePetnames, issuerPetnames } from './petnames.js';
import { allValues } from './allValues.js';
Expand All @@ -16,14 +17,17 @@ import { fallback } from './fallback.js';
/**
* @typedef {{
* agoricNames: ERef<NameHub>,
* priceAuthorityAdminFacet: ERef<import('../types.js').PriceAuthorityRegistryAdmin | void>,
* faucet: ERef<any>,
* vaultFactoryCreatorFacet: ERef<VaultFactory | void>,
* wallet: ERef<import('../types.js').HomeWallet>,
* zoe: ERef<ZoeService>,
* mintBundle: BundleSource,
* }} startParam
*/

const tokenBrandPetname = 'LGT';
const BASIS_POINTS = 10000n;

// This is loaded by the spawner into a new 'spawned' vat on the solo node.
// The default export function is called with some args.
Expand Down Expand Up @@ -117,6 +121,8 @@ const makePurseFinder = ({ wallet, walletAdmin }) => {
export default async function startAgent({
agoricNames,
faucet,
priceAuthorityAdminFacet,
vaultFactoryCreatorFacet,
zoe,
wallet,
mintBundle,
Expand Down Expand Up @@ -328,8 +334,81 @@ export default async function startAgent({
return false;
});

await fundingResult;
return harden(await allValues({ tokenKit, runKit, amm }));
/** @type {ERef<Instance>} */
const vaultFactoryInstance = fallback(
E(agoricNames).lookup('instance', 'VaultFactory'),
E(agoricNames).lookup('instance', 'Treasury'),
);
// Use `when` as older versions of agoric-sdk cannot accept a promise
// See https://github.com/Agoric/agoric-sdk/issues/3837
/** @type {ERef<import('../types.js').VaultFactoryPublicFacet>} */
const vaultFactoryPublicFacet = E.when(
withFee(vaultFactoryInstance),
E(zoe).getPublicFacet,
);

const vaultManager = E.when(
Promise.all([
priceAuthorityAdminFacet,
vaultFactoryCreatorFacet,
fundingResult,
]),
async ([priceAuthorityAdmin, vaultFactory, ammFunded]) => {
if (!priceAuthorityAdmin || !vaultFactory) {
console.error(
'prepare-loadgen: vaultFactoryCreator and priceAuthorityAdmin not available',
);
return null;
}

if (!ammFunded) {
return null;
}

const { brand: collateralBrand, issuer: collateralIssuer } =
await tokenKit;
const { brand: centralBrand } = await runKit;

const { toCentral, fromCentral } = E.get(
E(amm).getPriceAuthorities(collateralBrand),
);

await Promise.all([
E(priceAuthorityAdmin).registerPriceAuthority(
toCentral,
collateralBrand,
centralBrand,
),
E(priceAuthorityAdmin).registerPriceAuthority(
fromCentral,
centralBrand,
collateralBrand,
),
]);

const rates = {
liquidationMargin: makeRatio(105n, centralBrand),
interestRate: makeRatio(250n, centralBrand, BASIS_POINTS),
loanFee: makeRatio(200n, centralBrand, BASIS_POINTS),
};

return E(vaultFactory).addVaultType(
collateralIssuer,
issuerPetnames[tokenBrandPetname],
rates,
);
},
);

return harden(
await allValues({
tokenKit,
runKit,
amm,
vaultManager,
vaultFactory: vaultFactoryPublicFacet,
}),
);

// TODO: exit here?
}
6 changes: 3 additions & 3 deletions loadgen/loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { deepEquals } from './firebase/admin/helpers.js';
import { prepareLoadgen } from './prepare-loadgen.js';
import { prepareFaucet } from './task-tap-faucet.js';
import { prepareAMMTrade } from './task-trade-amm.js';
// import { prepareVaultCycle } from './task-create-vault.js';
import { prepareVaultCycle } from './task-create-vault.js';

const sortAndFilterNullish = (obj) =>
Object.fromEntries(
Expand All @@ -32,7 +32,7 @@ let pushHandlerBroker;
let currentConfig = sortAndFilterNullish({
faucet: null, // e.g. { interval=60, limit=1, wait=0 }
amm: null, // e.g. { interval: 120}
// vault: null, // e.g. { interval: 120, wait: 60 }
vault: null, // e.g. { interval: 120, wait: 60 }
});

let pushHandler = null;
Expand All @@ -41,7 +41,7 @@ let pushBroker = null;
const tasks = {
faucet: [prepareFaucet],
amm: [prepareAMMTrade],
// vault: [prepareVaultCycle],
vault: [prepareVaultCycle],
};

const runners = {}; // name -> { cycle, stop?, limit, pending }
Expand Down
23 changes: 21 additions & 2 deletions loadgen/prepare-loadgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,25 @@ const key = 'loadgenKit';
* @typedef {|
* 'agoricNames' |
* 'faucet' |
* 'priceAuthorityAdminFacet' |
* 'scratch' |
* 'spawner' |
* 'vaultFactoryCreatorFacet' |
* 'wallet' |
* 'zoe' |
* never} UsedHomeCaps
*/
export async function prepareLoadgen(home, deployPowers) {
const { agoricNames, faucet, scratch, spawner, wallet, zoe } = E.get(home);
const {
agoricNames,
faucet,
priceAuthorityAdminFacet,
scratch,
spawner,
vaultFactoryCreatorFacet,
wallet,
zoe,
} = E.get(home);

/** @type {import('./contract/agent-prepare-loadgen').LoadgenKit | undefined} */
let loadgenKit = await E(scratch).get(key);
Expand All @@ -45,7 +56,15 @@ export async function prepareLoadgen(home, deployPowers) {
// create a solo-side agent to setup everything
const installerP = E(spawner).install(agentBundle);
/** @type {import('./contract/agent-prepare-loadgen').startParam} */
const agentParam = harden({ agoricNames, faucet, wallet, zoe, mintBundle });
const agentParam = harden({
agoricNames,
faucet,
priceAuthorityAdminFacet,
vaultFactoryCreatorFacet,
wallet,
zoe,
mintBundle,
});
loadgenKit = await E(installerP).spawn(agentParam);

await E(scratch).set(key, loadgenKit);
Expand Down
Loading

0 comments on commit 52c735c

Please sign in to comment.