-
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: WithdrawReward on StakingAccountHolder (WIP 3/3)
- test non-trivial delegations - todos for remaining work - factor out tryDecodeResponse, toJSON - test: withdrawReward on StakingAccountHolder.helpers facet
- Loading branch information
Showing
2 changed files
with
211 additions
and
17 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,136 @@ | ||
// @ts-check | ||
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; | ||
|
||
import { encodeBase64 } from '@endo/base64'; | ||
import { E, Far } from '@endo/far'; | ||
import * as pbjs from 'protobufjs'; | ||
import { | ||
MsgWithdrawDelegatorReward, | ||
MsgWithdrawDelegatorRewardResponse, | ||
} from '@agoric/cosmic-proto/cosmos/distribution/v1beta1/tx.js'; | ||
import { makeScalarBigMapStore } from '@agoric/vat-data'; | ||
import { prepareStakingAccountKit } from '../src/exos/stakingAccountKit.js'; | ||
|
||
/** @import {ChainAccount} from '../src/types.js'; */ | ||
|
||
const test = anyTest; | ||
|
||
const { Fail } = assert; | ||
|
||
// XXX typescript doesn't realize .default is needed | ||
/** @type {typeof import('protobufjs').Writer} */ | ||
const Writer = pbjs.default.Writer; | ||
|
||
test('WithdrawDelegatorReward: protobuf encoding helper', t => { | ||
const actual = MsgWithdrawDelegatorReward.toProtoMsg({ | ||
delegatorAddress: 'abc', | ||
validatorAddress: 'def', | ||
}); | ||
|
||
const abc = [0x03, 0x61, 0x62, 0x63]; // wire type 3, a, b, c | ||
const def = [0x03, 0x64, 0x65, 0x66]; | ||
t.deepEqual(actual, { | ||
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', | ||
value: Uint8Array.from([0x0a, ...abc, 0x12, ...def]), | ||
}); | ||
}); | ||
|
||
test('WithdrawDelegatorReward: bad inputs', t => { | ||
/** @type {any[]} */ | ||
const badInputs = [{}, { delegatorAddress: 'abc' }, { delegatorAddress: 2 }]; | ||
|
||
for (const it of badInputs) { | ||
t.throws(() => MsgWithdrawDelegatorReward.encode(it)); | ||
} | ||
}); | ||
|
||
/** | ||
* XXX defined in codegen/cosmos/base/v1beta1/coin.d.ts | ||
* but that's not exported from comsmic-proto. | ||
* | ||
* @typedef {{ denom: string; amount: string; }} Coin | ||
*/ | ||
|
||
/** | ||
* @param {string} [addr] | ||
* @param {Record<string, Coin>} [delegations] | ||
*/ | ||
const mockAccount = (addr = 'agoric1234', delegations = {}) => { | ||
const calls = []; | ||
|
||
const typeUrl = '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward'; | ||
|
||
/** @type {ChainAccount} */ | ||
const account = Far('MockAccount', { | ||
getAccountAddress: () => addr, | ||
executeEncodedTx: async msgs => { | ||
assert.equal(msgs.length, 1); | ||
assert.equal(msgs[0].typeUrl, typeUrl); | ||
await null; | ||
calls.push({ msgs }); | ||
const wr = new Writer(); | ||
for (const v of Object.values(delegations)) { | ||
// @ts-expect-error BinaryWriter is not exported | ||
MsgWithdrawDelegatorRewardResponse.encode({ amount: [v] }, wr); | ||
} | ||
const bs = wr.finish(); | ||
return encodeBase64(bs); | ||
}, | ||
executeTx: () => Fail`mock`, | ||
close: () => Fail`mock`, | ||
deposit: () => Fail`mock`, | ||
getPurse: () => Fail`mock`, | ||
prepareTransfer: () => Fail`mock`, | ||
}); | ||
return { account, calls }; | ||
}; | ||
|
||
/** @returns {ZCF} */ | ||
const mockZCF = () => | ||
harden({ | ||
// @ts-expect-error mock | ||
makeInvitation: async (handler, desc, c = undefined, patt = undefined) => { | ||
Check failure on line 92 in packages/orchestration/test/test-withdraw-reward.js GitHub Actions / lint-rest
|
||
// const userSeat = harden({ | ||
// getOfferResult: () => { | ||
// const zcfSeat = {}; | ||
// const r = handler(zcfSeat); | ||
// return r; | ||
// }, | ||
// }); | ||
/** @type {Invitation} */ | ||
// @ts-expect-error mock | ||
const invitation = harden({}); | ||
return invitation; | ||
}, | ||
}); | ||
|
||
test('withdraw rewards from staking account holder', async t => { | ||
const makeRecorderKit = () => { | ||
/** @type {any} */ | ||
const kit = harden({}); | ||
return kit; | ||
}; | ||
const baggage = makeScalarBigMapStore('b1'); | ||
const zcf = mockZCF(); | ||
const make = prepareStakingAccountKit(baggage, makeRecorderKit, zcf); | ||
|
||
const validator = { address: 'agoric1valoper234', addressEncoding: 'bech32' }; | ||
const delegations = { | ||
[validator.address]: { denom: 'ustake', amount: '200' }, | ||
}; | ||
const { account } = mockAccount(undefined, delegations); | ||
// const { rootNode } = makeFakeStorageKit('mockChainStorageRoot'); | ||
/** @type {StorageNode} */ | ||
// @ts-expect-error mock | ||
const storageNode = Far('StorageNode', {}); | ||
const addr = 'agoric123'; | ||
|
||
// TODO: invitationMakers | ||
const { helper } = make(account, storageNode, addr); | ||
const actual = await E(helper).withdrawReward(validator); | ||
t.deepEqual(actual, [{ denom: 'ustake', value: 200n }]); | ||
}); | ||
|
||
test.todo(`delegate; undelegate; collect rewards`); | ||
test.todo('undelegate uses a timer: begin; how long? wait; resolve'); | ||
test.todo('undelegate is cancellable - cosmos cancelUnbonding'); |