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

wallet misc #6191

Merged
merged 8 commits into from
Sep 13, 2022
Merged
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
4 changes: 2 additions & 2 deletions packages/agoric-cli/src/commands/perf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/* eslint-disable func-names */
/* global process */
import {
iterateLatest,
iterateEach,
makeCastingSpec,
makeFollower,
makeLeaderFromRpcAddresses,
Expand Down Expand Up @@ -72,7 +72,7 @@ export const makePerfCommand = async logger => {
const follower = makeFollower(castingSpec, leader);

const watchForSatisfied = async () => {
for await (const { value } of iterateLatest(follower)) {
for await (const { value } of iterateEach(follower)) {
console.warn('wallet update', value);
if (value.updated === 'offerStatus' && value.status.id === offerId) {
const { status } = value;
Expand Down
7 changes: 3 additions & 4 deletions packages/agoric-cli/src/lib/psm.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ export const makePSMProposal = (brands, opts, fee = 0, anchor = 'AUSD') => {
* @returns {BridgeAction}
*/
export const makePSMSpendAction = (instance, brands, opts) => {
const method =
'wantMinted' in opts
? 'makeWantMintedInvitation'
: 'makeGiveMintedInvitation'; // ref psm.js
const method = opts.wantMinted
? 'makeWantMintedInvitation'
: 'makeGiveMintedInvitation'; // ref psm.js
const proposal = makePSMProposal(
brands,
opts,
Expand Down
7 changes: 1 addition & 6 deletions packages/agoric-cli/src/lib/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ export const networkConfigUrl = agoricNetSubdomain =>
export const rpcUrl = agoricNetSubdomain =>
`https://${agoricNetSubdomain}.rpc.agoric.net:443`;

// Env option instead of CLI option so that CLI args can be validated against it
// XXX lacking ocaps discipline
// look into https://github.com/tj/commander.js/blob/master/examples/options-env.js
export const networkId = process.env.AGORIC_NET || 'local';

/**
* @typedef {{ rpcAddrs: string[], chainName: string }} MinimalNetworkConfig
*/
Expand All @@ -37,7 +32,7 @@ const fromAgoricNet = str => {

/** @type {MinimalNetworkConfig} */
export const networkConfig =
'AGORIC_NET' in process.env
'AGORIC_NET' in process.env && process.env.AGORIC_NET !== 'local'
? await fromAgoricNet(NonNullish(process.env.AGORIC_NET))
: { rpcAddrs: ['http://0.0.0.0:26657'], chainName: 'agoric' };
// console.warn('networkConfig', networkConfig);
Expand Down
2 changes: 1 addition & 1 deletion packages/agoric-cli/src/lib/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { boardSlottingMarshaller, storageHelper } from './rpc.js';
*/
export const getWalletState = async (addr, ctx, { vstorage }) => {
const capDataStrings = await vstorage.readAll(`published.wallet.${addr}`);
assert(capDataStrings);
assert(capDataStrings?.length, 'readAll returned empty');
const capDatas = storageHelper.parseMany(capDataStrings);

// XXX very similar to `coalesceUpdates` util
Expand Down
51 changes: 40 additions & 11 deletions packages/agoric-cli/test/agops-smoketest.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,54 @@
#!/bin/sh

export AGORIC_NET=ollinet
if [ -z "$AGORIC_NET" ]; then
echo "AGORIC_NET env not set"
echo
echo "e.g. AGORIC_NET=ollinet (or export to save typing it each time)"
echo
echo "To test locally, AGORIC_NET=local and have the following running:
# freshen sdk
cd agoric-sdk
yarn install && yarn build

# (new tab)
# Start the chain
cd packages/cosmic-swingset
make scenario2-setup scenario2-run-chain-psm

# (new tab)
# Fund the pool (addr is a magic string)
make SOLO_COINS=1234000000ibc/usdc1234 ACCT_ADDR=agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 fund-acct
# Provision your wallet
cd packages/cosmic-swingset
# Copy the agoric address from your keplr wallet or 'agd keys list', starts with 'agoric1'
WALLET_ADDR=<yours>
make ACCT_ADDR=$WALLET_ADDR AGORIC_POWERS=SMART_WALLET fund-acct provision-acct
# verify
agoric wallet list
agoric wallet show --from $WALLET_ADDR
"
exit 1
fi

KEY=$1

if [ -z "$KEY" ]
then
echo "USAGE: $0 key"
echo "You can reference by name: agd keys list"
echo "Make sure it has been provisioned by the faucet: https://$AGORIC_NET.faucet.agoric.net/"
exit 1
if [ -z "$KEY" ]; then
echo "USAGE: $0 key"
echo "You can reference by name: agd keys list"
echo "Make sure it has been provisioned by the faucet: https://$AGORIC_NET.faucet.agoric.net/"
exit 1
fi

set -x

# NB: fee percentages must be at least the governed param values

# perf test wantMinted
OFFER=$(mktemp -t agops)
bin/agops psm swap --wantMinted 0.01 --feePct 0.01 >| "$OFFER"
OFFER=$(mktemp -t agops.XXX)
bin/agops psm swap --wantMinted 0.01 --feePct 0.01 >|"$OFFER"
time bin/agops perf satisfaction --executeOffer "$OFFER" --from "$KEY"

# perf test giveMinted
OFFER=$(mktemp -t agops)
bin/agops psm swap --giveMinted 0.01 --feePct 0.01 >| "$OFFER"
OFFER=$(mktemp -t agops.XXX)
bin/agops psm swap --giveMinted 0.01 --feePct 0.03 >|"$OFFER"
time bin/agops perf satisfaction --executeOffer "$OFFER" --from "$KEY"
6 changes: 5 additions & 1 deletion packages/smart-wallet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ There are no automated tests yet verifying the smart wallet running on chain. He

## Notifiers

```
```sh
# freshen sdk
cd agoric-sdk
yarn install && yarn build

# tab 1 (chain)
cd packages/cosmic-swingset/
make scenario2-setup scenario2-run-chain
Expand Down
7 changes: 5 additions & 2 deletions packages/smart-wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Wallet contract",
"type": "module",
"scripts": {
"build": "exit 0",
"build": "yarn build:bundles",
"build:bundles": "node ./scripts/build-bundles.js",
"test": "ava",
"test:xs": "exit 0",
"lint": "run-s --continue-on-error lint:*",
Expand All @@ -15,12 +16,14 @@
"devDependencies": {
"ava": "^4.3.1",
"@agoric/cosmic-swingset": "^0.37.0",
"@agoric/deploy-script-support": "^0.9.0",
"@agoric/cosmic-proto": "^0.1.0",
"@agoric/inter-protocol": "^0.11.0",
"@agoric/swingset-vat": "^0.28.0",
"@agoric/wallet-backend": "^0.12.1",
"@agoric/vats": "^0.10.0",
"@endo/captp": "^2.0.13"
"@endo/captp": "^2.0.13",
"@endo/init": "^0.5.47"
},
"dependencies": {
"@agoric/assert": "^0.4.0",
Expand Down
15 changes: 15 additions & 0 deletions packages/smart-wallet/scripts/build-bundles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#! /usr/bin/env node
import '@endo/init';
import { createBundles } from '@agoric/deploy-script-support';
import url from 'url';

const dirname = url.fileURLToPath(new URL('.', import.meta.url));

const sourceToBundle = [
[
`@agoric/smart-wallet/src/walletFactory.js`,
`../bundles/bundle-walletFactory.js`,
],
];

await createBundles(sourceToBundle, dirname);
45 changes: 31 additions & 14 deletions packages/smart-wallet/src/offers.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const UNPUBLISHED_RESULT = 'UNPUBLISHED';
* @param {{ receive: (payment: *) => Promise<Amount> }} opts.depositFacet
* @param {object} opts.powers
* @param {import('./types').Cell<number>} opts.powers.lastOfferId
* @param {Pick<Console, 'info'| 'error'>} opts.powers.logger
* @param {(spec: import('./invitations').InvitationSpec) => ERef<Invitation>} opts.powers.invitationFromSpec
* @param {(brand: Brand) => import('./types').RemotePurse} opts.powers.purseForBrand
* @param {(status: OfferStatus) => void} opts.onStatusChange
Expand All @@ -43,7 +44,7 @@ export const makeOfferExecutor = ({
onStatusChange,
onNewContinuingOffer,
}) => {
const { invitationFromSpec, lastOfferId, purseForBrand } = powers;
const { invitationFromSpec, lastOfferId, logger, purseForBrand } = powers;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 ocap-happy logging


return {
/**
Expand All @@ -54,6 +55,8 @@ export const makeOfferExecutor = ({
* @throws if any parts of the offer can be determined synchronously to be invalid
*/
async executeOffer(offerSpec) {
logger.info('starting executeOffer', offerSpec.id);

const paymentsManager = makePaymentsHelper(purseForBrand, depositFacet);

/** @type {OfferStatus} */
Expand All @@ -71,7 +74,7 @@ export const makeOfferExecutor = ({
* @param {Error} err
*/
const handleError = err => {
console.error('OFFER ERROR:', err);
logger.error('OFFER ERROR:', err);
updateStatus({ error: err.toString() });
paymentsManager.tryReclaimingWithdrawnPayments().then(result => {
if (result) {
Expand Down Expand Up @@ -104,23 +107,32 @@ export const makeOfferExecutor = ({
paymentKeywordRecord,
offerArgs,
);
// ??? should we notify of being seated?
logger.info(id, 'seated');

// publish 'result'
E.when(
E(seatRef).getOfferResult(),
result => {
const passStyle = passStyleOf(result);
console.log('offerResult', passStyle, result);
logger.info(id, 'offerResult', passStyle, result);
// someday can we get TS to type narrow based on the passStyleOf result match?
switch (passStyle) {
case 'bigint':
case 'boolean':
case 'null':
case 'number':
case 'string':
case 'symbol':
case 'undefined':
updateStatus({ result });
break;
case 'copyRecord':
if ('invitationMakers' in result) {
// save for continuing invitation offer
onNewContinuingOffer(id, result.invitationMakers);
}
// ??? are all copyRecord types valid to publish?
updateStatus({ result });
// copyRecord is valid to publish but not safe as it may have private info
updateStatus({ result: UNPUBLISHED_RESULT });
break;
default:
// drop the result
Expand All @@ -131,14 +143,19 @@ export const makeOfferExecutor = ({
);

// publish 'numWantsSatisfied'
E.when(E(seatRef).numWantsSatisfied(), numSatisfied => {
if (numSatisfied === 0) {
updateStatus({ numWantsSatisfied: 0 });
}
updateStatus({
numWantsSatisfied: numSatisfied,
});
});
E.when(
E(seatRef).numWantsSatisfied(),
numSatisfied => {
logger.info(id, 'numSatisfied', numSatisfied);
if (numSatisfied === 0) {
updateStatus({ numWantsSatisfied: 0 });
}
updateStatus({
numWantsSatisfied: numSatisfied,
});
},
handleError,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit message doesn't mention this. (not critical)

);

// publish 'payouts'
// This will block until all payouts succeed, but user will be updated
Expand Down
14 changes: 12 additions & 2 deletions packages/smart-wallet/src/smartWallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ const behavior = {
*/
async executeOffer(offerSpec) {
const { facets, state } = this;
/** @type {State} */
const {
address,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm. I missed something somewhere. A wallet knows the address it's associated with? Is that necessary? It sets off my ACL spidey-sense... it feels vagely like caller or msg.sender in solidity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had the same tingle. It's not strictly necessary. We could take it out by passing two other things in instead:

  • wallet logger
  • wallet storageNode

But it has to persist through init and there may be some churn with durability, so I'll punt until then: #5894

zoe,
brandPurses,
invitationBrand,
Expand All @@ -353,6 +355,11 @@ const behavior = {
updatePublishKit,
} = this.state;

const logger = {
info: (...args) => console.info('wallet', address, ...args),
error: (...args) => console.log('wallet', address, ...args),
};

const executor = makeOfferExecutor({
zoe,
depositFacet: facets.deposit,
Expand All @@ -375,12 +382,15 @@ const behavior = {
state.lastOfferId = id;
},
},
logger,
},
onStatusChange: offerStatus =>
onStatusChange: offerStatus => {
logger.info('offerStatus', offerStatus);
updatePublishKit.publisher.publish({
updated: 'offerStatus',
status: offerStatus,
}),
});
},
onNewContinuingOffer: (offerId, invitationMakers) =>
offerToInvitationMakers.init(offerId, invitationMakers),
});
Expand Down