@certen.io/cli 0.5.0 → 0.7.1
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/CHANGELOG.md +431 -0
- package/README.md +232 -160
- package/dist/chains.d.ts +67 -0
- package/dist/chains.js +242 -0
- package/dist/chains.js.map +1 -0
- package/dist/commands/admin.js +49 -4
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/auth.js +145 -12
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/billing.js +648 -40
- package/dist/commands/billing.js.map +1 -1
- package/dist/commands/call.d.ts +2 -0
- package/dist/commands/call.js +168 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/chains.d.ts +2 -0
- package/dist/commands/chains.js +123 -0
- package/dist/commands/chains.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +171 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/errors-catalogue.d.ts +2 -0
- package/dist/commands/errors-catalogue.js +83 -0
- package/dist/commands/errors-catalogue.js.map +1 -0
- package/dist/commands/identity.js +269 -19
- package/dist/commands/identity.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +307 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/keys.js +2 -0
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/oauth-clients.d.ts +2 -0
- package/dist/commands/oauth-clients.js +131 -0
- package/dist/commands/oauth-clients.js.map +1 -0
- package/dist/commands/orgs.d.ts +2 -0
- package/dist/commands/orgs.js +117 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/pending.d.ts +19 -0
- package/dist/commands/pending.js +117 -15
- package/dist/commands/pending.js.map +1 -1
- package/dist/commands/portfolio.js +34 -1
- package/dist/commands/portfolio.js.map +1 -1
- package/dist/commands/proof.d.ts +2 -0
- package/dist/commands/proof.js +400 -0
- package/dist/commands/proof.js.map +1 -0
- package/dist/commands/signup.d.ts +14 -0
- package/dist/commands/signup.js +271 -0
- package/dist/commands/signup.js.map +1 -0
- package/dist/commands/transaction.js +139 -21
- package/dist/commands/transaction.js.map +1 -1
- package/dist/commands/webhooks.d.ts +2 -0
- package/dist/commands/webhooks.js +200 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/commands/whoami.d.ts +16 -0
- package/dist/commands/whoami.js +98 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.d.ts +56 -0
- package/dist/config.js +51 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +14 -1
- package/dist/errors.js +15 -1
- package/dist/errors.js.map +1 -1
- package/dist/funding-guard.d.ts +40 -0
- package/dist/funding-guard.js +120 -0
- package/dist/funding-guard.js.map +1 -0
- package/dist/help-root.d.ts +2 -0
- package/dist/help-root.js +94 -0
- package/dist/help-root.js.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -1
- package/dist/output.d.ts +23 -0
- package/dist/output.js +46 -0
- package/dist/output.js.map +1 -1
- package/dist/passphrase.d.ts +18 -0
- package/dist/passphrase.js +35 -3
- package/dist/passphrase.js.map +1 -1
- package/dist/payment-uri.d.ts +76 -0
- package/dist/payment-uri.js +135 -0
- package/dist/payment-uri.js.map +1 -0
- package/dist/signer.js +6 -3
- package/dist/signer.js.map +1 -1
- package/dist/solidity-args.d.ts +31 -0
- package/dist/solidity-args.js +111 -0
- package/dist/solidity-args.js.map +1 -0
- package/dist/wait.d.ts +79 -0
- package/dist/wait.js +168 -0
- package/dist/wait.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a payment target into something a wallet can consume, and a wait into something a person
|
|
3
|
+
* can plan around.
|
|
4
|
+
*
|
|
5
|
+
* Funding asked someone to carry four values from a terminal into a wallet by hand: a token
|
|
6
|
+
* contract, a chain, a treasury address and an exact amount. **A mistyped recipient is the one
|
|
7
|
+
* error in this product that loses real money and cannot be reversed** — no retry, no support
|
|
8
|
+
* ticket, no proof to appeal to.
|
|
9
|
+
*
|
|
10
|
+
* Isolated in its own module because both functions here are pure arithmetic over values the
|
|
11
|
+
* gateway supplied, and both are wrong in ways that are invisible on screen: an off-by-one decimal
|
|
12
|
+
* looks like a plausible number, and a wait estimate that is silently zero looks like a fast chain.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* What the gateway sends back when a payment is opened. Only the fields a URI needs.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately structural rather than importing the SDK type: this module must be callable with
|
|
18
|
+
* exactly the gateway's own values and nothing reformatted on the way in.
|
|
19
|
+
*/
|
|
20
|
+
export interface PaymentTargetFields {
|
|
21
|
+
chain_id: number;
|
|
22
|
+
token_address: string;
|
|
23
|
+
token_decimals: number;
|
|
24
|
+
deposit_address: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert a decimal amount string into the token's smallest unit, exactly.
|
|
28
|
+
*
|
|
29
|
+
* String arithmetic, not `Number(amount) * 10 ** decimals`. That expression is wrong for values
|
|
30
|
+
* this function will certainly see: `25.10 * 1e6` is `25099999.999999996` in IEEE-754, which
|
|
31
|
+
* truncates to 25099999 — a payment one unit short of the amount attribution matches on, so the
|
|
32
|
+
* deposit is received and never credited. The failure is silent on both sides.
|
|
33
|
+
*
|
|
34
|
+
* Throws rather than rounding when the amount carries more precision than the token can express.
|
|
35
|
+
* Quietly dropping a digit would change what the user pays.
|
|
36
|
+
*/
|
|
37
|
+
export declare function toSmallestUnit(amount: string, decimals: number): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build an EIP-681 payment request for an ERC-20 transfer.
|
|
40
|
+
*
|
|
41
|
+
* `ethereum:<token>@<chainId>/transfer?address=<recipient>&uint256=<amount>`
|
|
42
|
+
*
|
|
43
|
+
* The shape is counter-intuitive and worth stating: the address BEFORE the `@` is the **token
|
|
44
|
+
* contract**, and the recipient is the `address` parameter. Reversing them produces a URI that a
|
|
45
|
+
* wallet will happily open and that transfers nothing — or, worse, calls an unknown method on the
|
|
46
|
+
* treasury address.
|
|
47
|
+
*
|
|
48
|
+
* Every value comes from the gateway's response untouched. Nothing here re-derives a chain id from
|
|
49
|
+
* a slug or re-formats an address, because that is precisely the transcription this exists to
|
|
50
|
+
* eliminate.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildPaymentUri(target: PaymentTargetFields, amountUsd: string): string;
|
|
53
|
+
export interface WaitEstimate {
|
|
54
|
+
seconds: number;
|
|
55
|
+
/** Rendered for a person: `about 24 seconds`, `about 2 minutes`. */
|
|
56
|
+
text: string;
|
|
57
|
+
/** The chain whose cadence produced this, so the estimate is checkable rather than magic. */
|
|
58
|
+
basis: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* How long `min_confirmations` is likely to take on this chain.
|
|
62
|
+
*
|
|
63
|
+
* Returns null for a chain with no known cadence rather than guessing. A wrong estimate on the
|
|
64
|
+
* command someone is already waiting on is worse than no estimate: it is the number they decide to
|
|
65
|
+
* interrupt against, and interrupting a funding flow is how people send twice.
|
|
66
|
+
*/
|
|
67
|
+
export declare function estimateWait(chain: string, confirmations: number): WaitEstimate | null;
|
|
68
|
+
/** `95` -> `about 2 minutes`. Coarse by design: false precision reads as a promise. */
|
|
69
|
+
export declare function humanDuration(totalSeconds: number): string;
|
|
70
|
+
/**
|
|
71
|
+
* `252` -> `4m 12s`. Exact, unlike `humanDuration`.
|
|
72
|
+
*
|
|
73
|
+
* Used for a quote's remaining validity, where the caller is deciding whether to act NOW and a
|
|
74
|
+
* rounded "about 4 minutes" on a quote with 20 seconds left would be actively misleading.
|
|
75
|
+
*/
|
|
76
|
+
export declare function preciseDuration(totalSeconds: number): string;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a payment target into something a wallet can consume, and a wait into something a person
|
|
3
|
+
* can plan around.
|
|
4
|
+
*
|
|
5
|
+
* Funding asked someone to carry four values from a terminal into a wallet by hand: a token
|
|
6
|
+
* contract, a chain, a treasury address and an exact amount. **A mistyped recipient is the one
|
|
7
|
+
* error in this product that loses real money and cannot be reversed** — no retry, no support
|
|
8
|
+
* ticket, no proof to appeal to.
|
|
9
|
+
*
|
|
10
|
+
* Isolated in its own module because both functions here are pure arithmetic over values the
|
|
11
|
+
* gateway supplied, and both are wrong in ways that are invisible on screen: an off-by-one decimal
|
|
12
|
+
* looks like a plausible number, and a wait estimate that is silently zero looks like a fast chain.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Convert a decimal amount string into the token's smallest unit, exactly.
|
|
16
|
+
*
|
|
17
|
+
* String arithmetic, not `Number(amount) * 10 ** decimals`. That expression is wrong for values
|
|
18
|
+
* this function will certainly see: `25.10 * 1e6` is `25099999.999999996` in IEEE-754, which
|
|
19
|
+
* truncates to 25099999 — a payment one unit short of the amount attribution matches on, so the
|
|
20
|
+
* deposit is received and never credited. The failure is silent on both sides.
|
|
21
|
+
*
|
|
22
|
+
* Throws rather than rounding when the amount carries more precision than the token can express.
|
|
23
|
+
* Quietly dropping a digit would change what the user pays.
|
|
24
|
+
*/
|
|
25
|
+
export function toSmallestUnit(amount, decimals) {
|
|
26
|
+
const clean = String(amount).trim();
|
|
27
|
+
if (!/^\d+(\.\d+)?$/.test(clean)) {
|
|
28
|
+
throw new Error(`"${amount}" is not a positive decimal amount.`);
|
|
29
|
+
}
|
|
30
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) {
|
|
31
|
+
throw new Error(`${decimals} is not a usable token decimal count.`);
|
|
32
|
+
}
|
|
33
|
+
const [whole, fraction = ''] = clean.split('.');
|
|
34
|
+
if (fraction.length > decimals) {
|
|
35
|
+
// Only ever raised by trailing zeros beyond the token's precision, which are safe to drop —
|
|
36
|
+
// anything else would silently alter the amount.
|
|
37
|
+
const significant = fraction.slice(decimals).replace(/0+$/, '');
|
|
38
|
+
if (significant.length > 0) {
|
|
39
|
+
throw new Error(`${amount} has more precision than this token supports (${decimals} decimals). `
|
|
40
|
+
+ 'Rounding it would change what you pay.');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const padded = (fraction + '0'.repeat(decimals)).slice(0, decimals);
|
|
44
|
+
// BigInt, so a large amount cannot lose its low digits the way a float would.
|
|
45
|
+
const units = BigInt(whole) * 10n ** BigInt(decimals) + BigInt(padded || '0');
|
|
46
|
+
return units.toString();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build an EIP-681 payment request for an ERC-20 transfer.
|
|
50
|
+
*
|
|
51
|
+
* `ethereum:<token>@<chainId>/transfer?address=<recipient>&uint256=<amount>`
|
|
52
|
+
*
|
|
53
|
+
* The shape is counter-intuitive and worth stating: the address BEFORE the `@` is the **token
|
|
54
|
+
* contract**, and the recipient is the `address` parameter. Reversing them produces a URI that a
|
|
55
|
+
* wallet will happily open and that transfers nothing — or, worse, calls an unknown method on the
|
|
56
|
+
* treasury address.
|
|
57
|
+
*
|
|
58
|
+
* Every value comes from the gateway's response untouched. Nothing here re-derives a chain id from
|
|
59
|
+
* a slug or re-formats an address, because that is precisely the transcription this exists to
|
|
60
|
+
* eliminate.
|
|
61
|
+
*/
|
|
62
|
+
export function buildPaymentUri(target, amountUsd) {
|
|
63
|
+
for (const [name, value] of Object.entries({
|
|
64
|
+
token_address: target.token_address,
|
|
65
|
+
deposit_address: target.deposit_address,
|
|
66
|
+
})) {
|
|
67
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(String(value ?? ''))) {
|
|
68
|
+
throw new Error(`${name} is not an address: ${String(value)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!Number.isInteger(target.chain_id) || target.chain_id <= 0) {
|
|
72
|
+
throw new Error(`chain_id is not a numeric EVM chain id: ${String(target.chain_id)}`);
|
|
73
|
+
}
|
|
74
|
+
const units = toSmallestUnit(amountUsd, target.token_decimals);
|
|
75
|
+
return `ethereum:${target.token_address}@${target.chain_id}`
|
|
76
|
+
+ `/transfer?address=${target.deposit_address}&uint256=${units}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Seconds per block, for turning a confirmation count into a wait somebody can plan around.
|
|
80
|
+
*
|
|
81
|
+
* Approximate on purpose, and every caller must present the result as an estimate. These are the
|
|
82
|
+
* observed cadences of the testnets this CLI targets; an L2 that batches will occasionally be much
|
|
83
|
+
* faster or much slower than its nominal block time.
|
|
84
|
+
*/
|
|
85
|
+
const BLOCK_SECONDS = {
|
|
86
|
+
'ethereum-sepolia': 12,
|
|
87
|
+
'base-sepolia': 2,
|
|
88
|
+
'arbitrum-sepolia': 0.25,
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* How long `min_confirmations` is likely to take on this chain.
|
|
92
|
+
*
|
|
93
|
+
* Returns null for a chain with no known cadence rather than guessing. A wrong estimate on the
|
|
94
|
+
* command someone is already waiting on is worse than no estimate: it is the number they decide to
|
|
95
|
+
* interrupt against, and interrupting a funding flow is how people send twice.
|
|
96
|
+
*/
|
|
97
|
+
export function estimateWait(chain, confirmations) {
|
|
98
|
+
const perBlock = BLOCK_SECONDS[chain];
|
|
99
|
+
if (perBlock === undefined)
|
|
100
|
+
return null;
|
|
101
|
+
if (!Number.isFinite(confirmations) || confirmations <= 0)
|
|
102
|
+
return null;
|
|
103
|
+
const seconds = Math.max(1, Math.round(perBlock * confirmations));
|
|
104
|
+
return { seconds, text: humanDuration(seconds), basis: chain };
|
|
105
|
+
}
|
|
106
|
+
/** `95` -> `about 2 minutes`. Coarse by design: false precision reads as a promise. */
|
|
107
|
+
export function humanDuration(totalSeconds) {
|
|
108
|
+
const s = Math.max(0, Math.round(totalSeconds));
|
|
109
|
+
if (s < 60)
|
|
110
|
+
return `about ${s} second${s === 1 ? '' : 's'}`;
|
|
111
|
+
const minutes = Math.round(s / 60);
|
|
112
|
+
if (minutes < 60)
|
|
113
|
+
return `about ${minutes} minute${minutes === 1 ? '' : 's'}`;
|
|
114
|
+
const hours = Math.round(minutes / 60);
|
|
115
|
+
return `about ${hours} hour${hours === 1 ? '' : 's'}`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `252` -> `4m 12s`. Exact, unlike `humanDuration`.
|
|
119
|
+
*
|
|
120
|
+
* Used for a quote's remaining validity, where the caller is deciding whether to act NOW and a
|
|
121
|
+
* rounded "about 4 minutes" on a quote with 20 seconds left would be actively misleading.
|
|
122
|
+
*/
|
|
123
|
+
export function preciseDuration(totalSeconds) {
|
|
124
|
+
const s = Math.max(0, Math.floor(totalSeconds));
|
|
125
|
+
if (s < 60)
|
|
126
|
+
return `${s}s`;
|
|
127
|
+
const minutes = Math.floor(s / 60);
|
|
128
|
+
const rest = s % 60;
|
|
129
|
+
if (minutes < 60)
|
|
130
|
+
return rest === 0 ? `${minutes}m` : `${minutes}m ${rest}s`;
|
|
131
|
+
const hours = Math.floor(minutes / 60);
|
|
132
|
+
const mins = minutes % 60;
|
|
133
|
+
return mins === 0 ? `${hours}h` : `${hours}h ${mins}m`;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=payment-uri.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-uri.js","sourceRoot":"","sources":["../src/payment-uri.ts"],"names":[],"mappings":"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"}
|
package/dist/signer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getKeyInfo, signHash } from './keystore.js';
|
|
2
2
|
import { resolvePassphrase } from './passphrase.js';
|
|
3
|
+
import { UsageError } from './errors.js';
|
|
3
4
|
export async function resolveSigner(name) {
|
|
4
5
|
const info = getKeyInfo(name);
|
|
5
6
|
const passphrase = await resolvePassphrase(info.encrypted, name);
|
|
@@ -18,18 +19,20 @@ export async function resolveSigner(name) {
|
|
|
18
19
|
* another. `--sign-with` is the convenience path, not the replacement.
|
|
19
20
|
*/
|
|
20
21
|
export async function resolveSignature(opts) {
|
|
22
|
+
// These are wrong invocations and must exit 2, not 1. As bare Errors they were indistinguishable
|
|
23
|
+
// from a rejected request, which is the exact confusion the exit-code taxonomy exists to prevent.
|
|
21
24
|
if (opts.signWith) {
|
|
22
25
|
if (opts.signature) {
|
|
23
|
-
throw new
|
|
26
|
+
throw new UsageError('Pass either --sign-with or --signature, not both.', 'CONFLICTING_SIGNING_FLAGS');
|
|
24
27
|
}
|
|
25
28
|
if (!opts.hash) {
|
|
26
|
-
throw new
|
|
29
|
+
throw new UsageError('--sign-with needs the hash to sign; this command did not supply one. Pass --hash <hex>.', 'MISSING_HASH');
|
|
27
30
|
}
|
|
28
31
|
const signer = await resolveSigner(opts.signWith);
|
|
29
32
|
return { signature: signer.sign(opts.hash), publicKey: signer.publicKey };
|
|
30
33
|
}
|
|
31
34
|
if (!opts.signature || !opts.publicKey) {
|
|
32
|
-
throw new
|
|
35
|
+
throw new UsageError('Provide --sign-with <key>, or both --signature <hex> and --public-key <hex>.', 'MISSING_SIGNATURE');
|
|
33
36
|
}
|
|
34
37
|
return { signature: opts.signature, publicKey: opts.publicKey };
|
|
35
38
|
}
|
package/dist/signer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgBzC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACjE,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAKtC;IACC,iGAAiG;IACjG,kGAAkG;IAClG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,UAAU,CAAC,mDAAmD,EAAE,2BAA2B,CAAC,CAAC;QACzG,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,UAAU,CAClB,yFAAyF,EACzF,cAAc,CACf,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,IAAI,UAAU,CAClB,8EAA8E,EAC9E,mBAAmB,CACpB,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a Solidity function signature and check arguments against it.
|
|
3
|
+
*
|
|
4
|
+
* This exists so a wrong argument fails HERE, naming the flag the user typed, rather than
|
|
5
|
+
* travelling to the proof service and coming back as a decoding failure with no visible
|
|
6
|
+
* connection to `--arg`. The check is deliberately shallow — it validates the shapes a human
|
|
7
|
+
* gets wrong at the command line (an address that is not 20 bytes, a bytes32 that is 31, a
|
|
8
|
+
* negative uint, a malformed bool) and does not attempt to be an ABI encoder. Encoding is the
|
|
9
|
+
* gateway's job and duplicating it here would be a second implementation to keep in sync.
|
|
10
|
+
*/
|
|
11
|
+
export interface ParsedSignature {
|
|
12
|
+
name: string;
|
|
13
|
+
types: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `confirm(bytes32)` → `{ name: 'confirm', types: ['bytes32'] }`.
|
|
17
|
+
*
|
|
18
|
+
* Nested tuples are rejected rather than half-supported: `--arg` is a flat list of strings, so a
|
|
19
|
+
* tuple has no unambiguous spelling at the command line. Someone who needs one should build the
|
|
20
|
+
* intent JSON and pass `--intent`, and saying so is more useful than accepting a value that will
|
|
21
|
+
* be encoded wrongly.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseSignature(signature: string): ParsedSignature;
|
|
24
|
+
/**
|
|
25
|
+
* Check that the supplied `--arg` values match the signature, and return them.
|
|
26
|
+
*
|
|
27
|
+
* Values are returned as the strings they arrived as. Converting `uint256` to a JS number here
|
|
28
|
+
* would silently lose precision past 2^53 — the exact bug the rest of this codebase takes care to
|
|
29
|
+
* avoid by keeping amounts as strings.
|
|
30
|
+
*/
|
|
31
|
+
export declare function checkArgs(signature: ParsedSignature, args: string[]): string[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { UsageError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* `confirm(bytes32)` → `{ name: 'confirm', types: ['bytes32'] }`.
|
|
4
|
+
*
|
|
5
|
+
* Nested tuples are rejected rather than half-supported: `--arg` is a flat list of strings, so a
|
|
6
|
+
* tuple has no unambiguous spelling at the command line. Someone who needs one should build the
|
|
7
|
+
* intent JSON and pass `--intent`, and saying so is more useful than accepting a value that will
|
|
8
|
+
* be encoded wrongly.
|
|
9
|
+
*/
|
|
10
|
+
export function parseSignature(signature) {
|
|
11
|
+
const trimmed = signature.trim();
|
|
12
|
+
const match = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\s*\((.*)\)$/s);
|
|
13
|
+
if (!match) {
|
|
14
|
+
throw new UsageError(`"${signature}" is not a Solidity function signature. `
|
|
15
|
+
+ 'Write it as name(type,type) — for example: confirm(bytes32) or transfer(address,uint256)', 'INVALID_FUNCTION_SIGNATURE');
|
|
16
|
+
}
|
|
17
|
+
const [, name, rawTypes] = match;
|
|
18
|
+
const inner = rawTypes.trim();
|
|
19
|
+
if (inner.includes('(')) {
|
|
20
|
+
throw new UsageError('Tuple arguments cannot be expressed with --arg. Build the intent as JSON and pass '
|
|
21
|
+
+ '--intent @file.json instead.', 'TUPLE_NOT_SUPPORTED');
|
|
22
|
+
}
|
|
23
|
+
// Split WITHOUT filtering, so an empty entry survives to be reported. Filtering first — which
|
|
24
|
+
// this did — silently swallowed `transfer(address,)` into a one-parameter signature, which is
|
|
25
|
+
// exactly the shift-every-argument-by-one bug the check below exists to prevent.
|
|
26
|
+
const types = inner.length === 0 ? [] : inner.split(',').map((t) => t.trim());
|
|
27
|
+
// `transfer(address, )` and friends: a stray comma means the caller thinks there is a parameter
|
|
28
|
+
// there, and silently dropping it would shift every later argument by one position.
|
|
29
|
+
if (types.some((t) => t.length === 0)) {
|
|
30
|
+
throw new UsageError(`"${signature}" has an empty parameter. Remove the stray comma.`, 'INVALID_FUNCTION_SIGNATURE');
|
|
31
|
+
}
|
|
32
|
+
return { name, types };
|
|
33
|
+
}
|
|
34
|
+
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
35
|
+
const HEX = /^0x[0-9a-fA-F]*$/;
|
|
36
|
+
function checkOne(type, value, position) {
|
|
37
|
+
const where = `argument ${position + 1} (${type})`;
|
|
38
|
+
// Arrays: the element type is checked, the bracket syntax is not further interpreted. A
|
|
39
|
+
// comma-separated list is the only spelling available at the command line.
|
|
40
|
+
if (type.endsWith('[]')) {
|
|
41
|
+
const element = type.slice(0, -2);
|
|
42
|
+
for (const [i, item] of value.split(',').entries()) {
|
|
43
|
+
checkOne(element, item.trim(), position + i);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (type === 'address') {
|
|
48
|
+
if (!ADDRESS.test(value)) {
|
|
49
|
+
throw new UsageError(`${where}: "${value}" is not an address. Expected 0x followed by 40 hex characters.`, 'INVALID_ARGUMENT');
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (type === 'bool') {
|
|
54
|
+
if (!['true', 'false'].includes(value)) {
|
|
55
|
+
throw new UsageError(`${where}: "${value}" is not a bool. Use true or false.`, 'INVALID_ARGUMENT');
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const bytesN = type.match(/^bytes(\d+)$/);
|
|
60
|
+
if (bytesN) {
|
|
61
|
+
const want = Number(bytesN[1]) * 2;
|
|
62
|
+
if (!HEX.test(value) || value.length - 2 !== want) {
|
|
63
|
+
throw new UsageError(`${where}: expected 0x followed by ${want} hex characters (${bytesN[1]} bytes), `
|
|
64
|
+
+ `got ${Math.max(0, value.length - 2)}.`, 'INVALID_ARGUMENT');
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (type === 'bytes') {
|
|
69
|
+
if (!HEX.test(value) || value.length % 2 !== 0) {
|
|
70
|
+
throw new UsageError(`${where}: expected 0x followed by an even number of hex characters.`, 'INVALID_ARGUMENT');
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const intType = type.match(/^(u?)int(\d*)$/);
|
|
75
|
+
if (intType) {
|
|
76
|
+
const unsigned = intType[1] === 'u';
|
|
77
|
+
// Decimal only. A hex integer at the command line is far more often a mistyped bytes32 than a
|
|
78
|
+
// deliberate choice, and BigInt would happily accept it.
|
|
79
|
+
if (!/^-?\d+$/.test(value)) {
|
|
80
|
+
throw new UsageError(`${where}: "${value}" is not a whole number. Pass it in base units, as digits.`, 'INVALID_ARGUMENT');
|
|
81
|
+
}
|
|
82
|
+
if (unsigned && value.startsWith('-')) {
|
|
83
|
+
throw new UsageError(`${where}: ${type} cannot be negative.`, 'INVALID_ARGUMENT');
|
|
84
|
+
}
|
|
85
|
+
const bits = intType[2] ? Number(intType[2]) : 256;
|
|
86
|
+
const limit = unsigned ? 2n ** BigInt(bits) - 1n : 2n ** BigInt(bits - 1) - 1n;
|
|
87
|
+
if (BigInt(value) > limit) {
|
|
88
|
+
throw new UsageError(`${where}: ${value} does not fit in ${type}.`, 'INVALID_ARGUMENT');
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// `string` and anything this function does not model are passed through. Rejecting an unknown
|
|
93
|
+
// type would make the CLI the thing that limits which contracts can be called, which is a much
|
|
94
|
+
// worse failure than letting the gateway decode it.
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check that the supplied `--arg` values match the signature, and return them.
|
|
98
|
+
*
|
|
99
|
+
* Values are returned as the strings they arrived as. Converting `uint256` to a JS number here
|
|
100
|
+
* would silently lose precision past 2^53 — the exact bug the rest of this codebase takes care to
|
|
101
|
+
* avoid by keeping amounts as strings.
|
|
102
|
+
*/
|
|
103
|
+
export function checkArgs(signature, args) {
|
|
104
|
+
if (args.length !== signature.types.length) {
|
|
105
|
+
throw new UsageError(`${signature.name}(${signature.types.join(',')}) takes ${signature.types.length} argument(s), `
|
|
106
|
+
+ `but ${args.length} --arg value(s) were given.`, 'ARGUMENT_COUNT_MISMATCH');
|
|
107
|
+
}
|
|
108
|
+
signature.types.forEach((type, i) => checkOne(type, args[i], i));
|
|
109
|
+
return args;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=solidity-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solidity-args.js","sourceRoot":"","sources":["../src/solidity-args.ts"],"names":[],"mappings":"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"}
|
package/dist/wait.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { CertenClient, Identity } from '@certen.io/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Waiting for asynchronous work to finish.
|
|
4
|
+
*
|
|
5
|
+
* Two of this product's central operations return before they are usable — `POST /v1/identity`
|
|
6
|
+
* answers 202 while provisioning continues, and a transaction intent takes a 60–110 second proof
|
|
7
|
+
* cycle to reach a terminal state. Every document in the repo warns about both. The CLI
|
|
8
|
+
* nonetheless printed the interim response and exited, leaving each user to write the same poll
|
|
9
|
+
* loop, and leaving anyone who did not write one holding an identity that fails at the last step
|
|
10
|
+
* of every flow with an error that never mentions provisioning.
|
|
11
|
+
*
|
|
12
|
+
* The polling shape here is lifted from `certen fund`, which got it right first: speak only when
|
|
13
|
+
* something changes, treat a timeout as neither success nor failure, and never exit 0 on an
|
|
14
|
+
* outcome a script would misread as done.
|
|
15
|
+
*/
|
|
16
|
+
/** `certen fund`'s defaults are 60 min / 5 s; these are per-operation because the work differs. */
|
|
17
|
+
export declare const IDENTITY_WAIT: {
|
|
18
|
+
timeoutMin: number;
|
|
19
|
+
intervalSec: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A proof cycle is 60–110 seconds of real validator work and `execute.wait()` budgets 360s. Seven
|
|
23
|
+
* minutes leaves room for a queue without being an unbounded hang. Do NOT shorten this to make a
|
|
24
|
+
* test faster — it is not a tunable delay.
|
|
25
|
+
*/
|
|
26
|
+
export declare const TX_WAIT: {
|
|
27
|
+
timeoutMin: number;
|
|
28
|
+
intervalSec: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Should this invocation wait?
|
|
32
|
+
*
|
|
33
|
+
* Human mode waits by default, because "it is not ready yet" is an implementation detail nobody
|
|
34
|
+
* asked to manage. JSON mode does NOT, because scripts already written against the old
|
|
35
|
+
* fire-and-forget behaviour must not silently start blocking for minutes. Either default is
|
|
36
|
+
* overridden by saying so explicitly.
|
|
37
|
+
*
|
|
38
|
+
* Read from `process.argv` rather than commander's parsed value: declaring `--no-wait` makes
|
|
39
|
+
* commander default `opts.wait` to true, which erases the distinction between "defaulted" and
|
|
40
|
+
* "asked for" — and that distinction is the whole rule.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveWait(argv?: string[]): boolean;
|
|
43
|
+
export interface WaitBudget {
|
|
44
|
+
timeoutMs: number;
|
|
45
|
+
intervalMs: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validate `--timeout` and `--poll-interval` BEFORE any network call.
|
|
49
|
+
*
|
|
50
|
+
* Checking after would mean a typo'd timeout had already opened an intent that the user then has
|
|
51
|
+
* to wait out or abandon — the same reasoning `certen fund` applies to its own options.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseWaitBudget(timeout: string | undefined, pollInterval: string | undefined, defaults: {
|
|
54
|
+
timeoutMin: number;
|
|
55
|
+
intervalSec: number;
|
|
56
|
+
}): WaitBudget;
|
|
57
|
+
/**
|
|
58
|
+
* Poll an identity until it is genuinely usable.
|
|
59
|
+
*
|
|
60
|
+
* "Usable" is `status` terminal AND `can_sign === true`, and those are two separate conditions
|
|
61
|
+
* that fail for different reasons:
|
|
62
|
+
*
|
|
63
|
+
* - `can_sign === false` — provisioning finished but the key on the on-chain key page is not
|
|
64
|
+
* yours. The identity exists, consumes quota, and can never sign.
|
|
65
|
+
* - `can_sign === null` — the key page could not be READ. That is unknown, not a soft yes; an
|
|
66
|
+
* Accumulate outage is exactly when this distinction matters most. Reporting it as ready would
|
|
67
|
+
* be the one wrong answer, so this keeps polling and, if the budget runs out, says plainly that
|
|
68
|
+
* it could not determine the answer.
|
|
69
|
+
*/
|
|
70
|
+
export declare function waitForIdentity(client: CertenClient, id: string, budget: WaitBudget): Promise<Identity>;
|
|
71
|
+
/**
|
|
72
|
+
* Poll a transaction intent to a terminal state.
|
|
73
|
+
*
|
|
74
|
+
* Delegates to the SDK's `execute.wait()` rather than re-implementing the loop, so the CLI and an
|
|
75
|
+
* SDK caller agree on which statuses are terminal. The SDK signals both failure and timeout by
|
|
76
|
+
* throwing a plain `Error`; those are translated here into typed CLI errors so the exit code and
|
|
77
|
+
* the `--json` envelope carry a code a caller can branch on.
|
|
78
|
+
*/
|
|
79
|
+
export declare function waitForTransaction(client: CertenClient, intentId: string, budget: WaitBudget): Promise<Record<string, unknown>>;
|