@integraledger/lcp-binding-evm-common 0.15.1 → 0.16.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/CHANGELOG.md +53 -3
- package/README.md +9 -2
- package/dist/eas.d.ts +13 -4
- package/dist/eas.d.ts.map +1 -1
- package/dist/eas.js +15 -4
- package/dist/eas.js.map +1 -1
- package/dist/erc1271.d.ts +12 -3
- package/dist/erc1271.d.ts.map +1 -1
- package/dist/erc1271.js +49 -19
- package/dist/erc1271.js.map +1 -1
- package/package.json +4 -4
- package/src/eas.ts +14 -4
- package/src/erc1271.ts +51 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# @integraledger/lcp-binding-evm-common
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2fd5eb2: `isEasValidAsOf` now bounds the validity interval from below.
|
|
8
|
+
|
|
9
|
+
The predicate answers "was this attestation valid AS OF the settlement". It gated on existence, revocation
|
|
10
|
+
and expiry — three facts that all bound the interval from ABOVE — and never read `att.time`, EAS's creation
|
|
11
|
+
timestamp, which was decoded and used by nothing. So an attestation minted the day after a settlement was
|
|
12
|
+
reported valid as of that settlement: backdating by omission, and the one direction an attester can exploit
|
|
13
|
+
after the fact.
|
|
14
|
+
|
|
15
|
+
`att.time > asOfUnixSeconds` is now a refusal. The boundary is inclusive in the same sense as the other
|
|
16
|
+
two: revoked or expired AT the as-of second is invalid, attested AT the as-of second is valid.
|
|
17
|
+
|
|
18
|
+
**This changes published behaviour** — a caller passing an attestation newer than its as-of instant now
|
|
19
|
+
gets `false` where it previously got `true`.
|
|
20
|
+
- bb48020: An RPC outage is no longer reported as a forged signature.
|
|
21
|
+
|
|
22
|
+
`verifyAcceptanceSignature` wrapped the bound verification call in `try { … } catch { return false }`. For
|
|
23
|
+
`eip191` and `eip712` that closure is pure offline recovery, so a throw genuinely is the signature. For
|
|
24
|
+
`evm:erc1271` and `evm:erc6492` it is an on-chain call, and viem has already drawn the line inside it: a
|
|
25
|
+
signature the validator rejects makes the deployless call revert, viem catches its own `VerificationError`
|
|
26
|
+
and returns `false`, and it rethrows only for an HTTP 429, a timeout, or a node that answered garbage.
|
|
27
|
+
Swallowing that rethrow turned every rate-limited RPC into `acceptance/bad-signature` — "signature did not
|
|
28
|
+
verify" — publishing a valid buyer acceptance as a forgery, a verdict the next run reverses. The package's
|
|
29
|
+
own README argued the opposite doctrine three paragraphs above the code: "'not verified' and 'verified as
|
|
30
|
+
forged' are different facts."
|
|
31
|
+
|
|
32
|
+
The guard is now scheme-shaped: it wraps the offline recovery only, and an on-chain call's throw
|
|
33
|
+
propagates. **This changes published behaviour** — a caller of `verifyAcceptanceSignature` or of the
|
|
34
|
+
`SignatureVerifier` returned by `makeEvmAcceptanceVerifier`, on a smart-account scheme, must now handle a
|
|
35
|
+
rejection where it previously received `false`. That is the point of the change: the two facts were
|
|
36
|
+
indistinguishable and one of them was wrong. The `false` verdict for a signature the chain actually
|
|
37
|
+
rejected is unchanged.
|
|
38
|
+
|
|
39
|
+
`authority` gains no behaviour change, only the contract in writing: `SignatureVerifier.verify` returning
|
|
40
|
+
`false` means CHECKED AND INVALID, and `verifyAcceptance` deliberately does not catch a rejection from the
|
|
41
|
+
port, because `acceptance/bad-signature` is a claim about the record and an unreachable node has made none.
|
|
42
|
+
|
|
43
|
+
The replaced test asserted the defect outright — "an on-chain call that throws is reported as false, not
|
|
44
|
+
propagated (a verifier must not crash)".
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- Updated dependencies [bb48020]
|
|
49
|
+
- @integraledger/lcp-authority@0.16.0
|
|
50
|
+
- @integraledger/lcp-binding-core@0.16.0
|
|
51
|
+
- @integraledger/lcp-kernel@0.16.0
|
|
52
|
+
|
|
3
53
|
## 0.15.1
|
|
4
54
|
|
|
5
55
|
### Patch Changes
|
|
@@ -100,8 +150,8 @@
|
|
|
100
150
|
`buildEip3009TypedData` has been here since the canonical EVM binding shipped, and nothing beside it could
|
|
101
151
|
answer whether a given authorization was actually signed by the account it names. So a seller surface
|
|
102
152
|
holding a payer's credential had three bad options: take the signature on trust until settlement, grow a
|
|
103
|
-
viem dependency of its own, or reimplement recovery.
|
|
104
|
-
|
|
153
|
+
viem dependency of its own, or reimplement recovery. A seller MPP surface needs exactly this to check a payer's
|
|
154
|
+
authorization before settlement, and `seller-x402` already reaches here for `makeEvmAcceptanceVerifier` — the commons owns EVM
|
|
105
155
|
crypto, and this is the piece that was missing.
|
|
106
156
|
|
|
107
157
|
⭐ **`ecrecover`, because that is what the TOKEN does.** `FiatTokenV2.transferWithAuthorization` recovers the
|
|
@@ -188,7 +238,7 @@ and a large number of documentation claims were corrected against the host speci
|
|
|
188
238
|
First public release.
|
|
189
239
|
|
|
190
240
|
`0.9.0` is deliberate: this is a release candidate for 1.0, not a preview. The implementation is complete
|
|
191
|
-
against LCP
|
|
241
|
+
against the published LCP specification and certified by the conformance corpus, and the remaining distance to 1.0 is the
|
|
192
242
|
specification's own — the standard is still moving through its steering committee, and this package will not
|
|
193
243
|
claim a stability its protocol has not yet promised.
|
|
194
244
|
|
package/README.md
CHANGED
|
@@ -39,13 +39,20 @@ const ok = await verifyAcceptanceSignature(acceptance);
|
|
|
39
39
|
const onChain = await verifyAcceptanceSignature(acceptance, smartAccountOpts);
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
##
|
|
42
|
+
## Four outcomes, kept distinct
|
|
43
43
|
|
|
44
44
|
A malformed **configuration** throws — an absent chain id or a missing client is an integration error the
|
|
45
45
|
caller must fix. A malformed **record** throws — an unparseable timestamp is a different fact from a
|
|
46
46
|
forged signature, and letting it hide behind a bad-signature verdict would lose that. A malformed
|
|
47
47
|
**signature** returns `false` — recovery over forged bytes fails deep in curve math, and a verifier that
|
|
48
|
-
crashes on a forgery cannot report the forgery.
|
|
48
|
+
crashes on a forgery cannot report the forgery. A chain that could not **answer** throws — an HTTP 429 or
|
|
49
|
+
a timeout says nothing whatever about the signature, and reporting it as `false` publishes a valid buyer
|
|
50
|
+
acceptance as a forgery, a verdict the next run reverses.
|
|
51
|
+
|
|
52
|
+
The last two are told apart by the scheme, not by the error class: `eip191` and `eip712` verify by pure
|
|
53
|
+
offline recovery, so a throw there is the signature; `erc1271` and `erc6492` verify on-chain, and viem
|
|
54
|
+
already returns `false` for a signature its validator rejects and throws only when the node could not be
|
|
55
|
+
reached.
|
|
49
56
|
|
|
50
57
|
Collapsing any two of those into one another is how a verifier ends up reporting the wrong thing about
|
|
51
58
|
the one case it exists for.
|
package/dist/eas.d.ts
CHANGED
|
@@ -84,10 +84,19 @@ export interface EasAttestation {
|
|
|
84
84
|
/** Normalize viem's decoded tuple into an `EasAttestation` (idempotent field mapping; addresses lowercased). */
|
|
85
85
|
export declare function decodeEasAttestation(raw: RawEasAttestation): EasAttestation;
|
|
86
86
|
/**
|
|
87
|
-
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist,
|
|
88
|
-
* as-of time (revocationTime 0 = never revoked), and
|
|
89
|
-
* EAS has no historical query, so a live read
|
|
90
|
-
*
|
|
87
|
+
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist, must already have been ATTESTED by
|
|
88
|
+
* then, must not have been revoked at/before the as-of time (revocationTime 0 = never revoked), and must
|
|
89
|
+
* not have expired by then (expirationTime 0 = no expiry). EAS has no historical query, so a live read
|
|
90
|
+
* yields today's revocationTime; a settlement-time snapshot of the uid is the authority (same as the
|
|
91
|
+
* Bitstring status-list as-of rule) — this predicate states the semantics.
|
|
92
|
+
*
|
|
93
|
+
* ⛔ **The `time` gate bounds the interval from BELOW, and it was missing until 2026-09-03.** Revocation
|
|
94
|
+
* and expiry both bound it from above, so an attestation minted the day AFTER a settlement was reported
|
|
95
|
+
* "valid as of" that settlement — backdating by omission, and the one direction an attester can exploit
|
|
96
|
+
* after the fact. `time` was decoded and read by nothing.
|
|
97
|
+
*
|
|
98
|
+
* All three boundaries are inclusive in the same sense: revoked or expired AT the as-of second is invalid,
|
|
99
|
+
* attested AT the as-of second is valid. The attestation was live for exactly that instant.
|
|
91
100
|
*/
|
|
92
101
|
export declare function isEasValidAsOf(att: EasAttestation, asOfUnixSeconds: bigint): boolean;
|
|
93
102
|
/** Read + normalize an EAS attestation by uid, over the injected viem client (imperative shell). */
|
package/dist/eas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eas.d.ts","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAE9C,2GAA2G;AAC3G,eAAO,MAAM,uBAAuB;aAEhC,IAAI,EAAE,UAAU;aAChB,IAAI,EAAE,gBAAgB;aACtB,eAAe,EAAE,MAAM;aACvB,MAAM;iBAAK,IAAI,EAAE,KAAK;iBAAE,IAAI,EAAE,SAAS;;aACvC,OAAO;iBAEH,IAAI,EAAE,OAAO;iBACb,IAAI,EAAE,EAAE;iBACR,UAAU;qBACN,IAAI,EAAE,KAAK;qBAAE,IAAI,EAAE,SAAS;;qBAC5B,IAAI,EAAE,QAAQ;qBAAE,IAAI,EAAE,SAAS;;qBAC/B,IAAI,EAAE,MAAM;qBAAE,IAAI,EAAE,QAAQ;;qBAC5B,IAAI,EAAE,gBAAgB;qBAAE,IAAI,EAAE,QAAQ;;qBACtC,IAAI,EAAE,gBAAgB;qBAAE,IAAI,EAAE,QAAQ;;qBACtC,IAAI,EAAE,QAAQ;qBAAE,IAAI,EAAE,SAAS;;qBAC/B,IAAI,EAAE,WAAW;qBAAE,IAAI,EAAE,SAAS;;qBAClC,IAAI,EAAE,UAAU;qBAAE,IAAI,EAAE,SAAS;;qBACjC,IAAI,EAAE,WAAW;qBAAE,IAAI,EAAE,MAAM;;qBAC/B,IAAI,EAAE,MAAM;qBAAE,IAAI,EAAE,OAAO;;;EAK7B,CAAC;AAEX,8FAA8F;AAC9F,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;AAED,wGAAwG;AACxG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;IACV,sGAAsG;IACtG,MAAM,EAAE,OAAO,CAAC;CACjB;AAKD,gHAAgH;AAChH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,CAc3E;AAED
|
|
1
|
+
{"version":3,"file":"eas.d.ts","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAE9C,2GAA2G;AAC3G,eAAO,MAAM,uBAAuB;aAEhC,IAAI,EAAE,UAAU;aAChB,IAAI,EAAE,gBAAgB;aACtB,eAAe,EAAE,MAAM;aACvB,MAAM;iBAAK,IAAI,EAAE,KAAK;iBAAE,IAAI,EAAE,SAAS;;aACvC,OAAO;iBAEH,IAAI,EAAE,OAAO;iBACb,IAAI,EAAE,EAAE;iBACR,UAAU;qBACN,IAAI,EAAE,KAAK;qBAAE,IAAI,EAAE,SAAS;;qBAC5B,IAAI,EAAE,QAAQ;qBAAE,IAAI,EAAE,SAAS;;qBAC/B,IAAI,EAAE,MAAM;qBAAE,IAAI,EAAE,QAAQ;;qBAC5B,IAAI,EAAE,gBAAgB;qBAAE,IAAI,EAAE,QAAQ;;qBACtC,IAAI,EAAE,gBAAgB;qBAAE,IAAI,EAAE,QAAQ;;qBACtC,IAAI,EAAE,QAAQ;qBAAE,IAAI,EAAE,SAAS;;qBAC/B,IAAI,EAAE,WAAW;qBAAE,IAAI,EAAE,SAAS;;qBAClC,IAAI,EAAE,UAAU;qBAAE,IAAI,EAAE,SAAS;;qBACjC,IAAI,EAAE,WAAW;qBAAE,IAAI,EAAE,MAAM;;qBAC/B,IAAI,EAAE,MAAM;qBAAE,IAAI,EAAE,OAAO;;;EAK7B,CAAC;AAEX,8FAA8F;AAC9F,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;AAED,wGAAwG;AACxG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;IACV,sGAAsG;IACtG,MAAM,EAAE,OAAO,CAAC;CACjB;AAKD,gHAAgH;AAChH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,CAc3E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,eAAe,EAAE,MAAM,GACtB,OAAO,CAQT;AAED,oGAAoG;AACpG,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,cAAc,CAAC,CAQzB"}
|
package/dist/eas.js
CHANGED
|
@@ -43,14 +43,25 @@ export function decodeEasAttestation(raw) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist,
|
|
47
|
-
* as-of time (revocationTime 0 = never revoked), and
|
|
48
|
-
* EAS has no historical query, so a live read
|
|
49
|
-
*
|
|
46
|
+
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist, must already have been ATTESTED by
|
|
47
|
+
* then, must not have been revoked at/before the as-of time (revocationTime 0 = never revoked), and must
|
|
48
|
+
* not have expired by then (expirationTime 0 = no expiry). EAS has no historical query, so a live read
|
|
49
|
+
* yields today's revocationTime; a settlement-time snapshot of the uid is the authority (same as the
|
|
50
|
+
* Bitstring status-list as-of rule) — this predicate states the semantics.
|
|
51
|
+
*
|
|
52
|
+
* ⛔ **The `time` gate bounds the interval from BELOW, and it was missing until 2026-09-03.** Revocation
|
|
53
|
+
* and expiry both bound it from above, so an attestation minted the day AFTER a settlement was reported
|
|
54
|
+
* "valid as of" that settlement — backdating by omission, and the one direction an attester can exploit
|
|
55
|
+
* after the fact. `time` was decoded and read by nothing.
|
|
56
|
+
*
|
|
57
|
+
* All three boundaries are inclusive in the same sense: revoked or expired AT the as-of second is invalid,
|
|
58
|
+
* attested AT the as-of second is valid. The attestation was live for exactly that instant.
|
|
50
59
|
*/
|
|
51
60
|
export function isEasValidAsOf(att, asOfUnixSeconds) {
|
|
52
61
|
if (!att.exists)
|
|
53
62
|
return false;
|
|
63
|
+
if (att.time > asOfUnixSeconds)
|
|
64
|
+
return false;
|
|
54
65
|
if (att.revocationTime !== 0n && att.revocationTime <= asOfUnixSeconds)
|
|
55
66
|
return false;
|
|
56
67
|
if (att.expirationTime !== 0n && att.expirationTime <= asOfUnixSeconds)
|
package/dist/eas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eas.js","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"AAWA,2GAA2G;AAC3G,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,gBAAgB;QACtB,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC1C,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,EAAE;gBACR,UAAU,EAAE;oBACV,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE;oBAChC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;oBACnC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAChC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC1C,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC1C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;oBACnC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;oBACtC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;oBACrC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;oBACnC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;iBAChC;aACF;SACF;KACF;CACO,CAAC;AAgCX,MAAM,QAAQ,GACZ,oEAAoE,CAAC;AAEvE,gHAAgH;AAChH,MAAM,UAAU,oBAAoB,CAAC,GAAsB;IACzD,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,EAAS;QACjC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,EAAS;QACvC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,EAAS;QACvC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAS;QAC7C,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAS;QAC3C,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,EAAS;QACnC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,QAAQ;KAC3C,CAAC;AACJ,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"eas.js","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"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"}
|
package/dist/erc1271.d.ts
CHANGED
|
@@ -106,7 +106,7 @@ export interface AcceptanceVerifyOpts {
|
|
|
106
106
|
* Verify an acceptance signature. EOA schemes recover offline; smart-account schemes verify on-chain through
|
|
107
107
|
* `opts.client`. Returns a boolean (the port contract).
|
|
108
108
|
*
|
|
109
|
-
*
|
|
109
|
+
* FOUR OUTCOMES, and keeping them distinct is the whole point:
|
|
110
110
|
*
|
|
111
111
|
* - **A malformed CONFIGURATION throws** (absent `chainId` for the envelope, absent client for a smart
|
|
112
112
|
* account) — an integration error the caller must fix, not a fact about the record.
|
|
@@ -118,9 +118,18 @@ export interface AcceptanceVerifyOpts {
|
|
|
118
118
|
* curve math ("Point is not on curve"), and a verifier that crashes on a forgery cannot report the
|
|
119
119
|
* forgery — the adversarial case is exactly the one verification exists for. An unrecoverable signature
|
|
120
120
|
* is definitively not a valid signature, so the walk records an honest `failed(verification-failure)`.
|
|
121
|
+
* - **A chain that could not ANSWER throws.** ⛔ This one used to be swallowed as `false`, and it is the
|
|
122
|
+
* reason the guard is now scheme-shaped rather than wrapped around everything. For an EOA scheme the
|
|
123
|
+
* bound closure is pure recovery with no I/O, so a throw there IS the signature. For `evm:erc1271` and
|
|
124
|
+
* `evm:erc6492` it is an on-chain call, and viem has already drawn this line inside it: a signature the
|
|
125
|
+
* validator rejects makes the deployless call revert, viem catches its own `VerificationError` and
|
|
126
|
+
* returns `false`, and it rethrows only for an HTTP 429, a timeout, or a node that answered garbage.
|
|
127
|
+
* Collapsing that into `false` published a valid buyer acceptance as `acceptance/bad-signature` —
|
|
128
|
+
* "signature did not verify" — for as long as an RPC was rate-limited, a verdict that reverses on the
|
|
129
|
+
* next run. "Not verified" and "verified as forged" are different facts.
|
|
121
130
|
*
|
|
122
|
-
* The guard therefore wraps ONLY the recovery
|
|
123
|
-
*
|
|
131
|
+
* The guard therefore wraps ONLY the OFFLINE recovery calls. Widening it over the normalization above
|
|
132
|
+
* collapses the second outcome into the third; widening it over the on-chain call collapses the fourth.
|
|
124
133
|
*/
|
|
125
134
|
export declare function verifyAcceptanceSignature(input: AcceptanceSignatureInput, opts?: AcceptanceVerifyOpts): Promise<boolean>;
|
|
126
135
|
/**
|
package/dist/erc1271.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erc1271.d.ts","sourceRoot":"","sources":["../src/erc1271.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,GAAG,EAER,KAAK,YAAY,EAGlB,MAAM,MAAM,CAAC;AAEd,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEhE,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB;aACnC,UAAU;iBACN,IAAI,EAAE,SAAS;iBAAE,IAAI,EAAE,SAAS;;iBAChC,IAAI,EAAE,UAAU;iBAAE,IAAI,EAAE,SAAS;;CAE7B,CAAC;AAEX,iHAAiH;AACjH,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AACvD;;qDAEqD;AACrD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,iHAAiH;AACjH,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,KAAK,EAAE,OAAO,wBAAwB,CAAC;IACvC,WAAW,EAAE,YAAY,CAAC;IAC1B,OAAO,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED,sGAAsG;AACtG,wBAAgB,wBAAwB,CAAC,CAAC,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAWtB;AAED,+FAA+F;AAC/F,eAAO,MAAM,sBAAsB,YACjC,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,CACL,CAAC;AACX;;qEAEqE;AACrE,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;uGACuG;AACvG,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAEzE;AAED,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,YAC5B,SAAS,EACT,4BAA4B,CACpB,CAAC;AACX;;;kDAGkD;AAClD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,cAAc,CAE/D;AAED,8GAA8G;AAC9G,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED;;;qFAGqF;AACrF,MAAM,WAAW,oBAAoB;IACnC,8GAA8G;IAC9G,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2GAA2G;IAC3G,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED
|
|
1
|
+
{"version":3,"file":"erc1271.d.ts","sourceRoot":"","sources":["../src/erc1271.ts"],"names":[],"mappings":"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"}
|
package/dist/erc1271.js
CHANGED
|
@@ -63,7 +63,7 @@ export function isEvmPayloadType(v) {
|
|
|
63
63
|
* Verify an acceptance signature. EOA schemes recover offline; smart-account schemes verify on-chain through
|
|
64
64
|
* `opts.client`. Returns a boolean (the port contract).
|
|
65
65
|
*
|
|
66
|
-
*
|
|
66
|
+
* FOUR OUTCOMES, and keeping them distinct is the whole point:
|
|
67
67
|
*
|
|
68
68
|
* - **A malformed CONFIGURATION throws** (absent `chainId` for the envelope, absent client for a smart
|
|
69
69
|
* account) — an integration error the caller must fix, not a fact about the record.
|
|
@@ -75,15 +75,27 @@ export function isEvmPayloadType(v) {
|
|
|
75
75
|
* curve math ("Point is not on curve"), and a verifier that crashes on a forgery cannot report the
|
|
76
76
|
* forgery — the adversarial case is exactly the one verification exists for. An unrecoverable signature
|
|
77
77
|
* is definitively not a valid signature, so the walk records an honest `failed(verification-failure)`.
|
|
78
|
+
* - **A chain that could not ANSWER throws.** ⛔ This one used to be swallowed as `false`, and it is the
|
|
79
|
+
* reason the guard is now scheme-shaped rather than wrapped around everything. For an EOA scheme the
|
|
80
|
+
* bound closure is pure recovery with no I/O, so a throw there IS the signature. For `evm:erc1271` and
|
|
81
|
+
* `evm:erc6492` it is an on-chain call, and viem has already drawn this line inside it: a signature the
|
|
82
|
+
* validator rejects makes the deployless call revert, viem catches its own `VerificationError` and
|
|
83
|
+
* returns `false`, and it rethrows only for an HTTP 429, a timeout, or a node that answered garbage.
|
|
84
|
+
* Collapsing that into `false` published a valid buyer acceptance as `acceptance/bad-signature` —
|
|
85
|
+
* "signature did not verify" — for as long as an RPC was rate-limited, a verdict that reverses on the
|
|
86
|
+
* next run. "Not verified" and "verified as forged" are different facts.
|
|
78
87
|
*
|
|
79
|
-
* The guard therefore wraps ONLY the recovery
|
|
80
|
-
*
|
|
88
|
+
* The guard therefore wraps ONLY the OFFLINE recovery calls. Widening it over the normalization above
|
|
89
|
+
* collapses the second outcome into the third; widening it over the on-chain call collapses the fourth.
|
|
81
90
|
*/
|
|
82
91
|
export async function verifyAcceptanceSignature(input, opts) {
|
|
83
92
|
// Normalization + configuration: OUTSIDE the guard, so both stay loud.
|
|
84
|
-
const
|
|
93
|
+
const { run, offline } = prepareRecovery(input, opts);
|
|
94
|
+
// On-chain: viem's verdict is the whole answer, and anything it throws is the chain failing to give one.
|
|
95
|
+
if (!offline)
|
|
96
|
+
return await run();
|
|
85
97
|
try {
|
|
86
|
-
return await
|
|
98
|
+
return await run();
|
|
87
99
|
}
|
|
88
100
|
catch {
|
|
89
101
|
return false; // the signature itself did not recover — not a valid signature
|
|
@@ -96,6 +108,12 @@ class ConfigurationError extends Error {
|
|
|
96
108
|
* Normalize the record's fields and bind the scheme-appropriate recovery call, returning it UNEXECUTED so
|
|
97
109
|
* the caller can guard the recovery alone. Anything wrong with the configuration or the record's own fields
|
|
98
110
|
* throws from here, before the guard exists.
|
|
111
|
+
*
|
|
112
|
+
* `offline` says whether the bound call does any I/O, and it is the caller's whole basis for deciding
|
|
113
|
+
* whether a throw is a fact about the signature or a fact about the network. It is derived from the scheme
|
|
114
|
+
* here — where the branch is already taken — rather than sniffed off an error class at the catch site: an
|
|
115
|
+
* allowlist of transport-error names is a subject set that goes stale silently, and getting it wrong in
|
|
116
|
+
* that direction reports a forgery.
|
|
99
117
|
*/
|
|
100
118
|
function prepareRecovery(input, opts) {
|
|
101
119
|
// A signer that is not an address is a malformed RECORD, not a forgery — thrown here, before the guard,
|
|
@@ -119,28 +137,40 @@ function prepareRecovery(input, opts) {
|
|
|
119
137
|
// `opts` (not `opts?.`): the chainId gate above already proved it defined — an optional chain here
|
|
120
138
|
// would be dead syntax guarding an impossible state, and the mutation run flags it as equivalent.
|
|
121
139
|
const client = requireClient(opts.client, input.scheme);
|
|
122
|
-
return
|
|
140
|
+
return {
|
|
141
|
+
offline: false,
|
|
142
|
+
run: () => client.verifyTypedData({ address: signer, ...typedData, signature }),
|
|
143
|
+
};
|
|
123
144
|
}
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
return {
|
|
146
|
+
offline: true,
|
|
147
|
+
run: async () => {
|
|
148
|
+
const recovered = await recoverTypedDataAddress({
|
|
149
|
+
...typedData,
|
|
150
|
+
signature,
|
|
151
|
+
});
|
|
152
|
+
return recovered.toLowerCase() === signer.toLowerCase();
|
|
153
|
+
},
|
|
130
154
|
};
|
|
131
155
|
}
|
|
132
156
|
// payloadType === "atrHash": the raw 32-byte atrHash signed as a personal_sign message.
|
|
133
157
|
const raw = assertBytes32(input.atrHash); // throws loud on a malformed atrHash
|
|
134
158
|
if (isContract) {
|
|
135
159
|
const client = requireClient(opts?.client, input.scheme);
|
|
136
|
-
return
|
|
160
|
+
return {
|
|
161
|
+
offline: false,
|
|
162
|
+
run: () => client.verifyMessage({ address: signer, message: { raw }, signature }),
|
|
163
|
+
};
|
|
137
164
|
}
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
165
|
+
return {
|
|
166
|
+
offline: true,
|
|
167
|
+
run: async () => {
|
|
168
|
+
const recovered = await recoverMessageAddress({
|
|
169
|
+
message: { raw },
|
|
170
|
+
signature,
|
|
171
|
+
});
|
|
172
|
+
return recovered.toLowerCase() === signer.toLowerCase();
|
|
173
|
+
},
|
|
144
174
|
};
|
|
145
175
|
}
|
|
146
176
|
function requireClient(client, scheme) {
|
package/dist/erc1271.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erc1271.js","sourceRoot":"","sources":["../src/erc1271.ts"],"names":[],"mappings":"AAyBA,OAAO,EAEL,SAAS,EAET,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAqB,MAAM,cAAc,CAAC;AAEhE,8CAA8C;AAC9C,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;QACpC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;KACtC;CACO,CAAC;AAEX,iHAAiH;AACjH,MAAM,CAAC,MAAM,sBAAsB,GAAG,gBAAgB,CAAC;AACvD;;qDAEqD;AACrD,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAU7C;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,+DAA+D,QAAQ,GAAG,CAC3E,CAAC;IACJ,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,wBAAwB,CAAC,CAIxC;IACC,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,yBAAyB;YAClC,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB;QACD,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,YAAY;QACzB,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE;KACrE,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,aAAa;CACL,CAAC;AAMX;uGACuG;AACvG,MAAM,UAAU,qBAAqB,CAAC,CAAS;IAC7C,OAAQ,sBAA4C,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,SAAS;IACT,4BAA4B;CACpB,CAAC;AAOX,iGAAiG;AACjG,MAAM,UAAU,gBAAgB,CAAC,CAAS;IACxC,OAAQ,iBAAuC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAwBD
|
|
1
|
+
{"version":3,"file":"erc1271.js","sourceRoot":"","sources":["../src/erc1271.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integraledger/lcp-binding-evm-common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Shared EVM machinery for LCP rail bindings: typed-data construction and signature verification.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lcp",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
},
|
|
44
44
|
"homepage": "https://github.com/IntegraLedger/integra-protocol/tree/main/packages/binding-evm-common#readme",
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@integraledger/lcp-authority": "0.
|
|
47
|
-
"@integraledger/lcp-binding-core": "0.
|
|
48
|
-
"@integraledger/lcp-kernel": "0.
|
|
46
|
+
"@integraledger/lcp-authority": "0.16.0",
|
|
47
|
+
"@integraledger/lcp-binding-core": "0.16.0",
|
|
48
|
+
"@integraledger/lcp-kernel": "0.16.0",
|
|
49
49
|
"viem": "2.55.19"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
package/src/eas.ts
CHANGED
|
@@ -88,16 +88,26 @@ export function decodeEasAttestation(raw: RawEasAttestation): EasAttestation {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist,
|
|
92
|
-
* as-of time (revocationTime 0 = never revoked), and
|
|
93
|
-
* EAS has no historical query, so a live read
|
|
94
|
-
*
|
|
91
|
+
* Was this attestation valid AS OF `asOfUnixSeconds`? — it must exist, must already have been ATTESTED by
|
|
92
|
+
* then, must not have been revoked at/before the as-of time (revocationTime 0 = never revoked), and must
|
|
93
|
+
* not have expired by then (expirationTime 0 = no expiry). EAS has no historical query, so a live read
|
|
94
|
+
* yields today's revocationTime; a settlement-time snapshot of the uid is the authority (same as the
|
|
95
|
+
* Bitstring status-list as-of rule) — this predicate states the semantics.
|
|
96
|
+
*
|
|
97
|
+
* ⛔ **The `time` gate bounds the interval from BELOW, and it was missing until 2026-09-03.** Revocation
|
|
98
|
+
* and expiry both bound it from above, so an attestation minted the day AFTER a settlement was reported
|
|
99
|
+
* "valid as of" that settlement — backdating by omission, and the one direction an attester can exploit
|
|
100
|
+
* after the fact. `time` was decoded and read by nothing.
|
|
101
|
+
*
|
|
102
|
+
* All three boundaries are inclusive in the same sense: revoked or expired AT the as-of second is invalid,
|
|
103
|
+
* attested AT the as-of second is valid. The attestation was live for exactly that instant.
|
|
95
104
|
*/
|
|
96
105
|
export function isEasValidAsOf(
|
|
97
106
|
att: EasAttestation,
|
|
98
107
|
asOfUnixSeconds: bigint,
|
|
99
108
|
): boolean {
|
|
100
109
|
if (!att.exists) return false;
|
|
110
|
+
if (att.time > asOfUnixSeconds) return false;
|
|
101
111
|
if (att.revocationTime !== 0n && att.revocationTime <= asOfUnixSeconds)
|
|
102
112
|
return false;
|
|
103
113
|
if (att.expirationTime !== 0n && att.expirationTime <= asOfUnixSeconds)
|
package/src/erc1271.ts
CHANGED
|
@@ -148,7 +148,7 @@ export interface AcceptanceVerifyOpts {
|
|
|
148
148
|
* Verify an acceptance signature. EOA schemes recover offline; smart-account schemes verify on-chain through
|
|
149
149
|
* `opts.client`. Returns a boolean (the port contract).
|
|
150
150
|
*
|
|
151
|
-
*
|
|
151
|
+
* FOUR OUTCOMES, and keeping them distinct is the whole point:
|
|
152
152
|
*
|
|
153
153
|
* - **A malformed CONFIGURATION throws** (absent `chainId` for the envelope, absent client for a smart
|
|
154
154
|
* account) — an integration error the caller must fix, not a fact about the record.
|
|
@@ -160,18 +160,29 @@ export interface AcceptanceVerifyOpts {
|
|
|
160
160
|
* curve math ("Point is not on curve"), and a verifier that crashes on a forgery cannot report the
|
|
161
161
|
* forgery — the adversarial case is exactly the one verification exists for. An unrecoverable signature
|
|
162
162
|
* is definitively not a valid signature, so the walk records an honest `failed(verification-failure)`.
|
|
163
|
+
* - **A chain that could not ANSWER throws.** ⛔ This one used to be swallowed as `false`, and it is the
|
|
164
|
+
* reason the guard is now scheme-shaped rather than wrapped around everything. For an EOA scheme the
|
|
165
|
+
* bound closure is pure recovery with no I/O, so a throw there IS the signature. For `evm:erc1271` and
|
|
166
|
+
* `evm:erc6492` it is an on-chain call, and viem has already drawn this line inside it: a signature the
|
|
167
|
+
* validator rejects makes the deployless call revert, viem catches its own `VerificationError` and
|
|
168
|
+
* returns `false`, and it rethrows only for an HTTP 429, a timeout, or a node that answered garbage.
|
|
169
|
+
* Collapsing that into `false` published a valid buyer acceptance as `acceptance/bad-signature` —
|
|
170
|
+
* "signature did not verify" — for as long as an RPC was rate-limited, a verdict that reverses on the
|
|
171
|
+
* next run. "Not verified" and "verified as forged" are different facts.
|
|
163
172
|
*
|
|
164
|
-
* The guard therefore wraps ONLY the recovery
|
|
165
|
-
*
|
|
173
|
+
* The guard therefore wraps ONLY the OFFLINE recovery calls. Widening it over the normalization above
|
|
174
|
+
* collapses the second outcome into the third; widening it over the on-chain call collapses the fourth.
|
|
166
175
|
*/
|
|
167
176
|
export async function verifyAcceptanceSignature(
|
|
168
177
|
input: AcceptanceSignatureInput,
|
|
169
178
|
opts?: AcceptanceVerifyOpts,
|
|
170
179
|
): Promise<boolean> {
|
|
171
180
|
// Normalization + configuration: OUTSIDE the guard, so both stay loud.
|
|
172
|
-
const
|
|
181
|
+
const { run, offline } = prepareRecovery(input, opts);
|
|
182
|
+
// On-chain: viem's verdict is the whole answer, and anything it throws is the chain failing to give one.
|
|
183
|
+
if (!offline) return await run();
|
|
173
184
|
try {
|
|
174
|
-
return await
|
|
185
|
+
return await run();
|
|
175
186
|
} catch {
|
|
176
187
|
return false; // the signature itself did not recover — not a valid signature
|
|
177
188
|
}
|
|
@@ -184,11 +195,17 @@ class ConfigurationError extends Error {}
|
|
|
184
195
|
* Normalize the record's fields and bind the scheme-appropriate recovery call, returning it UNEXECUTED so
|
|
185
196
|
* the caller can guard the recovery alone. Anything wrong with the configuration or the record's own fields
|
|
186
197
|
* throws from here, before the guard exists.
|
|
198
|
+
*
|
|
199
|
+
* `offline` says whether the bound call does any I/O, and it is the caller's whole basis for deciding
|
|
200
|
+
* whether a throw is a fact about the signature or a fact about the network. It is derived from the scheme
|
|
201
|
+
* here — where the branch is already taken — rather than sniffed off an error class at the catch site: an
|
|
202
|
+
* allowlist of transport-error names is a subject set that goes stale silently, and getting it wrong in
|
|
203
|
+
* that direction reports a forgery.
|
|
187
204
|
*/
|
|
188
205
|
function prepareRecovery(
|
|
189
206
|
input: AcceptanceSignatureInput,
|
|
190
207
|
opts?: AcceptanceVerifyOpts,
|
|
191
|
-
): () => Promise<boolean
|
|
208
|
+
): { run: () => Promise<boolean>; offline: boolean } {
|
|
192
209
|
// A signer that is not an address is a malformed RECORD, not a forgery — thrown here, before the guard,
|
|
193
210
|
// for the same reason rfc3339ToUnixSeconds throws: recovery over it would fail deep in viem and read as
|
|
194
211
|
// a bad-signature verdict about a signature nobody could have examined.
|
|
@@ -216,15 +233,21 @@ function prepareRecovery(
|
|
|
216
233
|
// `opts` (not `opts?.`): the chainId gate above already proved it defined — an optional chain here
|
|
217
234
|
// would be dead syntax guarding an impossible state, and the mutation run flags it as equivalent.
|
|
218
235
|
const client = requireClient(opts.client, input.scheme);
|
|
219
|
-
return
|
|
220
|
-
|
|
236
|
+
return {
|
|
237
|
+
offline: false,
|
|
238
|
+
run: () =>
|
|
239
|
+
client.verifyTypedData({ address: signer, ...typedData, signature }),
|
|
240
|
+
};
|
|
221
241
|
}
|
|
222
|
-
return
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
242
|
+
return {
|
|
243
|
+
offline: true,
|
|
244
|
+
run: async () => {
|
|
245
|
+
const recovered = await recoverTypedDataAddress({
|
|
246
|
+
...typedData,
|
|
247
|
+
signature,
|
|
248
|
+
});
|
|
249
|
+
return recovered.toLowerCase() === signer.toLowerCase();
|
|
250
|
+
},
|
|
228
251
|
};
|
|
229
252
|
}
|
|
230
253
|
|
|
@@ -232,15 +255,21 @@ function prepareRecovery(
|
|
|
232
255
|
const raw = assertBytes32(input.atrHash); // throws loud on a malformed atrHash
|
|
233
256
|
if (isContract) {
|
|
234
257
|
const client = requireClient(opts?.client, input.scheme);
|
|
235
|
-
return
|
|
236
|
-
|
|
258
|
+
return {
|
|
259
|
+
offline: false,
|
|
260
|
+
run: () =>
|
|
261
|
+
client.verifyMessage({ address: signer, message: { raw }, signature }),
|
|
262
|
+
};
|
|
237
263
|
}
|
|
238
|
-
return
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
264
|
+
return {
|
|
265
|
+
offline: true,
|
|
266
|
+
run: async () => {
|
|
267
|
+
const recovered = await recoverMessageAddress({
|
|
268
|
+
message: { raw },
|
|
269
|
+
signature,
|
|
270
|
+
});
|
|
271
|
+
return recovered.toLowerCase() === signer.toLowerCase();
|
|
272
|
+
},
|
|
244
273
|
};
|
|
245
274
|
}
|
|
246
275
|
|