@agoric/fast-usdc 0.1.1-dev-23120a9.0 → 0.1.1-dev-419df4e.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 +32 -0
- package/src/cli/cli.js +11 -101
- package/src/cli/config-commands.js +108 -0
- package/src/cli/config.js +6 -8
- package/src/cli/operator-commands.js +78 -0
- package/src/cli/transfer.js +2 -2
- package/src/exos/settler.js +3 -3
- package/src/exos/status-manager.js +43 -14
- package/src/fast-usdc.contract.js +5 -1
- package/src/util/file.js +1 -1
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-419df4e.0+419df4e",
|
|
4
4
|
"description": "CLI and library for Fast USDC product",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"lint:eslint": "eslint ."
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
25
|
-
"@agoric/vats": "0.15.2-dev-
|
|
26
|
-
"@agoric/zone": "0.2.3-dev-
|
|
24
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-419df4e.0+419df4e",
|
|
25
|
+
"@agoric/vats": "0.15.2-dev-419df4e.0+419df4e",
|
|
26
|
+
"@agoric/zone": "0.2.3-dev-419df4e.0+419df4e",
|
|
27
27
|
"@fast-check/ava": "^2.0.1",
|
|
28
28
|
"ava": "^5.3.0",
|
|
29
29
|
"c8": "^10.1.2",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"ts-blank-space": "^0.4.1"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@agoric/client-utils": "0.1.1-dev-
|
|
35
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
36
|
-
"@agoric/internal": "0.3.3-dev-
|
|
37
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
38
|
-
"@agoric/orchestration": "0.1.1-dev-
|
|
39
|
-
"@agoric/store": "0.9.3-dev-
|
|
40
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
41
|
-
"@agoric/vow": "0.1.1-dev-
|
|
42
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
34
|
+
"@agoric/client-utils": "0.1.1-dev-419df4e.0+419df4e",
|
|
35
|
+
"@agoric/ertp": "0.16.3-dev-419df4e.0+419df4e",
|
|
36
|
+
"@agoric/internal": "0.3.3-dev-419df4e.0+419df4e",
|
|
37
|
+
"@agoric/notifier": "0.6.3-dev-419df4e.0+419df4e",
|
|
38
|
+
"@agoric/orchestration": "0.1.1-dev-419df4e.0+419df4e",
|
|
39
|
+
"@agoric/store": "0.9.3-dev-419df4e.0+419df4e",
|
|
40
|
+
"@agoric/vat-data": "0.5.3-dev-419df4e.0+419df4e",
|
|
41
|
+
"@agoric/vow": "0.1.1-dev-419df4e.0+419df4e",
|
|
42
|
+
"@agoric/zoe": "0.26.3-dev-419df4e.0+419df4e",
|
|
43
43
|
"@cosmjs/proto-signing": "^0.32.4",
|
|
44
44
|
"@cosmjs/stargate": "^0.32.4",
|
|
45
45
|
"@endo/base64": "^1.0.9",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"publishConfig": {
|
|
79
79
|
"access": "public"
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "419df4ee7ce03499f30e7327c74e95a338201023"
|
|
82
82
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { boardSlottingMarshaller } from '@agoric/client-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @import {BridgeAction} from '@agoric/smart-wallet/src/smartWallet.js';
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const marshaller = boardSlottingMarshaller();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {BridgeAction} bridgeAction
|
|
11
|
+
* @param {Pick<import('stream').Writable,'write'>} stdout
|
|
12
|
+
*/
|
|
13
|
+
const outputAction = (bridgeAction, stdout) => {
|
|
14
|
+
const capData = marshaller.toCapData(harden(bridgeAction));
|
|
15
|
+
stdout.write(JSON.stringify(capData));
|
|
16
|
+
stdout.write('\n');
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const sendHint =
|
|
20
|
+
'Now use `agoric wallet send ...` to sign and broadcast the offer.\n';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {BridgeAction} bridgeAction
|
|
24
|
+
* @param {{
|
|
25
|
+
* stdout: Pick<import('stream').Writable,'write'>,
|
|
26
|
+
* stderr: Pick<import('stream').Writable,'write'>,
|
|
27
|
+
* }} io
|
|
28
|
+
*/
|
|
29
|
+
export const outputActionAndHint = (bridgeAction, { stdout, stderr }) => {
|
|
30
|
+
outputAction(bridgeAction, stdout);
|
|
31
|
+
stderr.write(sendHint);
|
|
32
|
+
};
|
package/src/cli/cli.js
CHANGED
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
readFile as readAsync,
|
|
13
13
|
writeFile as writeAsync,
|
|
14
14
|
} from 'node:fs/promises';
|
|
15
|
-
import
|
|
15
|
+
import { addConfigCommands } from './config-commands.js';
|
|
16
|
+
import { addOperatorCommands } from './operator-commands.js';
|
|
17
|
+
import * as configLib from './config.js';
|
|
16
18
|
import transferLib from './transfer.js';
|
|
17
19
|
import { makeFile } from '../util/file.js';
|
|
18
20
|
|
|
@@ -45,108 +47,16 @@ export const initProgram = (
|
|
|
45
47
|
`${defaultHome}/.fast-usdc/`,
|
|
46
48
|
);
|
|
47
49
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return
|
|
50
|
+
const makeConfigFile = () => {
|
|
51
|
+
const getConfigPath = () => {
|
|
52
|
+
const { home: configDir } = program.opts();
|
|
53
|
+
return `${configDir}config.json`;
|
|
54
|
+
};
|
|
55
|
+
return makeFile(getConfigPath(), readFile, writeFile, mkdir, exists);
|
|
54
56
|
};
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
config
|
|
60
|
-
.command('show')
|
|
61
|
-
.description('Show current config')
|
|
62
|
-
.action(async () => {
|
|
63
|
-
await configHelpers.show(makeConfigFile());
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
config
|
|
67
|
-
.command('init')
|
|
68
|
-
.description('Set initial config values')
|
|
69
|
-
.requiredOption(
|
|
70
|
-
'--noble-seed <seed>',
|
|
71
|
-
'Seed phrase for Noble account. CAUTION: Stored unencrypted in file system',
|
|
72
|
-
)
|
|
73
|
-
.requiredOption(
|
|
74
|
-
'--eth-seed <seed>',
|
|
75
|
-
'Seed phrase for Ethereum account. CAUTION: Stored unencrypted in file system',
|
|
76
|
-
)
|
|
77
|
-
.requiredOption(
|
|
78
|
-
'--agoric-seed <seed>',
|
|
79
|
-
'Seed phrase for Agoric LP account. CAUTION: Stored unencrypted in file system',
|
|
80
|
-
)
|
|
81
|
-
.option(
|
|
82
|
-
'--agoric-rpc [url]',
|
|
83
|
-
'Agoric RPC endpoint',
|
|
84
|
-
'http://127.0.0.1:26656',
|
|
85
|
-
)
|
|
86
|
-
.option(
|
|
87
|
-
'--agoric-api [url]',
|
|
88
|
-
'Agoric RPC endpoint',
|
|
89
|
-
'http://127.0.0.1:1317',
|
|
90
|
-
)
|
|
91
|
-
.option('--noble-rpc [url]', 'Noble RPC endpoint', 'http://127.0.0.1:26657')
|
|
92
|
-
.option('--noble-api [url]', 'Noble API endpoint', 'http://127.0.0.1:1318')
|
|
93
|
-
.option('--eth-rpc [url]', 'Ethereum RPC Endpoint', 'http://127.0.0.1:8545')
|
|
94
|
-
.option(
|
|
95
|
-
'--noble-to-agoric-channel [channel]',
|
|
96
|
-
'Channel ID on Noble for Agoric',
|
|
97
|
-
'channel-21',
|
|
98
|
-
)
|
|
99
|
-
.option(
|
|
100
|
-
'--token-messenger-address [address]',
|
|
101
|
-
'Address of TokenMessenger contract',
|
|
102
|
-
// Default to ETH mainnet contract address. For ETH sepolia, use 0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5
|
|
103
|
-
'0xbd3fa81b58ba92a82136038b25adec7066af3155',
|
|
104
|
-
)
|
|
105
|
-
.option(
|
|
106
|
-
'--token-contract-address [address]',
|
|
107
|
-
'Address of USDC token contract',
|
|
108
|
-
// Detault to ETH mainnet token address. For ETH sepolia, use 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238
|
|
109
|
-
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
110
|
-
)
|
|
111
|
-
.action(async options => {
|
|
112
|
-
await configHelpers.init(makeConfigFile(), options);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
config
|
|
116
|
-
.command('update')
|
|
117
|
-
.description('Update config values')
|
|
118
|
-
.option(
|
|
119
|
-
'--noble-seed [string]',
|
|
120
|
-
'Seed phrase for Noble account. CAUTION: Stored unencrypted in file system',
|
|
121
|
-
)
|
|
122
|
-
.option(
|
|
123
|
-
'--eth-seed [string]',
|
|
124
|
-
'Seed phrase for Ethereum account. CAUTION: Stored unencrypted in file system',
|
|
125
|
-
)
|
|
126
|
-
.option(
|
|
127
|
-
'--agoric-seed <seed>',
|
|
128
|
-
'Seed phrase for Agoric LP account. CAUTION: Stored unencrypted in file system',
|
|
129
|
-
)
|
|
130
|
-
.option('--agoric-rpc [url]', 'Agoric RPC endpoint')
|
|
131
|
-
.option('--agoric-api [url]', 'Agoric API endpoint')
|
|
132
|
-
.option('--noble-rpc [url]', 'Noble RPC endpoint')
|
|
133
|
-
.option('--noble-api [url]', 'Noble API endpoint')
|
|
134
|
-
.option('--eth-rpc [url]', 'Ethereum RPC Endpoint')
|
|
135
|
-
.option(
|
|
136
|
-
'--noble-to-agoric-channel [channel]',
|
|
137
|
-
'Channel ID on Noble for Agoric',
|
|
138
|
-
)
|
|
139
|
-
.option(
|
|
140
|
-
'--token-messenger-address [address]',
|
|
141
|
-
'Address of TokenMessenger contract',
|
|
142
|
-
)
|
|
143
|
-
.option(
|
|
144
|
-
'--token-contract-address [address]',
|
|
145
|
-
'Address of USDC token contract',
|
|
146
|
-
)
|
|
147
|
-
.action(async options => {
|
|
148
|
-
await configHelpers.update(makeConfigFile(), options);
|
|
149
|
-
});
|
|
58
|
+
addConfigCommands(program, configHelpers, makeConfigFile);
|
|
59
|
+
addOperatorCommands(program);
|
|
150
60
|
|
|
151
61
|
/** @param {string} value */
|
|
152
62
|
const parseDecimal = value => {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Command} from 'commander';
|
|
3
|
+
* @import {File} from '../util/file.js';
|
|
4
|
+
* @import * as ConfigHelpers from './config.js';
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {Command} program
|
|
9
|
+
* @param {ConfigHelpers} configHelpers
|
|
10
|
+
* @param {() => File} makeConfigFile
|
|
11
|
+
*/
|
|
12
|
+
export const addConfigCommands = (program, configHelpers, makeConfigFile) => {
|
|
13
|
+
const config = program.command('config').description('Manage config');
|
|
14
|
+
|
|
15
|
+
config
|
|
16
|
+
.command('show')
|
|
17
|
+
.description('Show current config')
|
|
18
|
+
.action(async () => {
|
|
19
|
+
await configHelpers.show(makeConfigFile());
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
config
|
|
23
|
+
.command('init')
|
|
24
|
+
.description('Set initial config values')
|
|
25
|
+
.requiredOption(
|
|
26
|
+
'--noble-seed <seed>',
|
|
27
|
+
'Seed phrase for Noble account. CAUTION: Stored unencrypted in file system',
|
|
28
|
+
)
|
|
29
|
+
.requiredOption(
|
|
30
|
+
'--eth-seed <seed>',
|
|
31
|
+
'Seed phrase for Ethereum account. CAUTION: Stored unencrypted in file system',
|
|
32
|
+
)
|
|
33
|
+
.requiredOption(
|
|
34
|
+
'--agoric-seed <seed>',
|
|
35
|
+
'Seed phrase for Agoric LP account. CAUTION: Stored unencrypted in file system',
|
|
36
|
+
)
|
|
37
|
+
.option(
|
|
38
|
+
'--agoric-rpc [url]',
|
|
39
|
+
'Agoric RPC endpoint',
|
|
40
|
+
'http://127.0.0.1:26656',
|
|
41
|
+
)
|
|
42
|
+
.option(
|
|
43
|
+
'--agoric-api [url]',
|
|
44
|
+
'Agoric RPC endpoint',
|
|
45
|
+
'http://127.0.0.1:1317',
|
|
46
|
+
)
|
|
47
|
+
.option('--noble-rpc [url]', 'Noble RPC endpoint', 'http://127.0.0.1:26657')
|
|
48
|
+
.option('--noble-api [url]', 'Noble API endpoint', 'http://127.0.0.1:1318')
|
|
49
|
+
.option('--eth-rpc [url]', 'Ethereum RPC Endpoint', 'http://127.0.0.1:8545')
|
|
50
|
+
.option(
|
|
51
|
+
'--noble-to-agoric-channel [channel]',
|
|
52
|
+
'Channel ID on Noble for Agoric',
|
|
53
|
+
'channel-21',
|
|
54
|
+
)
|
|
55
|
+
.option(
|
|
56
|
+
'--token-messenger-address [address]',
|
|
57
|
+
'Address of TokenMessenger contract',
|
|
58
|
+
// Default to ETH mainnet contract address. For ETH sepolia, use 0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5
|
|
59
|
+
'0xbd3fa81b58ba92a82136038b25adec7066af3155',
|
|
60
|
+
)
|
|
61
|
+
.option(
|
|
62
|
+
'--token-contract-address [address]',
|
|
63
|
+
'Address of USDC token contract',
|
|
64
|
+
// Detault to ETH mainnet token address. For ETH sepolia, use 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238
|
|
65
|
+
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
66
|
+
)
|
|
67
|
+
.action(async options => {
|
|
68
|
+
await configHelpers.init(makeConfigFile(), options);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
config
|
|
72
|
+
.command('update')
|
|
73
|
+
.description('Update config values')
|
|
74
|
+
.option(
|
|
75
|
+
'--noble-seed [string]',
|
|
76
|
+
'Seed phrase for Noble account. CAUTION: Stored unencrypted in file system',
|
|
77
|
+
)
|
|
78
|
+
.option(
|
|
79
|
+
'--eth-seed [string]',
|
|
80
|
+
'Seed phrase for Ethereum account. CAUTION: Stored unencrypted in file system',
|
|
81
|
+
)
|
|
82
|
+
.option(
|
|
83
|
+
'--agoric-seed <seed>',
|
|
84
|
+
'Seed phrase for Agoric LP account. CAUTION: Stored unencrypted in file system',
|
|
85
|
+
)
|
|
86
|
+
.option('--agoric-rpc [url]', 'Agoric RPC endpoint')
|
|
87
|
+
.option('--agoric-api [url]', 'Agoric API endpoint')
|
|
88
|
+
.option('--noble-rpc [url]', 'Noble RPC endpoint')
|
|
89
|
+
.option('--noble-api [url]', 'Noble API endpoint')
|
|
90
|
+
.option('--eth-rpc [url]', 'Ethereum RPC Endpoint')
|
|
91
|
+
.option(
|
|
92
|
+
'--noble-to-agoric-channel [channel]',
|
|
93
|
+
'Channel ID on Noble for Agoric',
|
|
94
|
+
)
|
|
95
|
+
.option(
|
|
96
|
+
'--token-messenger-address [address]',
|
|
97
|
+
'Address of TokenMessenger contract',
|
|
98
|
+
)
|
|
99
|
+
.option(
|
|
100
|
+
'--token-contract-address [address]',
|
|
101
|
+
'Address of USDC token contract',
|
|
102
|
+
)
|
|
103
|
+
.action(async options => {
|
|
104
|
+
await configHelpers.update(makeConfigFile(), options);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return config;
|
|
108
|
+
};
|
package/src/cli/config.js
CHANGED
|
@@ -15,10 +15,10 @@ import { stdin as input, stdout as output } from 'node:process';
|
|
|
15
15
|
}} ConfigOpts
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
/** @import {
|
|
18
|
+
/** @import { File } from '../util/file' */
|
|
19
19
|
|
|
20
|
-
const init = async (
|
|
21
|
-
/** @type {
|
|
20
|
+
export const init = async (
|
|
21
|
+
/** @type {File} */ configFile,
|
|
22
22
|
/** @type {ConfigOpts} */ options,
|
|
23
23
|
out = console,
|
|
24
24
|
rl = readline.createInterface({ input, output }),
|
|
@@ -52,8 +52,8 @@ const init = async (
|
|
|
52
52
|
await writeConfig();
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
const update = async (
|
|
56
|
-
/** @type {
|
|
55
|
+
export const update = async (
|
|
56
|
+
/** @type {File} */ configFile,
|
|
57
57
|
/** @type {Partial<ConfigOpts>} */ options,
|
|
58
58
|
out = console,
|
|
59
59
|
) => {
|
|
@@ -83,7 +83,7 @@ const update = async (
|
|
|
83
83
|
await updateConfig({ ...JSON.parse(file), ...options });
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
-
const show = async (/** @type {
|
|
86
|
+
export const show = async (/** @type {File} */ configFile, out = console) => {
|
|
87
87
|
let contents;
|
|
88
88
|
await null;
|
|
89
89
|
try {
|
|
@@ -97,5 +97,3 @@ const show = async (/** @type {file} */ configFile, out = console) => {
|
|
|
97
97
|
out.log(`Config found at ${configFile.path}:`);
|
|
98
98
|
out.log(contents);
|
|
99
99
|
};
|
|
100
|
-
|
|
101
|
-
export default { init, update, show };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-env node */
|
|
2
|
+
/**
|
|
3
|
+
* @import {Command} from 'commander';
|
|
4
|
+
* @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
|
|
5
|
+
* @import {ExecuteOfferAction} from '@agoric/smart-wallet/src/smartWallet.js';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
|
|
9
|
+
import { INVITATION_MAKERS_DESC } from '../exos/transaction-feed.js';
|
|
10
|
+
import { outputActionAndHint } from './bridge-action.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {Command} program
|
|
14
|
+
*/
|
|
15
|
+
export const addOperatorCommands = program => {
|
|
16
|
+
const operator = program
|
|
17
|
+
.command('operator')
|
|
18
|
+
.description('Oracle operator commands');
|
|
19
|
+
|
|
20
|
+
operator
|
|
21
|
+
.command('accept')
|
|
22
|
+
.description('Accept invitation to be an operator')
|
|
23
|
+
.addHelpText(
|
|
24
|
+
'after',
|
|
25
|
+
'\nPipe the STDOUT to a file such as accept.json, then use the Agoric CLI to broadcast it:\n agoric wallet send --offer accept.json --from gov1 --keyring-backend="test"',
|
|
26
|
+
)
|
|
27
|
+
.option(
|
|
28
|
+
'--offerId <string>',
|
|
29
|
+
'Offer id',
|
|
30
|
+
String,
|
|
31
|
+
`operatorAccept-${Date.now()}`,
|
|
32
|
+
)
|
|
33
|
+
.action(async opts => {
|
|
34
|
+
const networkConfig = await fetchEnvNetworkConfig({
|
|
35
|
+
env: process.env,
|
|
36
|
+
fetch,
|
|
37
|
+
});
|
|
38
|
+
const vsk = await makeVstorageKit({ fetch }, networkConfig);
|
|
39
|
+
const instance = vsk.agoricNames.instance.fastUsdc;
|
|
40
|
+
assert(instance, 'fastUsdc instance not in agoricNames');
|
|
41
|
+
|
|
42
|
+
/** @type {OfferSpec} */
|
|
43
|
+
const offer = {
|
|
44
|
+
id: opts.offerId,
|
|
45
|
+
invitationSpec: {
|
|
46
|
+
source: 'purse',
|
|
47
|
+
instance,
|
|
48
|
+
description: INVITATION_MAKERS_DESC,
|
|
49
|
+
},
|
|
50
|
+
proposal: {},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** @type {ExecuteOfferAction} */
|
|
54
|
+
const bridgeAction = {
|
|
55
|
+
method: 'executeOffer',
|
|
56
|
+
offer,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
outputActionAndHint(bridgeAction, {
|
|
60
|
+
stderr: process.stderr,
|
|
61
|
+
stdout: process.stdout,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
operator
|
|
66
|
+
.command('attest')
|
|
67
|
+
.description('Attest to an observed Fast USDC transfer')
|
|
68
|
+
.requiredOption('--previousOfferId <string>', 'Offer id', String)
|
|
69
|
+
.action(async options => {
|
|
70
|
+
const { previousOfferId } = options;
|
|
71
|
+
console.error(
|
|
72
|
+
'TODO: Implement attest logic for request:',
|
|
73
|
+
previousOfferId,
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return operator;
|
|
78
|
+
};
|
package/src/cli/transfer.js
CHANGED
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
} from '../util/noble.js';
|
|
10
10
|
import { queryFastUSDCLocalChainAccount } from '../util/agoric.js';
|
|
11
11
|
|
|
12
|
-
/** @import {
|
|
12
|
+
/** @import { File } from '../util/file' */
|
|
13
13
|
/** @import { VStorage } from '@agoric/client-utils' */
|
|
14
14
|
/** @import { SigningStargateClient } from '@cosmjs/stargate' */
|
|
15
15
|
/** @import { JsonRpcProvider as ethProvider } from 'ethers' */
|
|
16
16
|
|
|
17
17
|
const transfer = async (
|
|
18
|
-
/** @type {
|
|
18
|
+
/** @type {File} */ configFile,
|
|
19
19
|
/** @type {string} */ amount,
|
|
20
20
|
/** @type {string} */ destination,
|
|
21
21
|
out = console,
|
package/src/exos/settler.js
CHANGED
|
@@ -221,7 +221,7 @@ export const prepareSettler = (
|
|
|
221
221
|
repayer.repay(settlingSeat, split);
|
|
222
222
|
|
|
223
223
|
// update status manager, marking tx `SETTLED`
|
|
224
|
-
statusManager.disbursed(txHash
|
|
224
|
+
statusManager.disbursed(txHash);
|
|
225
225
|
},
|
|
226
226
|
/**
|
|
227
227
|
* @param {EvmHash | undefined} txHash
|
|
@@ -248,7 +248,7 @@ export const prepareSettler = (
|
|
|
248
248
|
},
|
|
249
249
|
transferHandler: {
|
|
250
250
|
/**
|
|
251
|
-
* @param {unknown}
|
|
251
|
+
* @param {unknown} _result
|
|
252
252
|
* @param {SettlerTransferCtx} ctx
|
|
253
253
|
*
|
|
254
254
|
* @typedef {{
|
|
@@ -257,7 +257,7 @@ export const prepareSettler = (
|
|
|
257
257
|
* amount: NatValue;
|
|
258
258
|
* }} SettlerTransferCtx
|
|
259
259
|
*/
|
|
260
|
-
onFulfilled(
|
|
260
|
+
onFulfilled(_result, ctx) {
|
|
261
261
|
const { txHash, sender, amount } = ctx;
|
|
262
262
|
statusManager.forwarded(txHash, sender, amount);
|
|
263
263
|
},
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { M } from '@endo/patterns';
|
|
2
2
|
import { Fail, makeError, q } from '@endo/errors';
|
|
3
|
-
|
|
4
3
|
import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js';
|
|
4
|
+
import { E } from '@endo/eventual-send';
|
|
5
|
+
import { makeTracer } from '@agoric/internal';
|
|
5
6
|
import {
|
|
6
7
|
CctpTxEvidenceShape,
|
|
7
8
|
EvmHashShape,
|
|
8
9
|
PendingTxShape,
|
|
9
10
|
} from '../type-guards.js';
|
|
10
|
-
import { PendingTxStatus } from '../constants.js';
|
|
11
|
+
import { PendingTxStatus, TxStatus } from '../constants.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @import {MapStore, SetStore} from '@agoric/store';
|
|
14
15
|
* @import {Zone} from '@agoric/zone';
|
|
15
|
-
* @import {CctpTxEvidence, NobleAddress, SeenTxKey, PendingTxKey, PendingTx, EvmHash} from '../types.js';
|
|
16
|
+
* @import {CctpTxEvidence, NobleAddress, SeenTxKey, PendingTxKey, PendingTx, EvmHash, LogFn} from '../types.js';
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -53,6 +54,12 @@ const seenTxKeyOf = evidence => {
|
|
|
53
54
|
return `seenTx:${JSON.stringify([txHash, chainId])}`;
|
|
54
55
|
};
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @typedef {{
|
|
59
|
+
* log?: LogFn;
|
|
60
|
+
* }} StatusManagerPowers
|
|
61
|
+
*/
|
|
62
|
+
|
|
56
63
|
/**
|
|
57
64
|
* The `StatusManager` keeps track of Pending and Seen Transactions
|
|
58
65
|
* via {@link PendingTxStatus} states, aiding in coordination between the `Advancer`
|
|
@@ -61,8 +68,16 @@ const seenTxKeyOf = evidence => {
|
|
|
61
68
|
* XXX consider separate facets for `Advancing` and `Settling` capabilities.
|
|
62
69
|
*
|
|
63
70
|
* @param {Zone} zone
|
|
71
|
+
* @param {() => Promise<StorageNode>} makeStatusNode
|
|
72
|
+
* @param {StatusManagerPowers} caps
|
|
64
73
|
*/
|
|
65
|
-
export const prepareStatusManager =
|
|
74
|
+
export const prepareStatusManager = (
|
|
75
|
+
zone,
|
|
76
|
+
makeStatusNode,
|
|
77
|
+
{
|
|
78
|
+
log = makeTracer('Advancer', true),
|
|
79
|
+
} = /** @type {StatusManagerPowers} */ ({}),
|
|
80
|
+
) => {
|
|
66
81
|
/** @type {MapStore<PendingTxKey, PendingTx[]>} */
|
|
67
82
|
const pendingTxs = zone.mapStore('PendingTxs', {
|
|
68
83
|
keyShape: M.string(),
|
|
@@ -74,6 +89,17 @@ export const prepareStatusManager = zone => {
|
|
|
74
89
|
keyShape: M.string(),
|
|
75
90
|
});
|
|
76
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @param {CctpTxEvidence['txHash']} hash
|
|
94
|
+
* @param {TxStatus} status
|
|
95
|
+
*/
|
|
96
|
+
const recordStatus = (hash, status) => {
|
|
97
|
+
const statusNodeP = makeStatusNode();
|
|
98
|
+
const txnNodeP = E(statusNodeP).makeChildNode(hash);
|
|
99
|
+
// Don't await, just writing to vstorage.
|
|
100
|
+
void E(txnNodeP).setValue(status);
|
|
101
|
+
};
|
|
102
|
+
|
|
77
103
|
/**
|
|
78
104
|
* Ensures that `txHash+chainId` has not been processed
|
|
79
105
|
* and adds entry to `seenTxs` set.
|
|
@@ -95,6 +121,7 @@ export const prepareStatusManager = zone => {
|
|
|
95
121
|
pendingTxKeyOf(evidence),
|
|
96
122
|
harden({ ...evidence, status }),
|
|
97
123
|
);
|
|
124
|
+
recordStatus(evidence.txHash, status);
|
|
98
125
|
};
|
|
99
126
|
|
|
100
127
|
return zone.exo(
|
|
@@ -118,9 +145,7 @@ export const prepareStatusManager = zone => {
|
|
|
118
145
|
M.undefined(),
|
|
119
146
|
),
|
|
120
147
|
),
|
|
121
|
-
disbursed: M.call(EvmHashShape
|
|
122
|
-
M.undefined(),
|
|
123
|
-
),
|
|
148
|
+
disbursed: M.call(EvmHashShape).returns(M.undefined()),
|
|
124
149
|
forwarded: M.call(M.opt(EvmHashShape), M.string(), M.nat()).returns(
|
|
125
150
|
M.undefined(),
|
|
126
151
|
),
|
|
@@ -163,6 +188,7 @@ export const prepareStatusManager = zone => {
|
|
|
163
188
|
: PendingTxStatus.AdvanceFailed;
|
|
164
189
|
const txpost = { ...tx, status };
|
|
165
190
|
pendingTxs.set(key, harden([...prefix, txpost, ...suffix]));
|
|
191
|
+
recordStatus(tx.txHash, status);
|
|
166
192
|
},
|
|
167
193
|
|
|
168
194
|
/**
|
|
@@ -219,12 +245,9 @@ export const prepareStatusManager = zone => {
|
|
|
219
245
|
* Mark a transaction as `DISBURSED`
|
|
220
246
|
*
|
|
221
247
|
* @param {EvmHash} txHash
|
|
222
|
-
* @param {NobleAddress} address
|
|
223
|
-
* @param {bigint} amount
|
|
224
248
|
*/
|
|
225
|
-
disbursed(txHash
|
|
226
|
-
|
|
227
|
-
console.log('TODO: vstorage update', { txHash, address, amount });
|
|
249
|
+
disbursed(txHash) {
|
|
250
|
+
recordStatus(txHash, TxStatus.Disbursed);
|
|
228
251
|
},
|
|
229
252
|
|
|
230
253
|
/**
|
|
@@ -235,8 +258,14 @@ export const prepareStatusManager = zone => {
|
|
|
235
258
|
* @param {bigint} amount
|
|
236
259
|
*/
|
|
237
260
|
forwarded(txHash, address, amount) {
|
|
238
|
-
|
|
239
|
-
|
|
261
|
+
if (txHash) {
|
|
262
|
+
recordStatus(txHash, TxStatus.Forwarded);
|
|
263
|
+
} else {
|
|
264
|
+
// TODO store (early) `Minted` transactions to check against incoming evidence
|
|
265
|
+
log(
|
|
266
|
+
`⚠️ Forwarded minted amount ${amount} from account ${address} before it was observed.`,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
240
269
|
},
|
|
241
270
|
|
|
242
271
|
/**
|
|
@@ -29,6 +29,8 @@ import * as flows from './fast-usdc.flows.js';
|
|
|
29
29
|
|
|
30
30
|
const trace = makeTracer('FastUsdc');
|
|
31
31
|
|
|
32
|
+
const STATUS_NODE = 'status';
|
|
33
|
+
|
|
32
34
|
/**
|
|
33
35
|
* @import {HostInterface} from '@agoric/async-flow';
|
|
34
36
|
* @import {CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration';
|
|
@@ -84,7 +86,9 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
|
|
|
84
86
|
marshaller,
|
|
85
87
|
);
|
|
86
88
|
|
|
87
|
-
const
|
|
89
|
+
const makeStatusNode = () =>
|
|
90
|
+
E(privateArgs.storageNode).makeChildNode(STATUS_NODE);
|
|
91
|
+
const statusManager = prepareStatusManager(zone, makeStatusNode);
|
|
88
92
|
|
|
89
93
|
const { USDC } = terms.brands;
|
|
90
94
|
const { withdrawToSeat } = tools.zoeTools;
|
package/src/util/file.js
CHANGED