@agoric/fast-usdc 0.1.1-other-dev-3eb1a1d.0 → 0.1.1-other-dev-d15096d.0.d15096d
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 +162 -36
- package/package.json +39 -38
- package/src/cli/bridge-action.js +41 -0
- package/src/cli/cli.js +47 -154
- package/src/cli/config-commands.js +108 -0
- package/src/cli/config.js +15 -9
- package/src/cli/lp-commands.js +161 -0
- package/src/cli/operator-commands.js +143 -0
- package/src/cli/transfer.js +84 -23
- package/src/cli/util/agoric.js +11 -0
- package/src/cli/util/bank.js +12 -0
- package/src/{util → cli/util}/cctp.js +1 -1
- package/src/{util → cli/util}/file.js +1 -1
- package/src/clientSupport.js +101 -0
- package/src/constants.js +29 -6
- package/src/main.js +1 -0
- package/src/operator-kit-interface.js +29 -0
- package/src/pool-share-math.js +72 -34
- package/src/type-guards.js +122 -34
- package/src/types.ts +136 -15
- package/src/utils/fees.js +105 -20
- package/tools/cli-tools.ts +9 -0
- package/tools/mock-evidence.ts +205 -0
- package/tools/mock-io.ts +14 -0
- package/src/exos/README.md +0 -26
- package/src/exos/advancer.js +0 -255
- package/src/exos/liquidity-pool.js +0 -365
- package/src/exos/operator-kit.js +0 -120
- package/src/exos/settler.js +0 -97
- package/src/exos/status-manager.js +0 -176
- package/src/exos/transaction-feed.js +0 -180
- package/src/fast-usdc.contract.js +0 -235
- package/src/fast-usdc.flows.js +0 -13
- package/src/fast-usdc.start.js +0 -284
- package/src/util/agoric.js +0 -12
- package/src/utils/address.js +0 -71
- package/src/utils/config-marshal.js +0 -130
- package/src/utils/zoe.js +0 -28
- /package/src/{util → cli/util}/noble.js +0 -0
package/src/types.ts
CHANGED
|
@@ -1,48 +1,121 @@
|
|
|
1
|
-
import type { ChainAddress } from '@agoric/orchestration';
|
|
2
|
-
import type { IBCChannelID } from '@agoric/vats';
|
|
3
1
|
import type { Amount } from '@agoric/ertp';
|
|
4
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AccountId,
|
|
4
|
+
BaseChainInfo,
|
|
5
|
+
Bech32Address,
|
|
6
|
+
CaipChainId,
|
|
7
|
+
CosmosChainAddress,
|
|
8
|
+
CosmosChainInfo,
|
|
9
|
+
Denom,
|
|
10
|
+
DenomDetail,
|
|
11
|
+
KnownNamespace,
|
|
12
|
+
} from '@agoric/orchestration';
|
|
13
|
+
import type { IBCChannelID } from '@agoric/vats';
|
|
14
|
+
import type { CopyRecord } from '@endo/pass-style';
|
|
15
|
+
import type { PendingTxStatus, TxStatus } from './constants.js';
|
|
16
|
+
import type { RepayAmountKWR } from './utils/fees.js';
|
|
17
|
+
|
|
18
|
+
// XXX duped with Zoe contractSupport ambient types
|
|
19
|
+
type Ratio = {
|
|
20
|
+
numerator: Amount<'nat'>;
|
|
21
|
+
denominator: Amount<'nat'>;
|
|
22
|
+
};
|
|
5
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Block hash is calculated using the keccak256 algorithm that always results
|
|
26
|
+
* in 32 bytes (64 hex characters prepended by 0x) no matter the input length.
|
|
27
|
+
*/
|
|
6
28
|
export type EvmHash = `0x${string}`;
|
|
29
|
+
/**
|
|
30
|
+
* An address is always the last 20 bytes (40 hex charaters prepended by 0x) of
|
|
31
|
+
* the public key hash.
|
|
32
|
+
*/
|
|
33
|
+
export type EvmAddress = `0x${string & { length: 40 }}`;
|
|
7
34
|
export type NobleAddress = `noble1${string}`;
|
|
8
35
|
export type EvmChainID = number;
|
|
9
36
|
export type EvmChainName = string;
|
|
10
37
|
|
|
38
|
+
export interface RiskAssessment {
|
|
39
|
+
risksIdentified?: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
11
42
|
export interface CctpTxEvidence {
|
|
12
43
|
/** from Noble RPC */
|
|
13
44
|
aux: {
|
|
14
45
|
forwardingChannel: IBCChannelID;
|
|
15
|
-
recipientAddress:
|
|
46
|
+
recipientAddress: CosmosChainAddress['value'] | AccountId;
|
|
16
47
|
};
|
|
48
|
+
/** on the source chain (e.g. L1 Ethereum and L2s Arbitrum, Base) */
|
|
17
49
|
blockHash: EvmHash;
|
|
50
|
+
/** height of blockHash on the source chain */
|
|
18
51
|
blockNumber: bigint;
|
|
52
|
+
/**
|
|
53
|
+
* Seconds since Unix epoch. Not all CCTP source chains update time the same
|
|
54
|
+
* way but they all use Unix epoch and thus are approximately equal. (Within
|
|
55
|
+
* minutes apart.)
|
|
56
|
+
*/
|
|
19
57
|
blockTimestamp: bigint;
|
|
58
|
+
//
|
|
59
|
+
/**
|
|
60
|
+
* [Domain of values](https://chainid.network/) per [EIP-155](https://eips.ethereum.org/EIPS/eip-155)
|
|
61
|
+
* (We don't have [CCTP `domain`](https://developers.circle.com/stablecoins/supported-domains) )
|
|
62
|
+
*/
|
|
20
63
|
chainId: number;
|
|
21
64
|
/** data covered by signature (aka txHash) */
|
|
22
65
|
tx: {
|
|
23
66
|
amount: bigint;
|
|
24
67
|
forwardingAddress: NobleAddress;
|
|
68
|
+
sender: EvmAddress;
|
|
25
69
|
};
|
|
26
70
|
txHash: EvmHash;
|
|
27
71
|
}
|
|
28
72
|
|
|
73
|
+
export interface EvidenceWithRisk extends CopyRecord {
|
|
74
|
+
evidence: CctpTxEvidence;
|
|
75
|
+
risk: RiskAssessment;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 'evidence' only available when it's first observed and not in subsequent
|
|
80
|
+
* updates.
|
|
81
|
+
*/
|
|
82
|
+
export interface TransactionRecord extends CopyRecord {
|
|
83
|
+
evidence?: CctpTxEvidence;
|
|
84
|
+
split?: RepayAmountKWR;
|
|
85
|
+
risksIdentified?: string[];
|
|
86
|
+
status: TxStatus;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** the record in vstorage at the path of the contract's node */
|
|
90
|
+
export interface ContractRecord extends CopyRecord {
|
|
91
|
+
nobleICA?: CosmosChainAddress['value'];
|
|
92
|
+
poolAccount: CosmosChainAddress['value'];
|
|
93
|
+
settlementAccount: CosmosChainAddress['value'];
|
|
94
|
+
}
|
|
95
|
+
|
|
29
96
|
export type LogFn = (...args: unknown[]) => void;
|
|
30
97
|
|
|
31
98
|
export interface PendingTx extends CctpTxEvidence {
|
|
32
99
|
status: PendingTxStatus;
|
|
33
100
|
}
|
|
34
101
|
|
|
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
102
|
export type FeeConfig = {
|
|
103
|
+
/** flat fee charged for every advance, eligible for LP disbursement */
|
|
42
104
|
flat: Amount<'nat'>;
|
|
105
|
+
/** proportion of advance kept as a fee, eligible for LP disbursement */
|
|
43
106
|
variableRate: Ratio;
|
|
44
|
-
|
|
107
|
+
/** proportion of `flat` and `variableRate` fees that goes to the contract (remaining goes to LPs) */
|
|
45
108
|
contractRate: Ratio;
|
|
109
|
+
/**
|
|
110
|
+
* if present, a fee required to relay (e.g. CCTP to EVM/Solana). Not
|
|
111
|
+
* considered for LP disbursement - goes to `contractSeat`.
|
|
112
|
+
*/
|
|
113
|
+
relay?: Amount<'nat'>;
|
|
114
|
+
/** Optional destination-specific overrides. If present, must supersede base values. */
|
|
115
|
+
destinationOverrides?: Record<
|
|
116
|
+
CaipChainId,
|
|
117
|
+
Partial<Omit<FeeConfig, 'destinationOverrides'>>
|
|
118
|
+
>;
|
|
46
119
|
};
|
|
47
120
|
|
|
48
121
|
export interface PoolStats {
|
|
@@ -58,18 +131,66 @@ export interface PoolMetrics extends PoolStats {
|
|
|
58
131
|
}
|
|
59
132
|
|
|
60
133
|
export interface ChainPolicy {
|
|
61
|
-
|
|
134
|
+
/** `msg.sender` of DepositAndBurn to TokenMessenger must be an attenuated wrapper contract that does not contain `replaceDepositForBurn` */
|
|
135
|
+
attenuatedCttpBridgeAddresses: EvmHash[];
|
|
136
|
+
/** @see {@link https://developers.circle.com/stablecoins/evm-smart-contracts} */
|
|
62
137
|
cctpTokenMessengerAddress: EvmHash;
|
|
63
|
-
|
|
138
|
+
/** e.g., `1` for ETH mainnet 42161 for Arbitrum One. @see {@link https://chainlist.org/} */
|
|
64
139
|
chainId: EvmChainID;
|
|
65
|
-
|
|
140
|
+
/** the number of block confirmations to observe before reporting */
|
|
141
|
+
confirmations: number;
|
|
142
|
+
rateLimits: {
|
|
143
|
+
/** do not advance more than this amount for an individual transaction */
|
|
144
|
+
tx: bigint;
|
|
145
|
+
/** do not advance more than this amount per block window */
|
|
146
|
+
blockWindow: bigint;
|
|
147
|
+
/** the number of blocks to consider for `blockWindow` */
|
|
148
|
+
blockWindowSize: number;
|
|
149
|
+
};
|
|
66
150
|
}
|
|
67
151
|
|
|
68
|
-
export
|
|
152
|
+
export type FeedPolicy = {
|
|
69
153
|
nobleDomainId: number;
|
|
70
154
|
nobleAgoricChannelId: string;
|
|
71
155
|
chainPolicies: Record<EvmChainName, ChainPolicy>;
|
|
72
156
|
eventFilter?: string;
|
|
157
|
+
} & CopyRecord;
|
|
158
|
+
|
|
159
|
+
export type FastUsdcTerms = {
|
|
160
|
+
usdcDenom: Denom;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export type FastUSDCConfig = {
|
|
164
|
+
terms: FastUsdcTerms;
|
|
165
|
+
oracles: Record<string, string>;
|
|
166
|
+
feeConfig: FeeConfig;
|
|
167
|
+
feedPolicy: FeedPolicy;
|
|
168
|
+
noNoble: boolean; // support a3p-integration, which has no noble chain
|
|
169
|
+
chainInfo: Record<string, ChainHubChainInfo>;
|
|
170
|
+
assetInfo: [Denom, DenomDetail & { brandKey?: string }][];
|
|
171
|
+
} & CopyRecord;
|
|
172
|
+
|
|
173
|
+
/** decoded address hook parameters */
|
|
174
|
+
export type AddressHook = {
|
|
175
|
+
baseAddress: string;
|
|
176
|
+
query: {
|
|
177
|
+
/** end user destination address */
|
|
178
|
+
EUD: Bech32Address;
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The shape of ChainInfo ChainHub is expecting for FUSDC.
|
|
184
|
+
*
|
|
185
|
+
* Note: this diverges from `CosmosChainInfo` and `BaseChainInfo` in that:
|
|
186
|
+
* - BaseChainInfo includes chainId for backwards compatibility with `CosmosChainInfoShapeV1`
|
|
187
|
+
*/
|
|
188
|
+
export type ChainHubChainInfo<N extends KnownNamespace = KnownNamespace> =
|
|
189
|
+
N extends 'cosmos' ? CosmosChainInfo : BaseChainInfoWithChainId<N>;
|
|
190
|
+
|
|
191
|
+
interface BaseChainInfoWithChainId<N extends KnownNamespace = KnownNamespace>
|
|
192
|
+
extends BaseChainInfo<N> {
|
|
193
|
+
chainId: string;
|
|
73
194
|
}
|
|
74
195
|
|
|
75
196
|
export type * from './constants.js';
|
package/src/utils/fees.js
CHANGED
|
@@ -1,57 +1,142 @@
|
|
|
1
1
|
import { AmountMath } from '@agoric/ertp';
|
|
2
|
-
import { multiplyBy } from '@agoric/
|
|
2
|
+
import { multiplyBy } from '@agoric/ertp/src/ratio.js';
|
|
3
3
|
import { Fail } from '@endo/errors';
|
|
4
4
|
import { mustMatch } from '@endo/patterns';
|
|
5
|
+
import { chainOfAccount } from '@agoric/orchestration/src/utils/address.js';
|
|
5
6
|
import { FeeConfigShape } from '../type-guards.js';
|
|
6
7
|
|
|
7
|
-
const { add, isGTE,
|
|
8
|
+
const { add, isGTE, subtract, makeEmpty } = AmountMath;
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
* @import {Amount} from '@agoric/ertp';
|
|
11
|
+
* @import {Amount, Payment} from '@agoric/ertp';
|
|
12
|
+
* @import {AccountId} from '@agoric/orchestration';
|
|
11
13
|
* @import {FeeConfig} from '../types.js';
|
|
12
|
-
* @import {RepayAmountKWR} from '../exos/liquidity-pool.js';
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {{
|
|
18
|
+
* Principal: Amount<'nat'>;
|
|
19
|
+
* PoolFee: Amount<'nat'>;
|
|
20
|
+
* ContractFee: Amount<'nat'>;
|
|
21
|
+
* RelayFee: Amount<'nat'>;
|
|
22
|
+
* }} RepayAmountKWR
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {{
|
|
27
|
+
* Principal: Payment<'nat'>;
|
|
28
|
+
* PoolFee: Payment<'nat'>;
|
|
29
|
+
* ContractFee: Payment<'nat'>;
|
|
30
|
+
* RelayFee: Payment<'nat'>;
|
|
31
|
+
* }} RepayPaymentKWR
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @template {keyof Omit<FeeConfig, 'destinationOverrides'>} K
|
|
36
|
+
* @param {FeeConfig} feeConfig
|
|
37
|
+
* @param {K} key
|
|
38
|
+
* @param {AccountId} destination
|
|
39
|
+
* @returns {FeeConfig[K]}
|
|
40
|
+
*/
|
|
41
|
+
const getConfigValue = (feeConfig, key, destination) => {
|
|
42
|
+
const chainId = chainOfAccount(destination);
|
|
43
|
+
if (
|
|
44
|
+
feeConfig.destinationOverrides?.[chainId] &&
|
|
45
|
+
feeConfig.destinationOverrides[chainId][key] !== undefined
|
|
46
|
+
) {
|
|
47
|
+
return feeConfig.destinationOverrides[chainId][key];
|
|
48
|
+
}
|
|
49
|
+
return feeConfig[key];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {FeeConfig} feeConfig
|
|
54
|
+
*/
|
|
16
55
|
export const makeFeeTools = feeConfig => {
|
|
17
56
|
mustMatch(feeConfig, FeeConfigShape, 'Must provide feeConfig');
|
|
18
|
-
const
|
|
57
|
+
const emptyAmount = makeEmpty(feeConfig.flat.brand);
|
|
58
|
+
|
|
19
59
|
const feeTools = harden({
|
|
20
60
|
/**
|
|
21
|
-
* Calculate the
|
|
61
|
+
* Calculate the base fee to charge for the advance (variable + flat).
|
|
62
|
+
* Will be shared between the pool and the contract based on
|
|
63
|
+
* {@link FeeConfig.contractRate}.
|
|
22
64
|
*
|
|
23
65
|
* @param {Amount<'nat'>} requested
|
|
24
|
-
* @
|
|
66
|
+
* @param {AccountId} destination
|
|
67
|
+
* @returns {Amount<'nat'>}
|
|
25
68
|
*/
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
69
|
+
calculateBaseFee(requested, destination) {
|
|
70
|
+
const flat = getConfigValue(feeConfig, 'flat', destination);
|
|
71
|
+
const variableRate = getConfigValue(
|
|
72
|
+
feeConfig,
|
|
73
|
+
'variableRate',
|
|
74
|
+
destination,
|
|
75
|
+
);
|
|
76
|
+
return add(multiplyBy(requested, variableRate), flat);
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Calculate the optional relay fee charged for certain destinations.
|
|
80
|
+
* Only disbursed to contract seat.
|
|
81
|
+
*
|
|
82
|
+
* @param {AccountId} destination
|
|
83
|
+
* @returns {Amount<'nat'>}
|
|
84
|
+
*/
|
|
85
|
+
calculateRelayFee(destination) {
|
|
86
|
+
const relay = getConfigValue(feeConfig, 'relay', destination);
|
|
87
|
+
return relay || emptyAmount;
|
|
29
88
|
},
|
|
30
89
|
/**
|
|
31
90
|
* Calculate the total fee to charge for the advance.
|
|
32
91
|
*
|
|
33
92
|
* @param {Amount<'nat'>} requested
|
|
93
|
+
* @param {AccountId} destination
|
|
34
94
|
* @throws {Error} if requested does not exceed fees
|
|
35
95
|
*/
|
|
36
|
-
calculateAdvanceFee(requested) {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
96
|
+
calculateAdvanceFee(requested, destination) {
|
|
97
|
+
const baseFee = feeTools.calculateBaseFee(requested, destination);
|
|
98
|
+
const relayFee = feeTools.calculateRelayFee(destination);
|
|
99
|
+
const fee = add(baseFee, relayFee);
|
|
39
100
|
!isGTE(fee, requested) || Fail`Request must exceed fees.`;
|
|
40
101
|
return fee;
|
|
41
102
|
},
|
|
103
|
+
/**
|
|
104
|
+
* Calculate the net amount to advance after withholding fees.
|
|
105
|
+
*
|
|
106
|
+
* @param {Amount<'nat'>} requested
|
|
107
|
+
* @param {AccountId} destination
|
|
108
|
+
* @throws {Error} if requested does not exceed fees
|
|
109
|
+
*/
|
|
110
|
+
calculateAdvance(requested, destination) {
|
|
111
|
+
const fee = feeTools.calculateAdvanceFee(requested, destination);
|
|
112
|
+
return subtract(requested, fee);
|
|
113
|
+
},
|
|
42
114
|
/**
|
|
43
115
|
* Calculate the split of fees between pool and contract.
|
|
44
116
|
*
|
|
117
|
+
* The `ContractFee` includes base fees plus the relay fee.
|
|
118
|
+
*
|
|
45
119
|
* @param {Amount<'nat'>} requested
|
|
120
|
+
* @param {AccountId} destination
|
|
46
121
|
* @returns {RepayAmountKWR} an {@link AmountKeywordRecord}
|
|
47
122
|
* @throws {Error} if requested does not exceed fees
|
|
48
123
|
*/
|
|
49
|
-
calculateSplit(requested) {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
124
|
+
calculateSplit(requested, destination) {
|
|
125
|
+
const baseFee = feeTools.calculateBaseFee(requested, destination);
|
|
126
|
+
const relayFee = feeTools.calculateRelayFee(destination);
|
|
127
|
+
const totalFee = add(baseFee, relayFee);
|
|
128
|
+
!isGTE(totalFee, requested) || Fail`Request must exceed fees.`;
|
|
129
|
+
|
|
130
|
+
const contractRate = getConfigValue(
|
|
131
|
+
feeConfig,
|
|
132
|
+
'contractRate',
|
|
133
|
+
destination,
|
|
134
|
+
);
|
|
135
|
+
const Principal = subtract(requested, totalFee);
|
|
136
|
+
const ContractFee = multiplyBy(baseFee, contractRate);
|
|
137
|
+
const PoolFee = subtract(baseFee, ContractFee);
|
|
138
|
+
|
|
139
|
+
return harden({ Principal, PoolFee, ContractFee, RelayFee: relayFee });
|
|
55
140
|
},
|
|
56
141
|
});
|
|
57
142
|
return feeTools;
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
|
|
2
|
+
import type { Bech32Address, CosmosChainAddress } from '@agoric/orchestration';
|
|
3
|
+
import type { CctpTxEvidence, EvmAddress } from '../src/types.js';
|
|
4
|
+
|
|
5
|
+
export type MockScenario =
|
|
6
|
+
| 'AGORIC_PLUS_OSMO'
|
|
7
|
+
| 'AGORIC_PLUS_DYDX'
|
|
8
|
+
| 'AGORIC_PLUS_AGORIC'
|
|
9
|
+
| 'AGORIC_NO_PARAMS'
|
|
10
|
+
| 'AGORIC_UNKNOWN_EUD'
|
|
11
|
+
| 'AGORIC_PLUS_ETHEREUM'
|
|
12
|
+
| 'AGORIC_PLUS_NOBLE'
|
|
13
|
+
| 'AGORIC_PLUS_NOBLE_B32EUD';
|
|
14
|
+
|
|
15
|
+
export const Senders = {
|
|
16
|
+
default: '0xDefaultFakeEthereumAddress',
|
|
17
|
+
} as unknown as Record<string, EvmAddress>;
|
|
18
|
+
|
|
19
|
+
const blockTimestamp = 1632340000n;
|
|
20
|
+
|
|
21
|
+
export const MockCctpTxEvidences: Record<
|
|
22
|
+
MockScenario,
|
|
23
|
+
(receiverAddress?: Bech32Address) => CctpTxEvidence
|
|
24
|
+
> = {
|
|
25
|
+
AGORIC_PLUS_OSMO: (receiverAddress?: Bech32Address) => ({
|
|
26
|
+
blockHash:
|
|
27
|
+
'0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665',
|
|
28
|
+
blockNumber: 21037663n,
|
|
29
|
+
blockTimestamp,
|
|
30
|
+
txHash:
|
|
31
|
+
'0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702',
|
|
32
|
+
tx: {
|
|
33
|
+
amount: 150000000n,
|
|
34
|
+
forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelqkd',
|
|
35
|
+
sender: Senders.default,
|
|
36
|
+
},
|
|
37
|
+
aux: {
|
|
38
|
+
forwardingChannel: 'channel-21',
|
|
39
|
+
recipientAddress:
|
|
40
|
+
receiverAddress ||
|
|
41
|
+
encodeAddressHook(settlementAddress.value, {
|
|
42
|
+
EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
chainId: 1,
|
|
46
|
+
}),
|
|
47
|
+
AGORIC_PLUS_DYDX: (receiverAddress?: Bech32Address) => ({
|
|
48
|
+
blockHash:
|
|
49
|
+
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee699',
|
|
50
|
+
blockNumber: 21037669n,
|
|
51
|
+
blockTimestamp,
|
|
52
|
+
txHash:
|
|
53
|
+
'0xd81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799',
|
|
54
|
+
tx: {
|
|
55
|
+
amount: 300000000n,
|
|
56
|
+
forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelktz',
|
|
57
|
+
sender: Senders.default,
|
|
58
|
+
},
|
|
59
|
+
aux: {
|
|
60
|
+
forwardingChannel: 'channel-21',
|
|
61
|
+
recipientAddress:
|
|
62
|
+
receiverAddress ||
|
|
63
|
+
encodeAddressHook(settlementAddress.value, {
|
|
64
|
+
EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
chainId: 1,
|
|
68
|
+
}),
|
|
69
|
+
AGORIC_PLUS_AGORIC: (receiverAddress?: Bech32Address) => ({
|
|
70
|
+
blockHash:
|
|
71
|
+
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee6z9',
|
|
72
|
+
blockNumber: 21037600n,
|
|
73
|
+
blockTimestamp,
|
|
74
|
+
txHash:
|
|
75
|
+
'0xd81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617z9',
|
|
76
|
+
tx: {
|
|
77
|
+
amount: 250000000n,
|
|
78
|
+
forwardingAddress: 'noble17ww3rfusv895d92c0ncgj0fl9trntn70jz7hd5',
|
|
79
|
+
sender: Senders.default,
|
|
80
|
+
},
|
|
81
|
+
aux: {
|
|
82
|
+
forwardingChannel: 'channel-21',
|
|
83
|
+
recipientAddress:
|
|
84
|
+
receiverAddress ||
|
|
85
|
+
encodeAddressHook(settlementAddress.value, {
|
|
86
|
+
EUD: 'agoric13rj0cc0hm5ac2nt0sdup2l7gvkx4v9tyvgq3h2',
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
chainId: 1,
|
|
90
|
+
}),
|
|
91
|
+
AGORIC_NO_PARAMS: (receiverAddress?: Bech32Address) => ({
|
|
92
|
+
blockHash:
|
|
93
|
+
'0x70d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee699',
|
|
94
|
+
blockNumber: 21037669n,
|
|
95
|
+
blockTimestamp,
|
|
96
|
+
txHash:
|
|
97
|
+
'0xa81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799',
|
|
98
|
+
tx: {
|
|
99
|
+
amount: 200000000n,
|
|
100
|
+
forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelyyy',
|
|
101
|
+
sender: Senders.default,
|
|
102
|
+
},
|
|
103
|
+
aux: {
|
|
104
|
+
forwardingChannel: 'channel-21',
|
|
105
|
+
recipientAddress: receiverAddress || settlementAddress.value,
|
|
106
|
+
},
|
|
107
|
+
chainId: 1,
|
|
108
|
+
}),
|
|
109
|
+
AGORIC_UNKNOWN_EUD: (receiverAddress?: Bech32Address) => ({
|
|
110
|
+
blockHash:
|
|
111
|
+
'0x70d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee699',
|
|
112
|
+
blockNumber: 21037669n,
|
|
113
|
+
blockTimestamp,
|
|
114
|
+
txHash:
|
|
115
|
+
'0xa81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799',
|
|
116
|
+
tx: {
|
|
117
|
+
amount: 200000000n,
|
|
118
|
+
forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelyyy',
|
|
119
|
+
sender: Senders.default,
|
|
120
|
+
},
|
|
121
|
+
aux: {
|
|
122
|
+
forwardingChannel: 'channel-21',
|
|
123
|
+
recipientAddress:
|
|
124
|
+
receiverAddress ||
|
|
125
|
+
encodeAddressHook(settlementAddress.value, {
|
|
126
|
+
EUD: 'random1addr',
|
|
127
|
+
}),
|
|
128
|
+
},
|
|
129
|
+
chainId: 1,
|
|
130
|
+
}),
|
|
131
|
+
AGORIC_PLUS_ETHEREUM: (receiverAddress?: Bech32Address) => ({
|
|
132
|
+
blockHash:
|
|
133
|
+
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee6z9',
|
|
134
|
+
blockNumber: 21037600n,
|
|
135
|
+
blockTimestamp,
|
|
136
|
+
txHash:
|
|
137
|
+
'0xe81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617z9',
|
|
138
|
+
tx: {
|
|
139
|
+
amount: 950000000n,
|
|
140
|
+
forwardingAddress: 'noble17ww3rfusv895d92c0ncgj0fl9trntn70jz7ee5',
|
|
141
|
+
sender: Senders.default,
|
|
142
|
+
},
|
|
143
|
+
aux: {
|
|
144
|
+
forwardingChannel: 'channel-21',
|
|
145
|
+
recipientAddress:
|
|
146
|
+
receiverAddress ||
|
|
147
|
+
encodeAddressHook(settlementAddress.value, {
|
|
148
|
+
EUD: 'eip155:1:0x1234567890123456789012345678901234567890',
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
chainId: 8453,
|
|
152
|
+
}),
|
|
153
|
+
AGORIC_PLUS_NOBLE: (receiverAddress?: Bech32Address) => ({
|
|
154
|
+
blockHash:
|
|
155
|
+
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee6z9',
|
|
156
|
+
blockNumber: 21037600n,
|
|
157
|
+
blockTimestamp,
|
|
158
|
+
txHash:
|
|
159
|
+
'0xe81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617z9',
|
|
160
|
+
tx: {
|
|
161
|
+
amount: 950000000n,
|
|
162
|
+
forwardingAddress: 'noble17ww3rfusv895d92c0ncgj0fl9trntn70jz7ee5',
|
|
163
|
+
sender: Senders.default,
|
|
164
|
+
},
|
|
165
|
+
aux: {
|
|
166
|
+
forwardingChannel: 'channel-21',
|
|
167
|
+
recipientAddress:
|
|
168
|
+
receiverAddress ||
|
|
169
|
+
encodeAddressHook(settlementAddress.value, {
|
|
170
|
+
EUD: 'cosmos:noble-1:noble1u2l9za2wa7wvffhtekgyuvyvum06lwhqxfyr5d',
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
chainId: 8453,
|
|
174
|
+
}),
|
|
175
|
+
/** Identical to AGORIC_PLUS_NOBLE, but the EUD is a bare bech32 */
|
|
176
|
+
AGORIC_PLUS_NOBLE_B32EUD: (receiverAddress?: Bech32Address) => ({
|
|
177
|
+
blockHash:
|
|
178
|
+
'0x80d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee6z9',
|
|
179
|
+
blockNumber: 21037600n,
|
|
180
|
+
blockTimestamp,
|
|
181
|
+
txHash:
|
|
182
|
+
'0xe81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617z9',
|
|
183
|
+
tx: {
|
|
184
|
+
amount: 950000000n,
|
|
185
|
+
forwardingAddress: 'noble17ww3rfusv895d92c0ncgj0fl9trntn70jz7ee5',
|
|
186
|
+
sender: Senders.default,
|
|
187
|
+
},
|
|
188
|
+
aux: {
|
|
189
|
+
forwardingChannel: 'channel-21',
|
|
190
|
+
recipientAddress:
|
|
191
|
+
receiverAddress ||
|
|
192
|
+
encodeAddressHook(settlementAddress.value, {
|
|
193
|
+
EUD: 'noble1u2l9za2wa7wvffhtekgyuvyvum06lwhqxfyr5d',
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
chainId: 8453,
|
|
197
|
+
}),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const settlementAddress: CosmosChainAddress = harden({
|
|
201
|
+
chainId: 'agoric-3',
|
|
202
|
+
encoding: 'bech32' as const,
|
|
203
|
+
// Random value, copied from tests of address hooks
|
|
204
|
+
value: 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
|
|
205
|
+
});
|
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
|
-
```
|