Agoric / agoric-sdk

monorepo for the Agoric Javascript smart contract platform
Apache License 2.0
328 stars 207 forks source link

deploy runStake to devnet (agoricdev-8) by cosmos governance #4348

Closed dckc closed 2 years ago

dckc commented 2 years ago

What is the Problem Being Solved?

In A Look at Our Recent Public Sale 22 Jan, we see:

The RUN token will be launched by the Agoric community through the RUN Protocol, a series of smart contracts authorized by the BLD holders through governance.

How do the BLD holders launch the contracts? In particular, RUNstake (#3788), known as getRUN in the Feb 15 Deep Dive into Agoric: JavaScript Smart Contracts:

getRUN: BLD stakers may lock their already-staked BLD to create RUN – similar to a Vault. This allows BLD stakers to participate in the ecosystem while still securing the chain

How do these contracts get access to closely held objects such as the RUN mint after bootstrap?

Description of the Design

In #4165 we arranged for "core" bootstrap, which consists of a collection of behaviors that produce and consume objects in named slots, and a manifest / permit system to declaratively specify which behaviors should get access to which objects. (Note: we recorded a 9 March bootstrap walkthrough as part of the Restival RUN protocol "purple team" security review.)

In #4642 we introduced a cosmos governance proposal type called swingset-core-eval, which consists of one or more additional behaviors, in source form, along with their permits. If the proposal passes, the code is evaluated and the resulting behavior is run with access to the permitted core bootstrap objects.

Security Considerations

It's critical to correctly apply the Principle of Least Authority to objects such as:

Test Plan

Note: The 4348-gov-demo branch thru 20a1513ace6 was a spike; the parts worth keeping are now elsewhere.

Options

Nice to have:

dckc commented 2 years ago

It seems to work!

I went over a bunch of screenshots with @dtribble and @michaelfig and a few others:

raw materials:

https://github.com/Agoric/agoric-sdk/tree/4348-gov-demo 20a1513

I put the screenshots and a rought start at a slide deck in an internal drive:

connection to voting dapp

alternatives:

dckc commented 2 years ago

1.1MB runStake bundle too big for agorictest-8?

p.s. for follow-up, see #5008

On a local chain, running agorictest-8, I'm struggling to E(zoe).install() this bundle. It weighs in at 1,126,596 bytes.

@michaelfig suggests a tweak to packages/agoric-cli/src/chain-config.js could work around this:

  config.rpc.max_body_bytes = RPC_MAX_BODY_BYTES;
  config.mempool.max_tx_bytes = RPC_MAX_BODY_BYTES;

We could stand up a devnet node with that config. It's not a genesis parameter.

bundle contents

size file
155289 compartment-map.json
39751 @agoric/store-v0.6.10-n180/src/patterns/patternMatchers.js
24982 @agoric/store-v0.6.10-n180/src/types.js
21529 @agoric/governance-v0.4.3-n175/src/types.js
18411 @endo/marshal-v0.6.3-n40/src/marshal.js
18275 @agoric/store-v0.6.10-n180/src/keys/checkKey.js
17084 @agoric/store-v0.6.10-n180/src/patterns/rankOrder.js
15902 @agoric/ertp-v0.13.3-n172/src/types.js
15258 @agoric/ertp-v0.13.3-n172/src/amountMath.js
15076 @agoric/zoe-v0.21.3-n186/src/contractSupport/zoeHelpers.js
14567 @agoric/store-v0.6.10-n180/src/patterns/encodePassable.js
13466 @agoric/governance-v0.4.3-n175/src/contractGovernance/paramManager.js
13141 @agoric/ertp-v0.13.3-n172/src/paymentLedger.js
12468 @agoric/run-protocol-v0.8.0-n178/src/runStake/runStakeKit.js
11418 @agoric/store-v0.6.10-n180/src/keys/merge-set-operators.js
11366 @agoric/zoe-v0.21.3-n186/src/contractSupport/priceAuthority.js
10964 @agoric/zoe-v0.21.3-n186/src/contractSupport/ratio.js
10475 @agoric/store-v0.6.10-n180/src/keys/merge-bag-operators.js
10420 @agoric/run-protocol-v0.8.0-n178/src/runStake/attestation.js
10122 @agoric/assert-v0.3.16-n174/src/types.js
9864 @agoric/zoe-v0.21.3-n186/src/internal-types.js
9249 @agoric/governance-v0.4.3-n175/src/contractGovernor.js
9005 @agoric/zoe-v0.21.3-n186/src/zoeService/types.js
8782 @agoric/zoe-v0.21.3-n186/src/contractFacet/types.js
8287 @agoric/notifier-v0.3.35-n176/src/notifier.js
8252 @agoric/notifier-v0.3.35-n176/src/asyncIterableAdaptor.js
8091 @endo/marshal-v0.6.3-n40/src/helpers/remotable.js
7923 @agoric/governance-v0.4.3-n175/src/binaryVoteCounter.js
7822 @agoric/store-v0.6.10-n180/src/keys/compareKeys.js
7767 @endo/marshal-v0.6.3-n40/src/passStyleOf.js
7678 @agoric/store-v0.6.10-n180/src/index.js
7579 @agoric/governance-v0.4.3-n175/src/question.js
7563 @agoric/run-protocol-v0.8.0-n178/src/runStake/runStakeManager.js
7555 @agoric/run-protocol-v0.8.0-n178/src/runStake/runStake.js
7536 @agoric/zoe-v0.21.3-n186/src/contractSupport/bondingCurves.js
7535 @agoric/run-protocol-v0.8.0-n178/src/interest.js
7252 @agoric/zoe-v0.21.3-n186/src/cleanProposal.js
6652 @endo/marshal-v0.6.3-n40/src/make-far.js
6527 @agoric/zoe-v0.21.3-n186/src/contracts/loan/types.js
6194 @agoric/store-v0.6.10-n180/src/stores/scalarMapStore.js
6115 @agoric/governance-v0.4.3-n175/src/contractGovernance/governParam.js
5541 @agoric/governance-v0.4.3-n175/src/contractHelper.js
5473 @agoric/notifier-v0.3.35-n176/src/types.js
5092 @agoric/zoe-v0.21.3-n186/tools/types.js
5033 @endo/marshal-v0.6.3-n40/src/helpers/symbol.js
5020 @endo/marshal-v0.6.3-n40/src/helpers/passStyle-helpers.js
4982 @agoric/governance-v0.4.3-n175/src/contractGovernance/typedParamManager.js
4975 @agoric/store-v0.6.10-n180/src/stores/scalarWeakMapStore.js
4943 @agoric/store-v0.6.10-n180/src/keys/copyBag.js
4915 @agoric/governance-v0.4.3-n175/src/contractGovernance/governApi.js
4865 @agoric/ertp-v0.13.3-n172/src/typeGuards.js
4743 @endo/marshal-v0.6.3-n40/src/helpers/error.js
4505 @agoric/zoe-v0.21.3-n186/src/contractSupport/index.js
4235 @agoric/store-v0.6.10-n180/src/stores/scalarSetStore.js
4140 @endo/marshal-v0.6.3-n40/src/typeGuards.js
4139 @agoric/store-v0.6.10-n180/src/keys/copySet.js
4106 @agoric/governance-v0.4.3-n175/src/index.js
3996 @endo/marshal-v0.6.3-n40/index.js
3988 @agoric/zoe-v0.21.3-n186/src/contractFacet/offerSafety.js
3959 @agoric/zoe-v0.21.3-n186/src/objArrayConversion.js
3900 @agoric/notifier-v0.3.35-n176/src/subscriber.js
3706 @agoric/store-v0.6.10-n180/src/stores/scalarWeakSetStore.js
3683 @agoric/ertp-v0.13.3-n172/src/issuerKit.js
3598 @endo/eventual-send-v0.14.8-n35/src/track-turns.js
3335 @agoric/zoe-v0.21.3-n186/src/contracts/priceAggregatorTypes.js
3308 @endo/marshal-v0.6.3-n40/src/deeplyFulfilled.js
3251 @endo/eventual-send-v0.14.8-n35/src/E.js
3195 @agoric/zoe-v0.21.3-n186/src/contractSupport/types.js
3130 @agoric/vat-data-v0.1.0-n182/src/index.js
3091 @agoric/swingset-vat-v0.25.1-n173/src/vats/timer/types.js
3074 @endo/nat-v4.1.8-n41/src/index.js
3054 @agoric/store-v0.6.10-n180/src/legacy/legacyMap.js
3011 @agoric/nat-v4.1.0-n2/dist/nat.esm.js
2948 @agoric/zoe-v0.21.3-n186/src/contracts/types.js
2839 @agoric/ertp-v0.13.3-n172/src/displayInfo.js
2814 @agoric/ertp-v0.13.3-n172/src/purse.js
2749 @agoric/governance-v0.4.3-n175/src/validators.js
2633 @agoric/store-v0.6.10-n180/src/stores/store-utils.js
2564 @agoric/governance-v0.4.3-n175/src/contractGovernance/assertions.js
2531 @agoric/run-protocol-v0.8.0-n178/src/contractSupport.js
2492 @agoric/zoe-v0.21.3-n186/src/typeGuards.js
2487 @endo/promise-kit-v0.2.37-n43/index.js
2314 @endo/marshal-v0.6.3-n40/src/helpers/iter-helpers.js
2237 @agoric/run-protocol-v0.8.0-n178/src/interest-math.js
2198 @endo/marshal-v0.6.3-n40/src/helpers/copyRecord.js
1940 @agoric/store-v0.6.10-n180/src/patterns/internal-types.js
1922 @agoric/ertp-v0.13.3-n172/src/mathHelpers/setMathHelpers.js
1911 @agoric/store-v0.6.10-n180/src/legacy/legacyWeakMap.js
1890 @endo/marshal-v0.6.3-n40/src/helpers/tagged.js
1889 @endo/marshal-v0.6.3-n40/src/helpers/copyArray.js
1865 @agoric/notifier-v0.3.35-n176/src/index.js
1777 @agoric/zoe-v0.21.3-n186/src/contracts/callSpread/types.js
1775 @agoric/assert-v0.3.16-n174/src/assert.js
1707 @agoric/zoe-v0.21.3-n186/src/types.js
1652 @endo/marshal-v0.6.3-n40/src/marshal-stringify.js
1567 @agoric/ertp-v0.13.3-n172/src/mathHelpers/natMathHelpers.js
1422 @agoric/zoe-v0.21.3-n186/src/contractSupport/statistics.js
1389 @agoric/ertp-v0.13.3-n172/src/mathHelpers/copySetMathHelpers.js
1369 @agoric/ertp-v0.13.3-n172/src/mathHelpers/copyBagMathHelpers.js
1213 @agoric/zoe-v0.21.3-n186/src/contractSupport/priceQuote.js
1160 @agoric/zoe-v0.21.3-n186/src/contractSupport/stateMachine.js
1080 @endo/marshal-v0.6.3-n40/src/makeTagged.js
1033 @agoric/ertp-v0.13.3-n172/src/brand.js
1002 @agoric/zoe-v0.21.3-n186/src/contractSupport/safeMath.js
997 @agoric/run-protocol-v0.8.0-n178/src/makeTracer.js
968 @agoric/zoe-v0.21.3-n186/src/makeHandle.js
881 @agoric/governance-v0.4.3-n175/src/constants.js
866 @agoric/zoe-v0.21.3-n186/exported.js
839 @agoric/ertp-v0.13.3-n172/src/payment.js
746 @agoric/governance-v0.4.3-n175/src/closingRule.js
637 @endo/far-v0.1.9-n36/src/index.js
467 @endo/eventual-send-v0.14.8-n35/src/no-shim.js
426 @agoric/zoe-v0.21.3-n186/src/contracts/exported.js
410 @agoric/ertp-v0.13.3-n172/src/index.js
348 @agoric/store-v0.6.10-n180/exported.js
292 @agoric/swingset-vat-v0.25.1-n173/exported.js
270 @agoric/notifier-v0.3.35-n176/exported.js
270 @agoric/ertp-v0.13.3-n172/exported.js
230 @endo/marshal-v0.6.3-n40/src/types.js
dckc commented 2 years ago

I told @michaelfig that I did not want to do fragmentation and reassembly of bundles... but based on some bundle handling clues from @kriskowal , I figured maybe it would be fun after all.

It seems to be working...

https://github.com/Agoric/agoric-sdk/tree/dc-installInPieces daae934

~/projects/agoric/ag8/packages/cosmic-swingset
16:43 connolly@jambox$ agoric deploy ~/projects/agoric/agoric-sdk/packages/run-protocol/test/runStake/runStake-deploy.js 
Debugger attached.
Open CapTP connection to ws://127.0.0.1:8000/private/captp...o
agoric: deploy: running /home/connolly/projects/agoric/agoric-sdk/packages/run-protocol/test/runStake/runStake-deploy.js
agoric: deploy: Deploy script will run with Node.js ESM
awaiting home promise...
bundling endoCAS contract...
131945 | compartment-map.json
18411 | @endo/marshal-v0.6.3-n40/src/marshal.js
14503 | @endo/zip-v0.2.21-n49/src/format-reader.js
8091 | @endo/marshal-v0.6.3-n40/src/helpers/remotable.js
...

[ [ 'runStake', 1127980 ], [ 'endoCAS', 371900 ] ]
installing endoCAS...
publishing on board...
{ bundler: { installation: '1265655452', publicFacet: '1202180815' } }
adding compartment-map.json 156327 ...
adding @agoric/assert-v0.3.16-n174/src/assert.js 1775 ...
adding @agoric/assert-v0.3.16-n174/src/types.js 10122 ...
adding @agoric/ertp-v0.13.3-n172/exported.js 270 ...
adding @agoric/ertp-v0.13.3-n172/src/amountMath.js 15258 ...
...
dckc commented 2 years ago

It's out for votes! https://devnet.explorer.agoric.net/proposals/2 Start RUNstake

txhash: ACA4515A108C094B1F49893C29D85434A40EEC96FB058CDC7DC16DA98F30740F

dckc commented 2 years ago

@arirubinstein suggested I do a demo of getting RUN with staked BLD using the REPL.

@samsiegart I'd like to test whether the front end can work with this contract, but I kinda doubt it. In particular, I didn't re-arrange the notifiers.

dckc commented 2 years ago

Another idea: show how to verify the correspondence between the contract in the proposal with a git hash in this repo.

dckc commented 2 years ago

nice to have:

dckc commented 2 years ago

runStake is deployed to devnet

We verified this in office hours today:

command[4] E(home.agoricNames).lookup('instance', 'getRUN')
history[4] [Object Alleged: InstanceHandle]{}
...
has [\"getAmount\",\"getBrand\",\"getContractGovernor\",\"getGovernedParams\",\"getInstallation\",\"getInstance\",\"getInvitationAmount\",\"getNat\",\"getRatio\",\"getString\",\"getSubscription\",\"getUnknown\",\"makeLoanInvitation\",\"makeReturnAttInvitation\"]")

command[8] E(rs).getGovernedParams()
history[8] {"DebtLimit":{"type":"amount","value":{"brand":[Object Alleged: RUN brand]{},"value":1000000000000n}},"Electorate":{"type":"invitation","value":{"brand":[Object Alleged: Zoe Invitation brand]{}
...

command[3] E(home.attMaker).lskdjfldsj()
history[3] Promise.reject("TypeError: target has no method \"lskdjfldsj\", has [\"getAccountState\",\"makeAttestation\",\"makeReturnAttInvitation\",\"unwrapLienedAmount\"]")
dckc commented 2 years ago

Verified: borrowed RUN against staked BLD

I was running with my client on a branch with special wallet support:

~/projects/agoric/ag8/packages/solo
15:36 connolly@jambox$ AG_SOLO_BASEDIR=/tmp/solo8 ./bin/ag-solo setup --netconfig=${NETCONFIG_URL:-https://devnet.agoric.net/network-config}

We start with an address of agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55 and 0 BLD:

Use home to see useful objects, and history[N] to refer to result history
Welcome to Agoric!
command[1] E(home.myAddressNameAdmin).getMyAddress()
history[1] "agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55"
command[2] home.attMaker
history[2] [Object Alleged: attestationTool]{}
command[3] E(home.attMaker).getAccountState()
history[3] {
  "bonded":{"brand":[Object Alleged: BLD brand]{},"value":0n},
  "currentTime":1649363969n,
  "liened":{"brand":[Object Alleged: BLD brand]{},"value":0n},
  "locked":{"brand":[Object Alleged: BLD brand]{},"value":0n},
  "total":{"brand":[Object Alleged: BLD brand]{},"value":0n},
  "unbonding":{"brand":[Object Alleged: BLD brand]{},"value":0n}
}

Then we use the faucet to give ourselves some BLD in tx 9317B7EE...

devnet# ./faucet-helper.sh add-delegate --force dckc agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55

Then stake 12 in tx 7389036...

$ ag8 cosmos --node=https://devnet.rpc.agoric.net:443 --home=/tmp/solo8/ag-cosmos-helper-statedir/   --keyring-backend=test tx staking delegate  agoricvaloper15rkql6lssrru98j3h4p80yvctjgltrljnyjv4v 12000000ubld --from ag-solo --gas auto --gas-adjustment 1.5 -b block --chain-id agoricdev-8

Now in the wallet REPL, our account state shows 12 BLD bonded. We then get an attestation for a lien on 2:

command[4] E(home.attMaker).getAccountState()
history[4] {
  "bonded":{"brand":[Object Alleged: BLD brand]{},"value":12000000n},"currentTime":1649374381n,...}
command[6] BLD = { brand: history[4].bonded.brand, unit: 1000000n }
command[7] mk = (kit, num) => harden({ brand: kit.brand, value: kit.unit * num })
command[8] mk(BLD, 2n)
history[8] {"brand":[Object Alleged: BLD brand]{},"value":2000000n}
command[9] E(home.attMaker).makeAttestation(mk(BLD, 2n))
history[9] [Object Alleged: Attestation payment]{}
command[23] attPmt = history[9] // presented here for continuity

Now we get the runStake instance (called getRUN for hysterical reasons), public facet, and terms (including issuers, MintingRatio):

command[10] E(home.agoricNames).lookup('instance', 'getRUN')
history[10] [Object Alleged: InstanceHandle]{}
command[11] E(home.zoe).getPublicFacet(history[10])
history[11] [Object Alleged: publicFacet]{}
command[12] runStake = history[11]

command[19] E(home.zoe).getTerms(history[10])
history[19] {
  "brands":{
    "Attestation":[Object Alleged: Attestation brand]{},
    "Debt":[Object Alleged: RUN brand]{},
    "Stake":[Object Alleged: BLD brand]{}
  },
  ...
  "governedParams":{ ...
    "MintingRatio":{"type":"ratio","value":{
      "denominator":{"brand":[Object Alleged: BLD brand]{},"value":4n},
      "numerator":{"brand":[Object Alleged: RUN brand]{},"value":1n}}}
    },
  "issuers":{
    "Attestation":[Object Alleged: Attestation issuer]{},
    "Debt":[Object Alleged: RUN issuer]{},
    "Stake":[Object Alleged: BLD issuer]{}
  }, ...
}
command[20] attIssuer = history[19].issuers.Attestation

The amount of the attestation is a semi-fungible token bearing the address and the number of tokens:

command[21] E(attIssuer).getAmountOf(pmt)
history[21] {"brand":[Object Alleged: Attestation brand]{},"value":{"payload":[["agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55",2000000n]],[Symbol(passStyle)]:"tagged",[Symbol(Symbol.toStringTag)]:"copyBag"}}
command[22] attAmt=history[21]

Now we organize the RUN brand and purse (from the wallet admin facet):

command[25] RUN = {unit:1000000n, brand:history[19].brands.Debt, issuer: history[19].issuers.Debt}
history[25] {"unit":1000000n,"brand":[Object Alleged: RUN brand]{},"issuer":[Object Alleged: RUN issuer]{}}
command[33] E(home.wallet).getAdminFacet()
history[33] [Object Alleged: adminFacet]{}
command[34] wa=history[33]
command[35] E(wa).getPurses()
history[35] [["Agoric RUN currency",[Object Alleged: Virtual Purse]{}],["Agoric staking token",[Object Alleged: Virtual Purse]{}],["Default Zoe invite purse",[Object Alleged: Zoe Invitation purse]{}]]
command[36] RUN.purse = history[35][0][1]

Now we make an offer including a proposal and attestation payment:

command[46] proposal = { give: { Attestation: attAmt }, want: { Debt: {brand:RUN.brand, value: 500000n } }}
history[46] {"give":{"Attestation":{"brand":[Object Alleged: Attestation brand]{},"value":{"payload":[["agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55",2000000n]],[Symbol(passStyle)]:"tagged",[Symbol(Symbol.toStringTag)]:"copyBag"}}},"want":{"Debt":{"brand":[Object Alleged: RUN brand]{},"value":500000n}}}
command[47] E(home.zoe).offer(E(runStake).makeLoanInvitation(), proposal, { Attestation: attPmt })
history[47] [Object Alleged: userSeat]{}
command[48] seat = history[47]

The result includes a vault with invitationMakers and a couple notifiers:

command[49] E(seat).getOfferResult()
history[49] {"assetNotifier":[Object Alleged: notifier]{},"invitationMakers":[Object Alleged: invitation makers]{},"vault":[Object Alleged: RUNstake]{},"vaultNotifier":[Object Alleged: notifier]{}}

Let's look at the payouts. An empty Attestation payout is not surprising. And lo! half a RUN!

command[50] E(seat).getPayout('Attestation')
history[50] [Object Alleged: Attestation payment]{}
command[51] E(seat).getPayout('Debt')
history[51] [Object Alleged: RUN payment]{}
command[52] E(attIssuer).getAmountOf(history[50])
history[52] {"brand":[Object Alleged: Attestation brand]{},"value":{"payload":[],[Symbol(passStyle)]:"tagged",[Symbol(Symbol.toStringTag)]:"copyBag"}}
command[53] E(RUN.purse).deposit(history[51])
history[53] {"brand":[Object Alleged: RUN brand]{},"value":500000n}

And now our account state shows 2 BLD liened:

command[54] E(home.attMaker).getAccountState()
history[54] {"bonded":{"brand":[Object Alleged: BLD brand]{},"value":12000000n},"currentTime":1649381191n,"liened":{"brand":[Object Alleged: BLD brand]{},"value":2000000n},"locked":{"brand":[Object Alleged: BLD brand]{},"value":0n},"total":{"brand":[Object Alleged: BLD brand]{},"value":75000000n},"unbonding":{"brand":[Object Alleged: BLD brand]{},"value":0n}}
dckc commented 2 years ago

These would be nice to have, but I'm going to call them out of scope and close this:

p.s. I worked on this 7 different days, so that's between 7 and 14 chunks vs. the estimated 2.