@agoric/fast-usdc 0.1.1-dev-1231911.0 → 0.1.1-dev-34f026b.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/cli/bridge-action.js +12 -4
- package/src/cli/cli.js +3 -51
- package/src/cli/lp-commands.js +171 -0
- package/src/cli/operator-commands.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/fast-usdc",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
3
|
+
"version": "0.1.1-dev-34f026b.0+34f026b",
|
|
4
4
|
"description": "CLI and library for Fast USDC product",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"lint:eslint": "eslint ."
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
26
|
-
"@agoric/vats": "0.15.2-dev-
|
|
27
|
-
"@agoric/zone": "0.2.3-dev-
|
|
25
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-34f026b.0+34f026b",
|
|
26
|
+
"@agoric/vats": "0.15.2-dev-34f026b.0+34f026b",
|
|
27
|
+
"@agoric/zone": "0.2.3-dev-34f026b.0+34f026b",
|
|
28
28
|
"@fast-check/ava": "^2.0.1",
|
|
29
29
|
"ava": "^5.3.0",
|
|
30
30
|
"c8": "^10.1.2",
|
|
@@ -32,15 +32,15 @@
|
|
|
32
32
|
"ts-blank-space": "^0.4.4"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@agoric/client-utils": "0.1.1-dev-
|
|
36
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
37
|
-
"@agoric/internal": "0.3.3-dev-
|
|
38
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
39
|
-
"@agoric/orchestration": "0.1.1-dev-
|
|
40
|
-
"@agoric/store": "0.9.3-dev-
|
|
41
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
42
|
-
"@agoric/vow": "0.1.1-dev-
|
|
43
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
35
|
+
"@agoric/client-utils": "0.1.1-dev-34f026b.0+34f026b",
|
|
36
|
+
"@agoric/ertp": "0.16.3-dev-34f026b.0+34f026b",
|
|
37
|
+
"@agoric/internal": "0.3.3-dev-34f026b.0+34f026b",
|
|
38
|
+
"@agoric/notifier": "0.6.3-dev-34f026b.0+34f026b",
|
|
39
|
+
"@agoric/orchestration": "0.1.1-dev-34f026b.0+34f026b",
|
|
40
|
+
"@agoric/store": "0.9.3-dev-34f026b.0+34f026b",
|
|
41
|
+
"@agoric/vat-data": "0.5.3-dev-34f026b.0+34f026b",
|
|
42
|
+
"@agoric/vow": "0.1.1-dev-34f026b.0+34f026b",
|
|
43
|
+
"@agoric/zoe": "0.26.3-dev-34f026b.0+34f026b",
|
|
44
44
|
"@cosmjs/proto-signing": "^0.32.4",
|
|
45
45
|
"@cosmjs/stargate": "^0.32.4",
|
|
46
46
|
"@endo/base64": "^1.0.9",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "34f026b7be9ace7022458d7f7b890828cfa4e951"
|
|
84
84
|
}
|
package/src/cli/bridge-action.js
CHANGED
|
@@ -4,13 +4,16 @@ import { boardSlottingMarshaller } from '@agoric/client-utils';
|
|
|
4
4
|
* @import {BridgeAction} from '@agoric/smart-wallet/src/smartWallet.js';
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const defaultMarshaller = boardSlottingMarshaller();
|
|
8
|
+
|
|
9
|
+
/** @typedef {ReturnType<boardSlottingMarshaller>} BoardSlottingMarshaller */
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* @param {BridgeAction} bridgeAction
|
|
11
13
|
* @param {Pick<import('stream').Writable,'write'>} stdout
|
|
14
|
+
* @param {BoardSlottingMarshaller} marshaller
|
|
12
15
|
*/
|
|
13
|
-
const outputAction = (bridgeAction, stdout) => {
|
|
16
|
+
const outputAction = (bridgeAction, stdout, marshaller) => {
|
|
14
17
|
const capData = marshaller.toCapData(harden(bridgeAction));
|
|
15
18
|
stdout.write(JSON.stringify(capData));
|
|
16
19
|
stdout.write('\n');
|
|
@@ -25,8 +28,13 @@ export const sendHint =
|
|
|
25
28
|
* stdout: Pick<import('stream').Writable,'write'>,
|
|
26
29
|
* stderr: Pick<import('stream').Writable,'write'>,
|
|
27
30
|
* }} io
|
|
31
|
+
* @param {BoardSlottingMarshaller | undefined} marshaller
|
|
28
32
|
*/
|
|
29
|
-
export const outputActionAndHint = (
|
|
30
|
-
|
|
33
|
+
export const outputActionAndHint = (
|
|
34
|
+
bridgeAction,
|
|
35
|
+
{ stdout, stderr },
|
|
36
|
+
marshaller = defaultMarshaller,
|
|
37
|
+
) => {
|
|
38
|
+
outputAction(bridgeAction, stdout, marshaller);
|
|
31
39
|
stderr.write(sendHint);
|
|
32
40
|
};
|
package/src/cli/cli.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/* eslint-env node */
|
|
2
2
|
/* global globalThis */
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
Command,
|
|
6
|
-
InvalidArgumentError,
|
|
7
|
-
InvalidOptionArgumentError,
|
|
8
|
-
} from 'commander';
|
|
3
|
+
import { Command } from 'commander';
|
|
9
4
|
import { existsSync, mkdirSync, readFileSync } from 'fs';
|
|
10
5
|
import { fileURLToPath } from 'url';
|
|
11
6
|
import { dirname, resolve } from 'path';
|
|
@@ -19,6 +14,7 @@ import { addOperatorCommands } from './operator-commands.js';
|
|
|
19
14
|
import * as configLib from './config.js';
|
|
20
15
|
import transferLib from './transfer.js';
|
|
21
16
|
import { makeFile } from '../util/file.js';
|
|
17
|
+
import { addLPCommands } from './lp-commands.js';
|
|
22
18
|
|
|
23
19
|
const packageJson = JSON.parse(
|
|
24
20
|
readFileSync(
|
|
@@ -83,51 +79,7 @@ export const initProgram = (
|
|
|
83
79
|
env,
|
|
84
80
|
now,
|
|
85
81
|
});
|
|
86
|
-
|
|
87
|
-
/** @param {string} value */
|
|
88
|
-
const parseDecimal = value => {
|
|
89
|
-
try {
|
|
90
|
-
assertParsableNumber(value);
|
|
91
|
-
} catch {
|
|
92
|
-
throw new InvalidArgumentError('Not a decimal number.');
|
|
93
|
-
}
|
|
94
|
-
return value;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @param {string} str
|
|
99
|
-
* @returns {'auto' | number}
|
|
100
|
-
*/
|
|
101
|
-
const parseFee = str => {
|
|
102
|
-
if (str === 'auto') return 'auto';
|
|
103
|
-
const num = parseFloat(str);
|
|
104
|
-
if (Number.isNaN(num)) {
|
|
105
|
-
throw new InvalidOptionArgumentError('Fee must be a number.');
|
|
106
|
-
}
|
|
107
|
-
return num;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
program
|
|
111
|
-
.command('deposit')
|
|
112
|
-
.description('Offer assets to the liquidity pool')
|
|
113
|
-
.argument('<give>', 'USDC to give', parseDecimal)
|
|
114
|
-
.option('--id [offer-id]', 'Offer ID')
|
|
115
|
-
.option('--fee [fee]', 'Cosmos fee', parseFee)
|
|
116
|
-
.action(() => {
|
|
117
|
-
console.error('TODO actually send deposit');
|
|
118
|
-
// TODO: Implement deposit logic
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
program
|
|
122
|
-
.command('withdraw')
|
|
123
|
-
.description('Withdraw assets from the liquidity pool')
|
|
124
|
-
.argument('<want>', 'USDC to withdraw', parseDecimal)
|
|
125
|
-
.option('--id [offer-id]', 'Offer ID')
|
|
126
|
-
.option('--fee [fee]', 'Cosmos fee', parseFee)
|
|
127
|
-
.action(() => {
|
|
128
|
-
console.error('TODO actually send withdrawal');
|
|
129
|
-
// TODO: Implement withdraw logic
|
|
130
|
-
});
|
|
82
|
+
addLPCommands(program, { fetch, stdout, stderr, env, now });
|
|
131
83
|
|
|
132
84
|
program
|
|
133
85
|
.command('transfer')
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Command} from 'commander';
|
|
3
|
+
* @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
|
|
4
|
+
* @import {ExecuteOfferAction} from '@agoric/smart-wallet/src/smartWallet.js';
|
|
5
|
+
* @import {USDCProposalShapes} from '../pool-share-math.js';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
|
|
9
|
+
import { InvalidArgumentError } from 'commander';
|
|
10
|
+
import {
|
|
11
|
+
assertParsableNumber,
|
|
12
|
+
ceilDivideBy,
|
|
13
|
+
multiplyBy,
|
|
14
|
+
parseRatio,
|
|
15
|
+
} from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
16
|
+
import { AmountMath } from '@agoric/ertp';
|
|
17
|
+
import { outputActionAndHint } from './bridge-action.js';
|
|
18
|
+
|
|
19
|
+
/** @param {string} arg */
|
|
20
|
+
const parseDecimal = arg => {
|
|
21
|
+
try {
|
|
22
|
+
assertParsableNumber(arg);
|
|
23
|
+
const n = Number(arg);
|
|
24
|
+
return n;
|
|
25
|
+
} catch {
|
|
26
|
+
throw new InvalidArgumentError('Not a number');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} amountString
|
|
32
|
+
* @param {Brand} usdc
|
|
33
|
+
*/
|
|
34
|
+
const parseUSDCAmount = (amountString, usdc) => {
|
|
35
|
+
const USDC_DECIMALS = 6;
|
|
36
|
+
const unit = AmountMath.make(usdc, 10n ** BigInt(USDC_DECIMALS));
|
|
37
|
+
return multiplyBy(unit, parseRatio(amountString, usdc));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {Command} program
|
|
42
|
+
* @param {{
|
|
43
|
+
* fetch?: Window['fetch'];
|
|
44
|
+
* vstorageKit?: Awaited<ReturnType<typeof makeVstorageKit>>;
|
|
45
|
+
* stdout: typeof process.stdout;
|
|
46
|
+
* stderr: typeof process.stderr;
|
|
47
|
+
* env: typeof process.env;
|
|
48
|
+
* now: typeof Date.now;
|
|
49
|
+
* }} io
|
|
50
|
+
*/
|
|
51
|
+
export const addLPCommands = (
|
|
52
|
+
program,
|
|
53
|
+
{ fetch, vstorageKit, stderr, stdout, env, now },
|
|
54
|
+
) => {
|
|
55
|
+
const loadVsk = async () => {
|
|
56
|
+
if (vstorageKit) {
|
|
57
|
+
return vstorageKit;
|
|
58
|
+
}
|
|
59
|
+
assert(fetch);
|
|
60
|
+
const networkConfig = await fetchEnvNetworkConfig({ env, fetch });
|
|
61
|
+
return makeVstorageKit({ fetch }, networkConfig);
|
|
62
|
+
};
|
|
63
|
+
/** @type {undefined | ReturnType<typeof loadVsk>} */
|
|
64
|
+
let vskP;
|
|
65
|
+
|
|
66
|
+
program
|
|
67
|
+
.command('deposit')
|
|
68
|
+
.description('Deposit USDC into pool')
|
|
69
|
+
.addHelpText(
|
|
70
|
+
'after',
|
|
71
|
+
'\nPipe the STDOUT to a file such as deposit.json, then use the Agoric CLI to broadcast it:\n agoric wallet send --offer deposit.json --from gov1 --keyring-backend="test"',
|
|
72
|
+
)
|
|
73
|
+
.requiredOption('--amount <number>', 'USDC amount', parseDecimal)
|
|
74
|
+
.option('--offerId <string>', 'Offer id', String, `lpDeposit-${now()}`)
|
|
75
|
+
.action(async opts => {
|
|
76
|
+
vskP ||= loadVsk();
|
|
77
|
+
const vsk = await vskP;
|
|
78
|
+
/** @type {Brand<'nat'>} */
|
|
79
|
+
// @ts-expect-error it doesnt recognize usdc as a Brand type
|
|
80
|
+
const usdc = vsk.agoricNames.brand.USDC;
|
|
81
|
+
assert(usdc, 'USDC brand not in agoricNames');
|
|
82
|
+
|
|
83
|
+
const usdcAmount = parseUSDCAmount(opts.amount, usdc);
|
|
84
|
+
|
|
85
|
+
/** @type {USDCProposalShapes['deposit']} */
|
|
86
|
+
const proposal = {
|
|
87
|
+
give: {
|
|
88
|
+
USDC: usdcAmount,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** @type {OfferSpec} */
|
|
93
|
+
const offer = {
|
|
94
|
+
id: opts.offerId,
|
|
95
|
+
invitationSpec: {
|
|
96
|
+
source: 'agoricContract',
|
|
97
|
+
instancePath: ['fastUsdc'],
|
|
98
|
+
callPipe: [['makeDepositInvitation', []]],
|
|
99
|
+
},
|
|
100
|
+
proposal,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/** @type {ExecuteOfferAction} */
|
|
104
|
+
const bridgeAction = {
|
|
105
|
+
method: 'executeOffer',
|
|
106
|
+
offer,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
outputActionAndHint(bridgeAction, { stderr, stdout }, vsk.marshaller);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
program
|
|
113
|
+
.command('withdraw')
|
|
114
|
+
.description("Withdraw USDC from the LP's pool share")
|
|
115
|
+
.addHelpText(
|
|
116
|
+
'after',
|
|
117
|
+
'\nPipe the STDOUT to a file such as withdraw.json, then use the Agoric CLI to broadcast it:\n agoric wallet send --offer withdraw.json --from gov1 --keyring-backend="test"',
|
|
118
|
+
)
|
|
119
|
+
.requiredOption('--amount <number>', 'USDC amount', parseDecimal)
|
|
120
|
+
.option('--offerId <string>', 'Offer id', String, `lpWithdraw-${now()}`)
|
|
121
|
+
.action(async opts => {
|
|
122
|
+
vskP ||= loadVsk();
|
|
123
|
+
const vsk = await vskP;
|
|
124
|
+
|
|
125
|
+
/** @type {Brand<'nat'>} */
|
|
126
|
+
// @ts-expect-error it doesnt recognize FastLP as a Brand type
|
|
127
|
+
const poolShare = vsk.agoricNames.brand.FastLP;
|
|
128
|
+
assert(poolShare, 'FastLP brand not in agoricNames');
|
|
129
|
+
|
|
130
|
+
/** @type {Brand<'nat'>} */
|
|
131
|
+
// @ts-expect-error it doesnt recognize usdc as a Brand type
|
|
132
|
+
const usdc = vsk.agoricNames.brand.USDC;
|
|
133
|
+
assert(usdc, 'USDC brand not in agoricNames');
|
|
134
|
+
|
|
135
|
+
const usdcAmount = parseUSDCAmount(opts.amount, usdc);
|
|
136
|
+
|
|
137
|
+
/** @type {import('../types.js').PoolMetrics} */
|
|
138
|
+
// @ts-expect-error it treats this as "unknown"
|
|
139
|
+
const metrics = await vsk.readPublished('fastUsdc.poolMetrics');
|
|
140
|
+
const fastLPAmount = ceilDivideBy(usdcAmount, metrics.shareWorth);
|
|
141
|
+
|
|
142
|
+
/** @type {USDCProposalShapes['withdraw']} */
|
|
143
|
+
const proposal = {
|
|
144
|
+
give: {
|
|
145
|
+
PoolShare: fastLPAmount,
|
|
146
|
+
},
|
|
147
|
+
want: {
|
|
148
|
+
USDC: usdcAmount,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/** @type {OfferSpec} */
|
|
153
|
+
const offer = {
|
|
154
|
+
id: opts.offerId,
|
|
155
|
+
invitationSpec: {
|
|
156
|
+
source: 'agoricContract',
|
|
157
|
+
instancePath: ['fastUsdc'],
|
|
158
|
+
callPipe: [['makeWithdrawInvitation', []]],
|
|
159
|
+
},
|
|
160
|
+
proposal,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
outputActionAndHint(
|
|
164
|
+
{ method: 'executeOffer', offer },
|
|
165
|
+
{ stderr, stdout },
|
|
166
|
+
vsk.marshaller,
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return program;
|
|
171
|
+
};
|
|
@@ -80,6 +80,10 @@ export const addOperatorCommands = (
|
|
|
80
80
|
operator
|
|
81
81
|
.command('attest')
|
|
82
82
|
.description('Attest to an observed Fast USDC transfer')
|
|
83
|
+
.addHelpText(
|
|
84
|
+
'after',
|
|
85
|
+
'\nPipe the STDOUT to a file such as attest.json, then use the Agoric CLI to broadcast it:\n agoric wallet send --offer attest.json --from gov1 --keyring-backend="test"',
|
|
86
|
+
)
|
|
83
87
|
.requiredOption('--previousOfferId <string>', 'Offer id', String)
|
|
84
88
|
.requiredOption('--forwardingChannel <string>', 'Channel id', String)
|
|
85
89
|
.requiredOption('--recipientAddress <string>', 'bech32 address', String)
|