-
Notifications
You must be signed in to change notification settings - Fork 208
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add null upgrade of vaultFactoryGovernor to upgrade-vaults.js (#…
…9953) refs: #5200 ## Description Do a null upgrade of the vaultFactory governor contract in the coreEval that upgrades the vaultFactory contract. ### Security Considerations If the governor is correctly connected to the contract (tests in process), and can govern parameters and enable offer filters, then everything is connected as it was, and there are no new security issues. ### Scaling Considerations None. ### Documentation Considerations No user-visible changes. ### Testing Considerations Test governance of the vaultFactory thoroughly on a testnet. ### Upgrade Considerations It appears that contract governor may be upgradeable..
- Loading branch information
Showing
8 changed files
with
627 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
/* 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 } | ||
|
||
// XXX likely longer than necessary | ||
const VOTING_WAIT_MS = 65 * 1000; | ||
|
||
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, VOTING_WAIT_MS)); | ||
}; | ||
|
||
export const proposeNewDebtCeiling = async ( | ||
address: string, | ||
debtLimit: number | bigint, | ||
) => { | ||
const charterAcceptOfferId = await agops.ec( | ||
'find-continuing-id', | ||
'--for', | ||
`${'charter\\ member\\ invitation'}`, | ||
'--from', | ||
address, | ||
); | ||
|
||
return executeOffer( | ||
address, | ||
paramChangeOfferGeneration(charterAcceptOfferId, 30, debtLimit), | ||
); | ||
}; | ||
|
||
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, VOTING_WAIT_MS)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
a3p-integration/proposals/z:acceptance/scripts/test-vaults.mts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#!/usr/bin/env tsx | ||
/* eslint-disable @jessie.js/safe-await-separator */ | ||
|
||
import { | ||
agoric, | ||
GOV1ADDR, | ||
GOV2ADDR, | ||
newOfferId, | ||
} 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)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.