@agoric/fast-usdc 0.1.1-other-dev-3eb1a1d.0 → 0.2.0-u18.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/README.md +43 -0
- package/package.json +19 -16
- package/src/cli/bridge-action.js +40 -0
- package/src/cli/cli.js +45 -152
- package/src/cli/config-commands.js +108 -0
- package/src/cli/config.js +15 -9
- package/src/cli/lp-commands.js +178 -0
- package/src/cli/operator-commands.js +145 -0
- package/src/cli/transfer.js +61 -11
- package/src/constants.js +25 -2
- package/src/exos/advancer.js +149 -103
- package/src/exos/liquidity-pool.js +52 -50
- package/src/exos/operator-kit.js +16 -10
- package/src/exos/settler.js +295 -58
- package/src/exos/status-manager.js +270 -57
- package/src/exos/transaction-feed.js +93 -35
- package/src/fast-usdc-policy.core.js +75 -0
- package/src/fast-usdc.contract.js +152 -63
- package/src/fast-usdc.flows.js +10 -0
- package/src/fast-usdc.start.js +44 -14
- package/src/type-guards.js +42 -20
- package/src/types.ts +58 -12
- package/src/util/agoric.js +1 -1
- package/src/util/bank.js +12 -0
- package/src/util/cctp.js +1 -1
- package/src/util/file.js +1 -1
- package/src/utils/deploy-config.js +166 -0
- package/tools/cli-tools.ts +9 -0
- package/tools/mock-io.ts +14 -0
- package/src/exos/README.md +0 -26
- package/src/utils/address.js +0 -71
package/src/type-guards.js
CHANGED
|
@@ -6,7 +6,7 @@ import { PendingTxStatus } from './constants.js';
|
|
|
6
6
|
* @import {TypedPattern} from '@agoric/internal';
|
|
7
7
|
* @import {FastUsdcTerms} from './fast-usdc.contract.js';
|
|
8
8
|
* @import {USDCProposalShapes} from './pool-share-math.js';
|
|
9
|
-
* @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy} from './types.js';
|
|
9
|
+
* @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook, EvmAddress, EvmHash, RiskAssessment, EvidenceWithRisk} from './types.js';
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -21,7 +21,7 @@ export const makeProposalShapes = ({ PoolShares, USDC }) => {
|
|
|
21
21
|
/** @type {TypedPattern<USDCProposalShapes['deposit']>} */
|
|
22
22
|
const deposit = M.splitRecord(
|
|
23
23
|
{ give: { USDC: makeNatAmountShape(USDC, 1n) } },
|
|
24
|
-
{ want: { PoolShare: makeNatAmountShape(PoolShares) } },
|
|
24
|
+
{ want: M.splitRecord({}, { PoolShare: makeNatAmountShape(PoolShares) }) },
|
|
25
25
|
);
|
|
26
26
|
/** @type {TypedPattern<USDCProposalShapes['withdraw']>} */
|
|
27
27
|
const withdraw = M.splitRecord({
|
|
@@ -36,12 +36,28 @@ export const FastUSDCTermsShape = harden({
|
|
|
36
36
|
usdcDenom: M.string(),
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
/** @type {TypedPattern<
|
|
39
|
+
/** @type {TypedPattern<EvmAddress>} */
|
|
40
|
+
export const EvmAddressShape = M.string({
|
|
41
|
+
// 0x + 40 hex digits
|
|
42
|
+
stringLengthLimit: 42,
|
|
43
|
+
});
|
|
44
|
+
harden(EvmAddressShape);
|
|
45
|
+
|
|
46
|
+
/** @type {TypedPattern<EvmHash>} */
|
|
40
47
|
export const EvmHashShape = M.string({
|
|
41
48
|
stringLengthLimit: 66,
|
|
42
49
|
});
|
|
43
50
|
harden(EvmHashShape);
|
|
44
51
|
|
|
52
|
+
/** @type {TypedPattern<RiskAssessment>} */
|
|
53
|
+
export const RiskAssessmentShape = M.splitRecord(
|
|
54
|
+
{},
|
|
55
|
+
{
|
|
56
|
+
risksIdentified: M.arrayOf(M.string()),
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
harden(RiskAssessmentShape);
|
|
60
|
+
|
|
45
61
|
/** @type {TypedPattern<CctpTxEvidence>} */
|
|
46
62
|
export const CctpTxEvidenceShape = {
|
|
47
63
|
aux: {
|
|
@@ -49,17 +65,24 @@ export const CctpTxEvidenceShape = {
|
|
|
49
65
|
recipientAddress: M.string(),
|
|
50
66
|
},
|
|
51
67
|
blockHash: EvmHashShape,
|
|
52
|
-
blockNumber: M.
|
|
53
|
-
blockTimestamp: M.bigint(),
|
|
68
|
+
blockNumber: M.nat(),
|
|
54
69
|
chainId: M.number(),
|
|
55
70
|
tx: {
|
|
56
|
-
amount: M.
|
|
71
|
+
amount: M.nat(),
|
|
57
72
|
forwardingAddress: M.string(),
|
|
73
|
+
sender: EvmAddressShape,
|
|
58
74
|
},
|
|
59
75
|
txHash: EvmHashShape,
|
|
60
76
|
};
|
|
61
77
|
harden(CctpTxEvidenceShape);
|
|
62
78
|
|
|
79
|
+
/** @type {TypedPattern<EvidenceWithRisk>} */
|
|
80
|
+
export const EvidenceWithRiskShape = {
|
|
81
|
+
evidence: CctpTxEvidenceShape,
|
|
82
|
+
risk: RiskAssessmentShape,
|
|
83
|
+
};
|
|
84
|
+
harden(EvidenceWithRiskShape);
|
|
85
|
+
|
|
63
86
|
/** @type {TypedPattern<PendingTx>} */
|
|
64
87
|
// @ts-expect-error TypedPattern not recognized as record
|
|
65
88
|
export const PendingTxShape = {
|
|
@@ -68,10 +91,12 @@ export const PendingTxShape = {
|
|
|
68
91
|
};
|
|
69
92
|
harden(PendingTxShape);
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
|
|
94
|
+
/** @type {TypedPattern<AddressHook>} */
|
|
95
|
+
export const AddressHookShape = {
|
|
96
|
+
baseAddress: M.string(),
|
|
97
|
+
query: { EUD: M.string() },
|
|
73
98
|
};
|
|
74
|
-
harden(
|
|
99
|
+
harden(AddressHookShape);
|
|
75
100
|
|
|
76
101
|
const NatAmountShape = { brand: BrandShape, value: M.nat() };
|
|
77
102
|
/** @type {TypedPattern<FeeConfig>} */
|
|
@@ -95,16 +120,13 @@ export const PoolMetricsShape = {
|
|
|
95
120
|
harden(PoolMetricsShape);
|
|
96
121
|
|
|
97
122
|
/** @type {TypedPattern<ChainPolicy>} */
|
|
98
|
-
export const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
{ chainType: M.number() },
|
|
106
|
-
);
|
|
107
|
-
harden(ChainPoliciesShape);
|
|
123
|
+
export const ChainPolicyShape = {
|
|
124
|
+
attenuatedCttpBridgeAddress: EvmHashShape,
|
|
125
|
+
cctpTokenMessengerAddress: EvmHashShape,
|
|
126
|
+
confirmations: M.number(),
|
|
127
|
+
chainId: M.number(),
|
|
128
|
+
};
|
|
129
|
+
harden(ChainPolicyShape);
|
|
108
130
|
|
|
109
131
|
/**
|
|
110
132
|
* @type {TypedPattern<FeedPolicy>}
|
|
@@ -116,7 +138,7 @@ export const FeedPolicyShape = M.splitRecord(
|
|
|
116
138
|
{
|
|
117
139
|
nobleDomainId: M.number(),
|
|
118
140
|
nobleAgoricChannelId: M.string(),
|
|
119
|
-
chainPolicies: M.recordOf(M.string(),
|
|
141
|
+
chainPolicies: M.recordOf(M.string(), ChainPolicyShape),
|
|
120
142
|
},
|
|
121
143
|
{ eventFilter: M.string() },
|
|
122
144
|
);
|
package/src/types.ts
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ChainAddress,
|
|
3
|
+
CosmosChainInfo,
|
|
4
|
+
Denom,
|
|
5
|
+
DenomDetail,
|
|
6
|
+
} from '@agoric/orchestration';
|
|
2
7
|
import type { IBCChannelID } from '@agoric/vats';
|
|
3
8
|
import type { Amount } from '@agoric/ertp';
|
|
4
|
-
import type {
|
|
9
|
+
import type { CopyRecord, Passable } from '@endo/pass-style';
|
|
10
|
+
import type { PendingTxStatus, TxStatus } from './constants.js';
|
|
11
|
+
import type { FastUsdcTerms } from './fast-usdc.contract.js';
|
|
12
|
+
import type { RepayAmountKWR } from './exos/liquidity-pool.js';
|
|
5
13
|
|
|
6
14
|
export type EvmHash = `0x${string}`;
|
|
15
|
+
export type EvmAddress = `0x${string & { length: 40 }}`;
|
|
7
16
|
export type NobleAddress = `noble1${string}`;
|
|
8
17
|
export type EvmChainID = number;
|
|
9
18
|
export type EvmChainName = string;
|
|
10
19
|
|
|
20
|
+
export interface RiskAssessment {
|
|
21
|
+
risksIdentified?: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
export interface CctpTxEvidence {
|
|
12
25
|
/** from Noble RPC */
|
|
13
26
|
aux: {
|
|
@@ -16,28 +29,38 @@ export interface CctpTxEvidence {
|
|
|
16
29
|
};
|
|
17
30
|
blockHash: EvmHash;
|
|
18
31
|
blockNumber: bigint;
|
|
19
|
-
blockTimestamp: bigint;
|
|
20
32
|
chainId: number;
|
|
21
33
|
/** data covered by signature (aka txHash) */
|
|
22
34
|
tx: {
|
|
23
35
|
amount: bigint;
|
|
24
36
|
forwardingAddress: NobleAddress;
|
|
37
|
+
sender: EvmAddress;
|
|
25
38
|
};
|
|
26
39
|
txHash: EvmHash;
|
|
27
40
|
}
|
|
28
41
|
|
|
42
|
+
export interface EvidenceWithRisk {
|
|
43
|
+
evidence: CctpTxEvidence;
|
|
44
|
+
risk: RiskAssessment;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 'evidence' only available when it's first observed and not in subsequent
|
|
49
|
+
* updates.
|
|
50
|
+
*/
|
|
51
|
+
export interface TransactionRecord extends CopyRecord {
|
|
52
|
+
evidence?: CctpTxEvidence;
|
|
53
|
+
split?: RepayAmountKWR;
|
|
54
|
+
risksIdentified?: string[];
|
|
55
|
+
status: TxStatus;
|
|
56
|
+
}
|
|
57
|
+
|
|
29
58
|
export type LogFn = (...args: unknown[]) => void;
|
|
30
59
|
|
|
31
60
|
export interface PendingTx extends CctpTxEvidence {
|
|
32
61
|
status: PendingTxStatus;
|
|
33
62
|
}
|
|
34
63
|
|
|
35
|
-
/** internal key for `StatusManager` exo */
|
|
36
|
-
export type PendingTxKey = `pendingTx:${string}`;
|
|
37
|
-
|
|
38
|
-
/** internal key for `StatusManager` exo */
|
|
39
|
-
export type SeenTxKey = `seenTx:${string}`;
|
|
40
|
-
|
|
41
64
|
export type FeeConfig = {
|
|
42
65
|
flat: Amount<'nat'>;
|
|
43
66
|
variableRate: Ratio;
|
|
@@ -58,11 +81,14 @@ export interface PoolMetrics extends PoolStats {
|
|
|
58
81
|
}
|
|
59
82
|
|
|
60
83
|
export interface ChainPolicy {
|
|
61
|
-
|
|
84
|
+
/** `msg.sender` of DepositAndBurn to TokenMessenger must be an attenuated wrapper contract that does not contain `replaceDepositForBurn` */
|
|
85
|
+
attenuatedCttpBridgeAddress: EvmHash;
|
|
86
|
+
/** @see {@link https://developers.circle.com/stablecoins/evm-smart-contracts} */
|
|
62
87
|
cctpTokenMessengerAddress: EvmHash;
|
|
63
|
-
|
|
88
|
+
/** e.g., `1` for ETH mainnet 42161 for Arbitrum One. @see {@link https://chainlist.org/} */
|
|
64
89
|
chainId: EvmChainID;
|
|
65
|
-
|
|
90
|
+
/** the number of block confirmations to observe before reporting */
|
|
91
|
+
confirmations: number;
|
|
66
92
|
}
|
|
67
93
|
|
|
68
94
|
export interface FeedPolicy {
|
|
@@ -72,4 +98,24 @@ export interface FeedPolicy {
|
|
|
72
98
|
eventFilter?: string;
|
|
73
99
|
}
|
|
74
100
|
|
|
101
|
+
export type FastUSDCConfig = {
|
|
102
|
+
terms: FastUsdcTerms;
|
|
103
|
+
oracles: Record<string, string>;
|
|
104
|
+
feeConfig: FeeConfig;
|
|
105
|
+
feedPolicy: FeedPolicy & Passable;
|
|
106
|
+
noNoble: boolean; // support a3p-integration, which has no noble chain
|
|
107
|
+
chainInfo: Record<string, CosmosChainInfo & Passable>;
|
|
108
|
+
assetInfo: [Denom, DenomDetail & { brandKey?: string }][];
|
|
109
|
+
} & CopyRecord;
|
|
110
|
+
|
|
111
|
+
/** decoded address hook parameters */
|
|
112
|
+
export type AddressHook = {
|
|
113
|
+
baseAddress: string;
|
|
114
|
+
query: {
|
|
115
|
+
/** end user destination address */
|
|
116
|
+
EUD: string;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
75
120
|
export type * from './constants.js';
|
|
121
|
+
export type { LiquidityPoolKit } from './exos/liquidity-pool.js';
|
package/src/util/agoric.js
CHANGED
|
@@ -5,7 +5,7 @@ export const queryFastUSDCLocalChainAccount = async (
|
|
|
5
5
|
out = console,
|
|
6
6
|
) => {
|
|
7
7
|
const agoricAddr = await vstorage.readLatest(
|
|
8
|
-
'published.
|
|
8
|
+
'published.fastUsdc.settlementAccount',
|
|
9
9
|
);
|
|
10
10
|
out.log(`Got Fast USDC Local Chain Account ${agoricAddr}`);
|
|
11
11
|
return agoricAddr;
|
package/src/util/bank.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const queryUSDCBalance = async (
|
|
2
|
+
/** @type {string} */ address,
|
|
3
|
+
/** @type {string} */ api,
|
|
4
|
+
/** @type {string} */ denom,
|
|
5
|
+
/** @type {typeof globalThis.fetch} */ fetch,
|
|
6
|
+
) => {
|
|
7
|
+
const query = `${api}/cosmos/bank/v1beta1/balances/${address}`;
|
|
8
|
+
const json = await fetch(query).then(res => res.json());
|
|
9
|
+
const amount = json.balances?.find(b => b.denom === denom)?.amount ?? '0';
|
|
10
|
+
|
|
11
|
+
return BigInt(amount);
|
|
12
|
+
};
|
package/src/util/cctp.js
CHANGED
|
@@ -67,5 +67,5 @@ export const depositForBurn = async (
|
|
|
67
67
|
|
|
68
68
|
out.log('Transaction confirmed in block', receipt.blockNumber);
|
|
69
69
|
out.log('Transaction hash:', receipt.hash);
|
|
70
|
-
out.log('USDC transfer initiated successfully
|
|
70
|
+
out.log('USDC transfer initiated successfully');
|
|
71
71
|
};
|
package/src/util/file.js
CHANGED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { denomHash, withChainCapabilities } from '@agoric/orchestration';
|
|
2
|
+
import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @import {FastUSDCConfig} from '@agoric/fast-usdc/src/types.js'
|
|
6
|
+
* @import {Passable} from '@endo/marshal';
|
|
7
|
+
* @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration';
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** @type {[Denom, DenomDetail & { brandKey?: string}][]} */
|
|
11
|
+
export const defaultAssetInfo = [
|
|
12
|
+
[
|
|
13
|
+
'uusdc',
|
|
14
|
+
{
|
|
15
|
+
baseName: 'noble',
|
|
16
|
+
chainName: 'noble',
|
|
17
|
+
baseDenom: 'uusdc',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.agoric.connections['noble-1'].transferChannel.channelId })}`,
|
|
22
|
+
{
|
|
23
|
+
baseName: 'noble',
|
|
24
|
+
chainName: 'agoric',
|
|
25
|
+
baseDenom: 'uusdc',
|
|
26
|
+
brandKey: 'USDC',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.osmosis.connections['noble-1'].transferChannel.channelId })}`,
|
|
31
|
+
{
|
|
32
|
+
baseName: 'noble',
|
|
33
|
+
chainName: 'osmosis',
|
|
34
|
+
baseDenom: 'uusdc',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
];
|
|
38
|
+
harden(defaultAssetInfo);
|
|
39
|
+
|
|
40
|
+
const agoricAssetInfo = defaultAssetInfo.filter(
|
|
41
|
+
([_d, i]) => i.chainName === 'agoric',
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @type {Record<string, Pick<FastUSDCConfig, 'oracles' | 'feedPolicy' | 'chainInfo' | 'assetInfo' >>}
|
|
46
|
+
*
|
|
47
|
+
* TODO: determine OCW operator addresses
|
|
48
|
+
* meanwhile, use price oracle addresses (from updatePriceFeeds.js).
|
|
49
|
+
*/
|
|
50
|
+
export const configurations = {
|
|
51
|
+
/**
|
|
52
|
+
* NOTE: The a3p-integration runtime does _not_ include
|
|
53
|
+
* a noble chain; this limits functionality to advancing
|
|
54
|
+
* to the Agoric chain.
|
|
55
|
+
*/
|
|
56
|
+
A3P_INTEGRATION: {
|
|
57
|
+
oracles: {
|
|
58
|
+
gov1: 'agoric1ee9hr0jyrxhy999y755mp862ljgycmwyp4pl7q',
|
|
59
|
+
gov2: 'agoric1wrfh296eu2z34p6pah7q04jjuyj3mxu9v98277',
|
|
60
|
+
gov3: 'agoric1ydzxwh6f893jvpaslmaz6l8j2ulup9a7x8qvvq',
|
|
61
|
+
},
|
|
62
|
+
feedPolicy: {
|
|
63
|
+
nobleAgoricChannelId: 'channel-does-not-exist',
|
|
64
|
+
nobleDomainId: 4,
|
|
65
|
+
chainPolicies: {
|
|
66
|
+
Arbitrum: {
|
|
67
|
+
attenuatedCttpBridgeAddress:
|
|
68
|
+
'0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
|
|
69
|
+
cctpTokenMessengerAddress:
|
|
70
|
+
'0x19330d10D9Cc8751218eaf51E8885D058642E08A',
|
|
71
|
+
chainId: 42161,
|
|
72
|
+
confirmations: 2,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
chainInfo: /** @type {Record<string, CosmosChainInfo & Passable>} */ (
|
|
77
|
+
withChainCapabilities({
|
|
78
|
+
agoric: fetchedChainInfo.agoric,
|
|
79
|
+
// registering USDC-on-agoric requires registering the noble chain
|
|
80
|
+
noble: fetchedChainInfo.noble,
|
|
81
|
+
})
|
|
82
|
+
),
|
|
83
|
+
assetInfo: agoricAssetInfo,
|
|
84
|
+
},
|
|
85
|
+
MAINNET: {
|
|
86
|
+
oracles: {
|
|
87
|
+
'01node': 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8',
|
|
88
|
+
'Simply Staking': 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr',
|
|
89
|
+
P2P: 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj',
|
|
90
|
+
},
|
|
91
|
+
feedPolicy: {
|
|
92
|
+
nobleAgoricChannelId: 'channel-21',
|
|
93
|
+
nobleDomainId: 4,
|
|
94
|
+
chainPolicies: {
|
|
95
|
+
Arbitrum: {
|
|
96
|
+
attenuatedCttpBridgeAddress:
|
|
97
|
+
'0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
|
|
98
|
+
cctpTokenMessengerAddress:
|
|
99
|
+
'0x19330d10D9Cc8751218eaf51E8885D058642E08A',
|
|
100
|
+
chainId: 42161,
|
|
101
|
+
confirmations: 2,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
chainInfo: /** @type {Record<string, CosmosChainInfo & Passable>} */ (
|
|
106
|
+
withChainCapabilities(fetchedChainInfo)
|
|
107
|
+
),
|
|
108
|
+
assetInfo: defaultAssetInfo,
|
|
109
|
+
},
|
|
110
|
+
DEVNET: {
|
|
111
|
+
oracles: {
|
|
112
|
+
DSRV: 'agoric1lw4e4aas9q84tq0q92j85rwjjjapf8dmnllnft',
|
|
113
|
+
Stakin: 'agoric1zj6vrrrjq4gsyr9lw7dplv4vyejg3p8j2urm82',
|
|
114
|
+
'01node': 'agoric1ra0g6crtsy6r3qnpu7ruvm7qd4wjnznyzg5nu4',
|
|
115
|
+
'Simply Staking': 'agoric1qj07c7vfk3knqdral0sej7fa6eavkdn8vd8etf',
|
|
116
|
+
P2P: 'agoric10vjkvkmpp9e356xeh6qqlhrny2htyzp8hf88fk',
|
|
117
|
+
},
|
|
118
|
+
feedPolicy: {
|
|
119
|
+
nobleAgoricChannelId: 'TODO',
|
|
120
|
+
nobleDomainId: 4,
|
|
121
|
+
chainPolicies: {
|
|
122
|
+
Arbitrum: {
|
|
123
|
+
attenuatedCttpBridgeAddress: '0xTODO',
|
|
124
|
+
cctpTokenMessengerAddress: '0xTODO',
|
|
125
|
+
chainId: 421614,
|
|
126
|
+
confirmations: 2,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
chainInfo: /** @type {Record<string, CosmosChainInfo & Passable>} */ (
|
|
131
|
+
withChainCapabilities(fetchedChainInfo) // TODO: use devnet values
|
|
132
|
+
),
|
|
133
|
+
assetInfo: defaultAssetInfo, // TODO: use emerynet values
|
|
134
|
+
},
|
|
135
|
+
EMERYNET: {
|
|
136
|
+
oracles: {
|
|
137
|
+
gov1: 'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce',
|
|
138
|
+
gov2: 'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang',
|
|
139
|
+
},
|
|
140
|
+
feedPolicy: {
|
|
141
|
+
nobleAgoricChannelId: 'TODO',
|
|
142
|
+
nobleDomainId: 4,
|
|
143
|
+
chainPolicies: {
|
|
144
|
+
Arbitrum: {
|
|
145
|
+
attenuatedCttpBridgeAddress: '0xTODO',
|
|
146
|
+
cctpTokenMessengerAddress: '0xTODO',
|
|
147
|
+
chainId: 421614,
|
|
148
|
+
confirmations: 2,
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
chainInfo: /** @type {Record<string, CosmosChainInfo & Passable>} */ (
|
|
153
|
+
withChainCapabilities(fetchedChainInfo) // TODO: use emerynet values
|
|
154
|
+
),
|
|
155
|
+
assetInfo: defaultAssetInfo, // TODO: use emerynet values
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
harden(configurations);
|
|
159
|
+
|
|
160
|
+
// Constraints on the configurations
|
|
161
|
+
const MAINNET_EXPECTED_ORACLES = 3;
|
|
162
|
+
assert(
|
|
163
|
+
new Set(Object.values(configurations.MAINNET.oracles)).size ===
|
|
164
|
+
MAINNET_EXPECTED_ORACLES,
|
|
165
|
+
`Mainnet must have exactly ${MAINNET_EXPECTED_ORACLES} oracles`,
|
|
166
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const flags = (
|
|
2
|
+
record: Record<string, string | number | bigint | undefined>,
|
|
3
|
+
): string[] => {
|
|
4
|
+
// @ts-expect-error undefined is filtered out
|
|
5
|
+
const skipUndef: [string, string][] = Object.entries(record).filter(
|
|
6
|
+
([_k, v]) => v !== undefined,
|
|
7
|
+
);
|
|
8
|
+
return skipUndef.map(([k, v]) => [`--${k}`, `${v}`]).flat();
|
|
9
|
+
};
|
package/tools/mock-io.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* mock stdout / stderr, for example
|
|
5
|
+
*
|
|
6
|
+
* @param buf - caller-provided buffer for written data
|
|
7
|
+
*/
|
|
8
|
+
export const mockStream = <T extends Writable>(buf: string[]): T =>
|
|
9
|
+
({
|
|
10
|
+
write: txt => {
|
|
11
|
+
buf.push(txt);
|
|
12
|
+
return true;
|
|
13
|
+
},
|
|
14
|
+
}) as T;
|
package/src/exos/README.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
## **StatusManager** state diagram, showing different transitions
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
### Contract state diagram
|
|
5
|
-
|
|
6
|
-
*Transactions are qualified by the OCW and EventFeed before arriving to the Advancer.*
|
|
7
|
-
|
|
8
|
-
```mermaid
|
|
9
|
-
stateDiagram-v2
|
|
10
|
-
[*] --> Advanced: Advancer .advance()
|
|
11
|
-
Advanced --> Settled: Settler .settle() after fees
|
|
12
|
-
[*] --> Observed: Advancer .observed()
|
|
13
|
-
Observed --> Settled: Settler .settle() sans fees
|
|
14
|
-
Settled --> [*]
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Complete state diagram (starting from OCW)
|
|
18
|
-
|
|
19
|
-
```mermaid
|
|
20
|
-
stateDiagram-v2
|
|
21
|
-
Observed --> Qualified
|
|
22
|
-
Observed --> Unqualified
|
|
23
|
-
Qualified --> Advanced
|
|
24
|
-
Advanced --> Settled
|
|
25
|
-
Qualified --> Settled
|
|
26
|
-
```
|
package/src/utils/address.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { makeError, q } from '@endo/errors';
|
|
2
|
-
import { M, mustMatch } from '@endo/patterns';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @import {Pattern} from '@endo/patterns';
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Default pattern matcher for `getQueryParams`.
|
|
10
|
-
* Does not assert keys exist, but ensures existing keys are strings.
|
|
11
|
-
*/
|
|
12
|
-
const QueryParamsShape = M.splitRecord(
|
|
13
|
-
{},
|
|
14
|
-
{},
|
|
15
|
-
M.recordOf(M.string(), M.string()),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Very minimal 'URL query string'-like parser that handles:
|
|
20
|
-
* - Query string delimiter (?)
|
|
21
|
-
* - Key-value separator (=)
|
|
22
|
-
* - Query parameter separator (&)
|
|
23
|
-
*
|
|
24
|
-
* Does not handle:
|
|
25
|
-
* - Subpaths (`agoric1bech32addr/opt/account?k=v`)
|
|
26
|
-
* - URI encoding/decoding (`%20` -> ` `)
|
|
27
|
-
* - note: `decodeURIComponent` seems to be available in XS
|
|
28
|
-
* - Multiple question marks (foo?bar=1?baz=2)
|
|
29
|
-
* - Empty parameters (foo=)
|
|
30
|
-
* - Array parameters (`foo?k=v1&k=v2` -> k: [v1, v2])
|
|
31
|
-
* - Parameters without values (foo&bar=2)
|
|
32
|
-
*/
|
|
33
|
-
export const addressTools = {
|
|
34
|
-
/**
|
|
35
|
-
* @param {string} address
|
|
36
|
-
* @returns {boolean}
|
|
37
|
-
*/
|
|
38
|
-
hasQueryParams: address => {
|
|
39
|
-
try {
|
|
40
|
-
const params = addressTools.getQueryParams(address);
|
|
41
|
-
return Object.keys(params).length > 0;
|
|
42
|
-
} catch {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
/**
|
|
47
|
-
* @param {string} address
|
|
48
|
-
* @param {Pattern} [shape]
|
|
49
|
-
* @returns {Record<string, string>}
|
|
50
|
-
* @throws {Error} if the address cannot be parsed or params do not match `shape`
|
|
51
|
-
*/
|
|
52
|
-
getQueryParams: (address, shape = QueryParamsShape) => {
|
|
53
|
-
const parts = address.split('?');
|
|
54
|
-
if (parts.length !== 2) {
|
|
55
|
-
throw makeError(`Unable to parse query params: ${q(address)}`);
|
|
56
|
-
}
|
|
57
|
-
/** @type {Record<string, string>} */
|
|
58
|
-
const result = {};
|
|
59
|
-
const paramPairs = parts[1].split('&');
|
|
60
|
-
for (const pair of paramPairs) {
|
|
61
|
-
const [key, value] = pair.split('=');
|
|
62
|
-
if (!key || !value) {
|
|
63
|
-
throw makeError(`Invalid parameter format in pair: ${q(pair)}`);
|
|
64
|
-
}
|
|
65
|
-
result[key] = value;
|
|
66
|
-
}
|
|
67
|
-
harden(result);
|
|
68
|
-
mustMatch(result, shape);
|
|
69
|
-
return result;
|
|
70
|
-
},
|
|
71
|
-
};
|