@agoric/orchestration 0.1.1-dev-699cb28.0.699cb28 → 0.1.1-dev-eb52bc3.0.eb52bc3
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 +17 -17
- package/src/utils/address.d.ts +3 -3
- package/src/utils/address.d.ts.map +1 -1
- package/src/utils/address.js +2 -18
- package/src/utils/eip712-messages.js +1 -1
- package/src/utils/evm-address.d.ts +4 -0
- package/src/utils/evm-address.d.ts.map +1 -0
- package/src/utils/evm-address.js +28 -0
- package/src/utils/meta.d.ts +31 -0
- package/src/utils/meta.d.ts.map +1 -0
- package/src/utils/meta.js +87 -0
- package/src/utils/permit2/signatureTransferHelpers.js +1 -1
- package/src/utils/viem-utils/eip712-normalize.d.ts.map +1 -1
- package/src/utils/viem-utils/eip712-normalize.js +7 -94
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/orchestration",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
3
|
+
"version": "0.1.1-dev-eb52bc3.0.eb52bc3",
|
|
4
4
|
"description": "Chain abstraction for Agoric's orchestration clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/Agoric/agoric-sdk#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@agoric/async-flow": "0.1.1-dev-
|
|
39
|
-
"@agoric/cosmic-proto": "0.4.1-dev-
|
|
40
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
41
|
-
"@agoric/internal": "0.3.3-dev-
|
|
42
|
-
"@agoric/network": "0.1.1-dev-
|
|
43
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
44
|
-
"@agoric/store": "0.9.3-dev-
|
|
45
|
-
"@agoric/time": "0.3.3-dev-
|
|
46
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
47
|
-
"@agoric/vow": "0.1.1-dev-
|
|
48
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
49
|
-
"@agoric/zone": "0.2.3-dev-
|
|
38
|
+
"@agoric/async-flow": "0.1.1-dev-eb52bc3.0.eb52bc3",
|
|
39
|
+
"@agoric/cosmic-proto": "0.4.1-dev-eb52bc3.0.eb52bc3",
|
|
40
|
+
"@agoric/ertp": "0.16.3-dev-eb52bc3.0.eb52bc3",
|
|
41
|
+
"@agoric/internal": "0.3.3-dev-eb52bc3.0.eb52bc3",
|
|
42
|
+
"@agoric/network": "0.1.1-dev-eb52bc3.0.eb52bc3",
|
|
43
|
+
"@agoric/notifier": "0.6.3-dev-eb52bc3.0.eb52bc3",
|
|
44
|
+
"@agoric/store": "0.9.3-dev-eb52bc3.0.eb52bc3",
|
|
45
|
+
"@agoric/time": "0.3.3-dev-eb52bc3.0.eb52bc3",
|
|
46
|
+
"@agoric/vat-data": "0.5.3-dev-eb52bc3.0.eb52bc3",
|
|
47
|
+
"@agoric/vow": "0.1.1-dev-eb52bc3.0.eb52bc3",
|
|
48
|
+
"@agoric/zoe": "0.26.3-dev-eb52bc3.0.eb52bc3",
|
|
49
|
+
"@agoric/zone": "0.2.3-dev-eb52bc3.0.eb52bc3",
|
|
50
50
|
"@cosmjs/encoding": "^0.36.0",
|
|
51
51
|
"@endo/base64": "^1.1.1",
|
|
52
52
|
"@endo/common": "^1.4.0",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"bs58": "^6.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
65
|
-
"@agoric/vats": "0.15.2-dev-
|
|
66
|
-
"@agoric/xsnap": "0.14.3-dev-
|
|
64
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-eb52bc3.0.eb52bc3",
|
|
65
|
+
"@agoric/vats": "0.15.2-dev-eb52bc3.0.eb52bc3",
|
|
66
|
+
"@agoric/xsnap": "0.14.3-dev-eb52bc3.0.eb52bc3",
|
|
67
67
|
"@chain-registry/client": "^1.53.194",
|
|
68
68
|
"@cosmjs/amino": "^0.36.0",
|
|
69
69
|
"@cosmjs/proto-signing": "^0.36.0",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"typeCoverage": {
|
|
101
101
|
"atLeast": 96.68
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "eb52bc371f1d95f517989c49cf30633ba50d9d41"
|
|
104
104
|
}
|
package/src/utils/address.d.ts
CHANGED
|
@@ -11,8 +11,6 @@ export const DEFAULT_ICQ_VERSION: "icq-1";
|
|
|
11
11
|
export function makeICQChannelAddress(controllerConnectionId: IBCConnectionID, version?: string): RemoteIbcAddress;
|
|
12
12
|
export function findAddressField(remoteAddressString: RemoteIbcAddress): CosmosChainAddress["value"] | undefined;
|
|
13
13
|
export function getBech32Prefix(address: Bech32Address | string): string;
|
|
14
|
-
export function sameEvmAddress(a: EvmAddress, b: EvmAddress | undefined): boolean;
|
|
15
|
-
export function isEvmAddressShape(x: unknown): x is EvmAddress;
|
|
16
14
|
export function coerceAccountId(idArg: AccountIdArg): AccountId;
|
|
17
15
|
export function parseAccountIdArg(idArg: AccountIdArg): Caip10Record;
|
|
18
16
|
export function parseAccountId(accountId: AccountId): Caip10Record;
|
|
@@ -44,9 +42,11 @@ import type { Bech32Address } from '../types.js';
|
|
|
44
42
|
import type { IBCConnectionID } from '@agoric/network/ibc';
|
|
45
43
|
import type { RemoteIbcAddress } from '@agoric/network/ibc';
|
|
46
44
|
import type { CosmosChainAddress } from '../types.js';
|
|
47
|
-
import
|
|
45
|
+
import { sameEvmAddress } from './evm-address.js';
|
|
46
|
+
import { isEvmAddressShape } from './evm-address.js';
|
|
48
47
|
import type { AccountIdArg } from '../orchestration-api.js';
|
|
49
48
|
import type { AccountId } from '../orchestration-api.js';
|
|
50
49
|
import type { Caip10Record } from '../orchestration-api.js';
|
|
51
50
|
import type { CaipChainId } from '../types.js';
|
|
51
|
+
export { sameEvmAddress, isEvmAddressShape };
|
|
52
52
|
//# sourceMappingURL=address.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["address.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["address.js"],"names":[],"mappings":"AA4NA;;;;;;GAMG;AACH,6CAHW,MAAM,GACJ,QAAQ,OAAO,IAAI,aAAa,CAM5C;AA1MM,wDALI,eAAe,0BACf,eAAe,6CACf,qBAAqB,GACnB,gBAAgB,CA4B5B;AAGD,kCAAmC,OAAO,CAAC;AAOpC,8DAJI,eAAe,YACf,MAAM,GACJ,gBAAgB,CAa5B;AAaM,sDAJI,gBAAgB,GAEd,kBAAkB,CAAC,OAAO,CAAC,GAAG,SAAS,CAYnD;AAaM,yCAHI,aAAa,GAAG,MAAM,GACpB,MAAM,CAQlB;AAeM,uCAJI,YAAY,GAEV,SAAS,CAQrB;AAUM,yCAJI,YAAY,GAEV,YAAY,CAaxB;AASM,0CAHI,SAAS,GACP,YAAY,CAaxB;AAUM,6CAJI,YAAY,GAEV,WAAW,CAKvB;AASM,yCAJI,MAAM,GACJ,OAAO,CAkBnB;AAwBM,uDAFI,MAAM,+BAOhB;AAWM,8CAJI,SAAS,GACP,UAAU,CAatB;;;;;;;;;;;;;;;;;;;;;mCAlQgE,aAAa;qCAF1B,qBAAqB;sCAArB,qBAAqB;wCAER,aAAa;+BAL5B,kBAAkB;kCAAlB,kBAAkB;kCAMZ,yBAAyB;+BAAzB,yBAAyB;kCAAzB,yBAAyB;iCADhB,aAAa"}
|
package/src/utils/address.js
CHANGED
|
@@ -2,6 +2,7 @@ import { encodeRemoteIbcAddress } from '@agoric/network/ibc/utils.js';
|
|
|
2
2
|
import { fromBech32, fromHex } from '@cosmjs/encoding';
|
|
3
3
|
import { Fail, q } from '@endo/errors';
|
|
4
4
|
import bs58 from 'bs58';
|
|
5
|
+
import { isEvmAddressShape, sameEvmAddress } from './evm-address.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @import {IBCConnectionID, RemoteIbcAddress} from '@agoric/network/ibc';
|
|
@@ -117,25 +118,8 @@ export const getBech32Prefix = address => {
|
|
|
117
118
|
return address.slice(0, split);
|
|
118
119
|
};
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
* Compare two EVM addresses for equality, case-insensitive.
|
|
122
|
-
*
|
|
123
|
-
* @param {EvmAddress} a
|
|
124
|
-
* @param {EvmAddress | undefined} b
|
|
125
|
-
* @returns {boolean}
|
|
126
|
-
*/
|
|
127
|
-
export const sameEvmAddress = (a, b) => a.toLowerCase() === b?.toLowerCase();
|
|
121
|
+
export { sameEvmAddress, isEvmAddressShape };
|
|
128
122
|
harden(sameEvmAddress);
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Whether `x` has the shape of an EVM address: `0x` followed by 40 hex
|
|
132
|
-
* digits, in any casing (an EIP-55 checksum is not verified).
|
|
133
|
-
*
|
|
134
|
-
* @param {unknown} x
|
|
135
|
-
* @returns {x is EvmAddress}
|
|
136
|
-
*/
|
|
137
|
-
export const isEvmAddressShape = x =>
|
|
138
|
-
typeof x === 'string' && /^0x[0-9a-fA-F]{40}$/u.test(x);
|
|
139
123
|
harden(isEvmAddressShape);
|
|
140
124
|
|
|
141
125
|
/**
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
makeWitness,
|
|
36
36
|
PermitTransferFromTypeParams,
|
|
37
37
|
} from './permit2.js';
|
|
38
|
-
import { isEvmAddressShape, sameEvmAddress } from './address.js';
|
|
38
|
+
import { isEvmAddressShape, sameEvmAddress } from './evm-address.js';
|
|
39
39
|
import { normalizeAndValidateEIP712Data } from './viem-utils/eip712-normalize.js';
|
|
40
40
|
|
|
41
41
|
;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm-address.d.ts","sourceRoot":"","sources":["evm-address.js"],"names":[],"mappings":"AAiBO,kCAJI,UAAU,KACV,UAAU,GAAG,SAAS,GACpB,OAAO,CAEwD;AASrE,qCAHI,OAAO,GACL,CAAC,IAAI,UAAU,CAG6B;2CApBjB,MAAM"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file EVM address helpers with no runtime dependencies, so that modules
|
|
3
|
+
* meant to also run outside of a locked-down (SES) environment, such as the
|
|
4
|
+
* EIP-712 message helpers, can use them.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @import {Address as EvmAddress} from 'viem';
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compare two EVM addresses for equality, case-insensitive.
|
|
13
|
+
*
|
|
14
|
+
* @param {EvmAddress} a
|
|
15
|
+
* @param {EvmAddress | undefined} b
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
export const sameEvmAddress = (a, b) => a.toLowerCase() === b?.toLowerCase();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether `x` has the shape of an EVM address: `0x` followed by 40 hex
|
|
22
|
+
* digits, in any casing (an EIP-55 checksum is not verified).
|
|
23
|
+
*
|
|
24
|
+
* @param {unknown} x
|
|
25
|
+
* @returns {x is EvmAddress}
|
|
26
|
+
*/
|
|
27
|
+
export const isEvmAddressShape = x =>
|
|
28
|
+
typeof x === 'string' && /^0x[0-9a-fA-F]{40}$/u.test(x);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Helpers for quoting or describing values in e.g. error messages
|
|
3
|
+
* and test descriptions.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Quotes and escapes an identifier (a struct/field type or field name) for
|
|
7
|
+
* embedding in an error message. Escaping via `JSON.stringify` happens
|
|
8
|
+
* *after* truncating and covers the whole (possibly-annotated) result, so
|
|
9
|
+
* an embedded quote, backslash, or newline in the identifier can't break
|
|
10
|
+
* out of the message's own quoting, and the `(N chars total)` annotation
|
|
11
|
+
* can't itself get chopped off by a later truncation step (there isn't
|
|
12
|
+
* one).
|
|
13
|
+
*/
|
|
14
|
+
export declare const quoteName: (str: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Quotes and escapes each name in `names` (see `quoteName`) and joins them
|
|
17
|
+
* for an error message -- bounding not just each individual name's length
|
|
18
|
+
* but also, since attacker-controlled data can make the *list itself*
|
|
19
|
+
* arbitrarily long (e.g. very many extra fields on a struct), the number of
|
|
20
|
+
* items included. Cuts off whole items rather than slicing the joined
|
|
21
|
+
* string's raw characters, so the result can never end mid-quote the way
|
|
22
|
+
* `truncate`-ing an already-joined-and-quoted string could.
|
|
23
|
+
*/
|
|
24
|
+
export declare const quoteNameList: (names: readonly string[]) => string;
|
|
25
|
+
/**
|
|
26
|
+
* A short, bounded description of a value for error messages. Only
|
|
27
|
+
* `string`/`number`/`bigint` can be arbitrarily long themselves; anything
|
|
28
|
+
* else is described by shape/type rather than rendered.
|
|
29
|
+
*/
|
|
30
|
+
export declare const describeValue: (value: unknown) => string;
|
|
31
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["meta.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,KAAG,MAAuC,CAAC;AAEhF;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,SAAS,MAAM,EAAE,KAAG,MAIxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,MAqB9C,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Helpers for quoting or describing values in e.g. error messages
|
|
3
|
+
* and test descriptions.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const MAX_DESCRIBED_LENGTH = 100;
|
|
7
|
+
const MAX_DESCRIBED_ITEMS = 10;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Slices `str` to at most `MAX_DESCRIBED_LENGTH` characters, appending
|
|
11
|
+
* `...` if it was cut. Bounds length only -- doesn't escape or annotate;
|
|
12
|
+
* `truncate` and `describeValue`'s string case each build on this
|
|
13
|
+
* differently (an appended `(N chars total)` annotation, or JSON escaping,
|
|
14
|
+
* respectively), so the raw slicing lives in one place.
|
|
15
|
+
*/
|
|
16
|
+
const truncateRaw = (str ) =>
|
|
17
|
+
str.length > MAX_DESCRIBED_LENGTH
|
|
18
|
+
? `${str.slice(0, MAX_DESCRIBED_LENGTH)}...`
|
|
19
|
+
: str;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Bounds a string embedded in an error message -- `message` (and, in
|
|
23
|
+
* 'throw' mode, `types`) can come from an untrusted source, so a field
|
|
24
|
+
* name, value, or joined list of them could otherwise be arbitrarily large.
|
|
25
|
+
* Bounds length only, and doesn't escape the result -- see `quoteName` for
|
|
26
|
+
* a quoted-and-escaped identifier suitable for embedding directly in a
|
|
27
|
+
* message (manually wrapping this in literal quotes instead is unsafe: an
|
|
28
|
+
* embedded quote character in `str` would break out of them).
|
|
29
|
+
*/
|
|
30
|
+
const truncate = (str ) =>
|
|
31
|
+
str.length > MAX_DESCRIBED_LENGTH
|
|
32
|
+
? `${truncateRaw(str)}(${str.length} chars total)`
|
|
33
|
+
: str;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Quotes and escapes an identifier (a struct/field type or field name) for
|
|
37
|
+
* embedding in an error message. Escaping via `JSON.stringify` happens
|
|
38
|
+
* *after* truncating and covers the whole (possibly-annotated) result, so
|
|
39
|
+
* an embedded quote, backslash, or newline in the identifier can't break
|
|
40
|
+
* out of the message's own quoting, and the `(N chars total)` annotation
|
|
41
|
+
* can't itself get chopped off by a later truncation step (there isn't
|
|
42
|
+
* one).
|
|
43
|
+
*/
|
|
44
|
+
export const quoteName = (str ) => JSON.stringify(truncate(str));
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Quotes and escapes each name in `names` (see `quoteName`) and joins them
|
|
48
|
+
* for an error message -- bounding not just each individual name's length
|
|
49
|
+
* but also, since attacker-controlled data can make the *list itself*
|
|
50
|
+
* arbitrarily long (e.g. very many extra fields on a struct), the number of
|
|
51
|
+
* items included. Cuts off whole items rather than slicing the joined
|
|
52
|
+
* string's raw characters, so the result can never end mid-quote the way
|
|
53
|
+
* `truncate`-ing an already-joined-and-quoted string could.
|
|
54
|
+
*/
|
|
55
|
+
export const quoteNameList = (names ) => {
|
|
56
|
+
const shown = names.slice(0, MAX_DESCRIBED_ITEMS).map(quoteName).join(', ');
|
|
57
|
+
const omitted = names.length - MAX_DESCRIBED_ITEMS;
|
|
58
|
+
return omitted > 0 ? `${shown}, and ${omitted} more` : shown;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A short, bounded description of a value for error messages. Only
|
|
63
|
+
* `string`/`number`/`bigint` can be arbitrarily long themselves; anything
|
|
64
|
+
* else is described by shape/type rather than rendered.
|
|
65
|
+
*/
|
|
66
|
+
export const describeValue = (value ) => {
|
|
67
|
+
if (value === null) return 'null';
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
if (value.length > MAX_DESCRIBED_LENGTH) {
|
|
70
|
+
// The `(N chars total)` annotation goes *outside* the JSON-quoted,
|
|
71
|
+
// truncated value (unlike `quoteName`), so it reads as metadata about
|
|
72
|
+
// the value rather than part of it.
|
|
73
|
+
return `${JSON.stringify(truncateRaw(value))}(${value.length} chars total)`;
|
|
74
|
+
}
|
|
75
|
+
return JSON.stringify(value);
|
|
76
|
+
}
|
|
77
|
+
// Truncate the digits *before* appending the `n` suffix -- appending
|
|
78
|
+
// first and truncating the combined string risks slicing the `n` itself
|
|
79
|
+
// off a long enough value, leaving output that no longer looks like a
|
|
80
|
+
// bigint.
|
|
81
|
+
if (typeof value === 'bigint') return `${truncate(`${value}`)}n`;
|
|
82
|
+
if (typeof value === 'number') return truncate(String(value));
|
|
83
|
+
if (value instanceof Uint8Array)
|
|
84
|
+
return `a Uint8Array with ${value.length} byte(s)`;
|
|
85
|
+
if (Array.isArray(value)) return `an array with ${value.length} element(s)`;
|
|
86
|
+
return `a ${typeof value}`;
|
|
87
|
+
};
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
permitWitnessTransferFromTypes,
|
|
28
28
|
TokenPermissionTypeParams,
|
|
29
29
|
} from './signatureTransfer.js';
|
|
30
|
-
import { isEvmAddressShape, sameEvmAddress } from '../address.js';
|
|
30
|
+
import { isEvmAddressShape, sameEvmAddress } from '../evm-address.js';
|
|
31
31
|
|
|
32
32
|
const PrimaryTypes = keyMirror({
|
|
33
33
|
PermitBatchWitnessTransferFrom: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip712-normalize.d.ts","sourceRoot":"","sources":["eip712-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"eip712-normalize.d.ts","sourceRoot":"","sources":["eip712-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIxD,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC,CAAC;AAEjE,MAAM,MAAM,mCAAmC,GAAG;IAChD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACzC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAuCF;;;;;;;;;GASG;AACH,eAAO,MAAM,6BAA6B,QAAO,MACf,CAAC;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAIpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,SAc5D,CAAC;AAeF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,wBAAwB,GACnC,WAAW,MAAM,EACjB,OAAO,OAAO,KACb,OAgFF,CAAC;AAwLF,eAAO,MAAM,8BAA8B,GACzC,OAAO,mCAAmC,EAC1C,UAAS,qCAA0C,KAClD,oCA+EF,CAAC"}
|
|
@@ -65,16 +65,18 @@
|
|
|
65
65
|
* than converted to the equivalent hex string.
|
|
66
66
|
*/
|
|
67
67
|
|
|
68
|
+
import { isEvmAddressShape } from '../evm-address.js';
|
|
69
|
+
import { describeValue, quoteName, quoteNameList } from '../meta.js';
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
;
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
;
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
;
|
|
78
80
|
|
|
79
81
|
|
|
80
82
|
|
|
@@ -87,7 +89,7 @@
|
|
|
87
89
|
|
|
88
90
|
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
;
|
|
91
93
|
|
|
92
94
|
|
|
93
95
|
|
|
@@ -107,11 +109,6 @@ const splitArrayType = (
|
|
|
107
109
|
};
|
|
108
110
|
};
|
|
109
111
|
|
|
110
|
-
// Same shape as `isEvmAddressShape` in `../address.js`, duplicated rather
|
|
111
|
-
// than imported: this module must have no runtime imports (see the module
|
|
112
|
-
// doc comment; `eip712-normalize.xs.test.js` also evaluates its source
|
|
113
|
-
// directly), and `address.js` has runtime dependencies of its own.
|
|
114
|
-
const ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/u;
|
|
115
112
|
// Solidity `(u)int<M>`: (un)signed integer of `M` bits, `0 < M <= 256`,
|
|
116
113
|
// `M % 8 === 0`. Unlike viem's `integerRegex` (utils/regex.ts), the width
|
|
117
114
|
// is required: EIP-712 has no bare `uint`/`int` aliases, and viem and
|
|
@@ -157,90 +154,6 @@ export const EIP712_INTEGER_STRING_MAX_LENGTH = 100;
|
|
|
157
154
|
// abitype types `(u)int<M>` values as `number` for `M <= 48`, else `bigint`.
|
|
158
155
|
const MAX_NUMBER_INTEGER_BITS = 48;
|
|
159
156
|
|
|
160
|
-
const MAX_DESCRIBED_LENGTH = 100;
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Slices `str` to at most `MAX_DESCRIBED_LENGTH` characters, appending
|
|
164
|
-
* `...` if it was cut. Bounds length only -- doesn't escape or annotate;
|
|
165
|
-
* `truncate` and `describeValue`'s string case each build on this
|
|
166
|
-
* differently (an appended `(N chars total)` annotation, or JSON escaping,
|
|
167
|
-
* respectively), so the raw slicing lives in one place.
|
|
168
|
-
*/
|
|
169
|
-
const truncateRaw = (str ) =>
|
|
170
|
-
str.length > MAX_DESCRIBED_LENGTH
|
|
171
|
-
? `${str.slice(0, MAX_DESCRIBED_LENGTH)}...`
|
|
172
|
-
: str;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Bounds a string embedded in an error message -- `message` (and, in
|
|
176
|
-
* 'throw' mode, `types`) can come from an untrusted source, so a field
|
|
177
|
-
* name, value, or joined list of them could otherwise be arbitrarily large.
|
|
178
|
-
* Bounds length only, and doesn't escape the result -- see `quoteName` for
|
|
179
|
-
* a quoted-and-escaped identifier suitable for embedding directly in a
|
|
180
|
-
* message (manually wrapping this in literal quotes instead is unsafe: an
|
|
181
|
-
* embedded quote character in `str` would break out of them).
|
|
182
|
-
*/
|
|
183
|
-
const truncate = (str ) =>
|
|
184
|
-
str.length > MAX_DESCRIBED_LENGTH
|
|
185
|
-
? `${truncateRaw(str)}(${str.length} chars total)`
|
|
186
|
-
: str;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Quotes and escapes an identifier (a struct/field type or field name) for
|
|
190
|
-
* embedding in an error message. Escaping via `JSON.stringify` happens
|
|
191
|
-
* *after* truncating and covers the whole (possibly-annotated) result, so
|
|
192
|
-
* an embedded quote, backslash, or newline in the identifier can't break
|
|
193
|
-
* out of the message's own quoting, and the `(N chars total)` annotation
|
|
194
|
-
* can't itself get chopped off by a later truncation step (there isn't
|
|
195
|
-
* one).
|
|
196
|
-
*/
|
|
197
|
-
const quoteName = (str ) => JSON.stringify(truncate(str));
|
|
198
|
-
|
|
199
|
-
const MAX_DESCRIBED_ITEMS = 10;
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Quotes and escapes each name in `names` (see `quoteName`) and joins them
|
|
203
|
-
* for an error message -- bounding not just each individual name's length
|
|
204
|
-
* but also, since attacker-controlled data can make the *list itself*
|
|
205
|
-
* arbitrarily long (e.g. very many extra fields on a struct), the number of
|
|
206
|
-
* items included. Cuts off whole items rather than slicing the joined
|
|
207
|
-
* string's raw characters, so the result can never end mid-quote the way
|
|
208
|
-
* `truncate`-ing an already-joined-and-quoted string could.
|
|
209
|
-
*/
|
|
210
|
-
const quoteNameList = (names ) => {
|
|
211
|
-
const shown = names.slice(0, MAX_DESCRIBED_ITEMS).map(quoteName).join(', ');
|
|
212
|
-
const omitted = names.length - MAX_DESCRIBED_ITEMS;
|
|
213
|
-
return omitted > 0 ? `${shown}, and ${omitted} more` : shown;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* A short, bounded description of a value for error messages. Only
|
|
218
|
-
* `string`/`number`/`bigint` can be arbitrarily long themselves; anything
|
|
219
|
-
* else is described by shape/type rather than rendered.
|
|
220
|
-
*/
|
|
221
|
-
const describeValue = (value ) => {
|
|
222
|
-
if (value === null) return 'null';
|
|
223
|
-
if (typeof value === 'string') {
|
|
224
|
-
if (value.length > MAX_DESCRIBED_LENGTH) {
|
|
225
|
-
// The `(N chars total)` annotation goes *outside* the JSON-quoted,
|
|
226
|
-
// truncated value (unlike `quoteName`), so it reads as metadata about
|
|
227
|
-
// the value rather than part of it.
|
|
228
|
-
return `${JSON.stringify(truncateRaw(value))}(${value.length} chars total)`;
|
|
229
|
-
}
|
|
230
|
-
return JSON.stringify(value);
|
|
231
|
-
}
|
|
232
|
-
// Truncate the digits *before* appending the `n` suffix -- appending
|
|
233
|
-
// first and truncating the combined string risks slicing the `n` itself
|
|
234
|
-
// off a long enough value, leaving output that no longer looks like a
|
|
235
|
-
// bigint.
|
|
236
|
-
if (typeof value === 'bigint') return `${truncate(`${value}`)}n`;
|
|
237
|
-
if (typeof value === 'number') return truncate(String(value));
|
|
238
|
-
if (value instanceof Uint8Array)
|
|
239
|
-
return `a Uint8Array with ${value.length} byte(s)`;
|
|
240
|
-
if (Array.isArray(value)) return `an array with ${value.length} element(s)`;
|
|
241
|
-
return `a ${typeof value}`;
|
|
242
|
-
};
|
|
243
|
-
|
|
244
157
|
/**
|
|
245
158
|
* Parses an integer given in one of the JS representations accepted for an
|
|
246
159
|
* EIP-712 `(u)int<M>` value: a `bigint`, a safe integer `number`, or a
|
|
@@ -320,7 +233,7 @@ export const normalizeEIP712Primitive = (
|
|
|
320
233
|
const quotedType = quoteName(fieldType);
|
|
321
234
|
|
|
322
235
|
if (fieldType === 'address') {
|
|
323
|
-
if (
|
|
236
|
+
if (!isEvmAddressShape(value)) {
|
|
324
237
|
throw new Error(`Invalid EIP-712 address value: ${describeValue(value)}`);
|
|
325
238
|
}
|
|
326
239
|
return value;
|