@integraledger/lcp-binding-evm-escrow 0.14.0 → 0.15.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 +34 -0
- package/README.md +0 -1
- package/dist/adapter.d.ts +26 -2
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +33 -5
- package/dist/adapter.js.map +1 -1
- package/package.json +6 -6
- package/src/adapter.ts +35 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @integraledger/lcp-binding-evm-escrow
|
|
2
2
|
|
|
3
|
+
## 0.15.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 78a8748: `saltFromAtrHash` welded whatever `BigInt` would parse. It was a bare `BigInt(atrHash)`, and the call site
|
|
8
|
+
said a malformed value would be "surfaced by BigInt() (fail-fast)" — but `BigInt` accepts any parseable
|
|
9
|
+
numeral, so it surfaced almost nothing. Counted across the EVM rails, this was the only one with no
|
|
10
|
+
atrHash validation anywhere in it: `binding-evm-x402` 2 call sites, `binding-evm-mpp` 6,
|
|
11
|
+
`binding-tempo-mpp` 3, escrow 0.
|
|
12
|
+
|
|
13
|
+
The harm is a silent round trip rather than a crash. Measured: `0x` + `ab`×31 welded as a salt and came
|
|
14
|
+
back out of `atrHashFromSalt` as `0x00abab…` — a DIFFERENT hash, so a verifier reports a mismatch against
|
|
15
|
+
a settlement that welded exactly what it was handed. `"12345"` welded as `0x…3039`. A 33-byte value came
|
|
16
|
+
back as 68 characters, which is not a bytes32 at all. `"0b1010"`, `"0o777"`, `""` and a whitespace-padded
|
|
17
|
+
hash all welded too.
|
|
18
|
+
|
|
19
|
+
`saltFromAtrHash` now goes through `canonicalAtrHash`, which throws — its stated contract for an emit
|
|
20
|
+
path, and what the original comment intended. Uppercase hex DIGITS are still accepted and lowercased: the
|
|
21
|
+
ATR canon is case-insensitive on the digits, and a counterparty spelling its own hash that way is
|
|
22
|
+
conformant. `atrHashFromSalt` asserts the salt fits a uint256 for the mirror reason — `padStart` pads and
|
|
23
|
+
never truncates, so an out-of-range salt returned a string longer than a bytes32 that then compared
|
|
24
|
+
unequal to every real atrHash instead of being refused.
|
|
25
|
+
- Updated dependencies [1da6c07]
|
|
26
|
+
- Updated dependencies [431b8ec]
|
|
27
|
+
- @integraledger/lcp-binding-evm-common@0.15.1
|
|
28
|
+
- @integraledger/lcp-binding-core@0.15.1
|
|
29
|
+
|
|
30
|
+
## 0.15.0
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- @integraledger/lcp-binding-core@0.15.0
|
|
35
|
+
- @integraledger/lcp-binding-evm-common@0.15.0
|
|
36
|
+
|
|
3
37
|
## 0.14.0
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -13,7 +13,6 @@ npm install @integraledger/lcp-binding-evm-escrow
|
|
|
13
13
|
| **Carrier** | `PaymentInfo.salt` |
|
|
14
14
|
| **Surface** | `createEscrowAdapter` returning [`@integraledger/lcp-binding-core`](../binding-core#readme)'s `WeldAdapter` over a `ChainReader` |
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
Built on [`@integraledger/lcp-binding-core`](../binding-core#readme)'s `WeldAdapter` and
|
|
18
17
|
[`@integraledger/lcp-binding-evm-common`](../binding-evm-common#readme). Installing this package installs
|
|
19
18
|
**viem**.
|
package/dist/adapter.d.ts
CHANGED
|
@@ -25,9 +25,33 @@ export interface PaymentInfo {
|
|
|
25
25
|
feeReceiver: `0x${string}`;
|
|
26
26
|
salt: bigint;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* `salt = uint256(atrHash)` — the 32-byte atrHash reinterpreted as a uint256.
|
|
30
|
+
*
|
|
31
|
+
* ⛔ **VALIDATED, because `BigInt` is not a validation.** This was a bare `BigInt(atrHash)` on the
|
|
32
|
+
* strength of a comment saying a malformed value would be "surfaced by BigInt() (fail-fast)". `BigInt`
|
|
33
|
+
* accepts any parseable numeral — a decimal string, a binary or octal literal, a whitespace-padded value,
|
|
34
|
+
* a hash of the wrong length — so it fails fast on almost nothing, and this was the only EVM rail with no
|
|
35
|
+
* atrHash check anywhere in it.
|
|
36
|
+
*
|
|
37
|
+
* The harm is a SILENT ROUND TRIP rather than a crash. A 31-byte value welds and comes back out of
|
|
38
|
+
* {@link atrHashFromSalt} zero-extended — a DIFFERENT hash — so a verifier reports a mismatch against a
|
|
39
|
+
* settlement that welded exactly what it was handed. `"12345"` welds as `0x…3039`.
|
|
40
|
+
*
|
|
41
|
+
* THROWS rather than refusing, which is {@link canonicalAtrHash}'s contract for an emit path and what the
|
|
42
|
+
* original comment meant to arrange: writing a canonical form of a non-hash puts a fabricated reference
|
|
43
|
+
* on a wire. Uppercase hex DIGITS are accepted and lowercased — the ATR canon is case-insensitive on the
|
|
44
|
+
* digits, so a counterparty spelling its own hash that way is conformant.
|
|
45
|
+
*/
|
|
29
46
|
export declare function saltFromAtrHash(atrHash: `0x${string}`): bigint;
|
|
30
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Recover the atrHash from a `PaymentInfo.salt` — the reverse (lowercase 0x, 32 bytes).
|
|
49
|
+
*
|
|
50
|
+
* ⛔ The range is asserted for the same reason the forward direction validates: `padStart` pads and never
|
|
51
|
+
* truncates, so a salt outside `[0, 2^256)` returns a string LONGER than a bytes32, which then compares
|
|
52
|
+
* unequal to every real atrHash instead of being refused. Unreachable through the adapter — viem decodes
|
|
53
|
+
* `salt` as a uint256 — and reachable by any caller of this export.
|
|
54
|
+
*/
|
|
31
55
|
export declare function atrHashFromSalt(salt: bigint): `0x${string}`;
|
|
32
56
|
/** The per-payment proposal inputs (everything but `salt`, which the adapter fills from the atrHash). */
|
|
33
57
|
export type EscrowProposalContext = Omit<PaymentInfo, "salt">;
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAKV,WAAW,EACZ,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAKV,WAAW,EACZ,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,KAAK,GAAG,EAAkB,KAAK,GAAG,EAAY,MAAM,MAAM,CAAC;AAEpE,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,gBAAgB,CAAC;AAMtE;0EAC0E;AAC1E,eAAO,MAAM,iBAAiB,EAAE,GAO9B,CAAC;AAEH,iGAAiG;AACjG,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,GAAG,MAAM,CAE9D;AACD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAM3D;AAED,yGAAyG;AACzG,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAC9D;;+EAE+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED;;qFAEqF;AACrF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB;;;;;;;;;;;;;OAaG;IACH,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B,2GAA2G;IAC3G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,KAAK,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACtB,sEAAsE;IACtE,KAAK,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,GAAG,EAAE,EACpB,MAAM,EAAE,MAAM,GACb,gBAAgB,EAAE,CA0CpB;AAED,sDAAsD;AACtD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,WAAW,CAsG5E"}
|
package/dist/adapter.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { refOf } from "@integraledger/lcp-binding-evm-common";
|
|
2
|
+
import { canonicalAtrHash } from "@integraledger/lcp-kernel";
|
|
2
3
|
import { decodeEventLog, parseAbi } from "viem";
|
|
3
4
|
import { AUTH_CAPTURE_ESCROW } from "./collectors.js";
|
|
4
5
|
import { EVENT_TO_STATE } from "./lifecycle.js";
|
|
@@ -14,12 +15,38 @@ export const ESCROW_EVENTS_ABI = parseAbi([
|
|
|
14
15
|
"event PaymentReclaimed(bytes32 indexed paymentInfoHash, uint256 amount)",
|
|
15
16
|
"event PaymentRefunded(bytes32 indexed paymentInfoHash, uint256 amount, address tokenCollector)",
|
|
16
17
|
]);
|
|
17
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* `salt = uint256(atrHash)` — the 32-byte atrHash reinterpreted as a uint256.
|
|
20
|
+
*
|
|
21
|
+
* ⛔ **VALIDATED, because `BigInt` is not a validation.** This was a bare `BigInt(atrHash)` on the
|
|
22
|
+
* strength of a comment saying a malformed value would be "surfaced by BigInt() (fail-fast)". `BigInt`
|
|
23
|
+
* accepts any parseable numeral — a decimal string, a binary or octal literal, a whitespace-padded value,
|
|
24
|
+
* a hash of the wrong length — so it fails fast on almost nothing, and this was the only EVM rail with no
|
|
25
|
+
* atrHash check anywhere in it.
|
|
26
|
+
*
|
|
27
|
+
* The harm is a SILENT ROUND TRIP rather than a crash. A 31-byte value welds and comes back out of
|
|
28
|
+
* {@link atrHashFromSalt} zero-extended — a DIFFERENT hash — so a verifier reports a mismatch against a
|
|
29
|
+
* settlement that welded exactly what it was handed. `"12345"` welds as `0x…3039`.
|
|
30
|
+
*
|
|
31
|
+
* THROWS rather than refusing, which is {@link canonicalAtrHash}'s contract for an emit path and what the
|
|
32
|
+
* original comment meant to arrange: writing a canonical form of a non-hash puts a fabricated reference
|
|
33
|
+
* on a wire. Uppercase hex DIGITS are accepted and lowercased — the ATR canon is case-insensitive on the
|
|
34
|
+
* digits, so a counterparty spelling its own hash that way is conformant.
|
|
35
|
+
*/
|
|
18
36
|
export function saltFromAtrHash(atrHash) {
|
|
19
|
-
return BigInt(atrHash);
|
|
37
|
+
return BigInt(canonicalAtrHash(atrHash, "saltFromAtrHash"));
|
|
20
38
|
}
|
|
21
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Recover the atrHash from a `PaymentInfo.salt` — the reverse (lowercase 0x, 32 bytes).
|
|
41
|
+
*
|
|
42
|
+
* ⛔ The range is asserted for the same reason the forward direction validates: `padStart` pads and never
|
|
43
|
+
* truncates, so a salt outside `[0, 2^256)` returns a string LONGER than a bytes32, which then compares
|
|
44
|
+
* unequal to every real atrHash instead of being refused. Unreachable through the adapter — viem decodes
|
|
45
|
+
* `salt` as a uint256 — and reachable by any caller of this export.
|
|
46
|
+
*/
|
|
22
47
|
export function atrHashFromSalt(salt) {
|
|
48
|
+
if (salt < 0n || salt >= 1n << 256n)
|
|
49
|
+
throw new Error(`atrHashFromSalt: salt must fit a uint256, got ${salt.toString()}`);
|
|
23
50
|
return `0x${salt.toString(16).padStart(64, "0")}`;
|
|
24
51
|
}
|
|
25
52
|
/**
|
|
@@ -71,8 +98,9 @@ export function createEscrowAdapter(config) {
|
|
|
71
98
|
manifest: ESCROW_MANIFEST,
|
|
72
99
|
async propose(atrHash, ctx) {
|
|
73
100
|
const c = ctx;
|
|
74
|
-
// The salt is filled from the atrHash — never re-derived. No value-level Refusal
|
|
75
|
-
//
|
|
101
|
+
// The salt is filled from the atrHash — never re-derived. No value-level Refusal on this path; a
|
|
102
|
+
// malformed atrHash is a programming error and `saltFromAtrHash` throws on one. It used to say
|
|
103
|
+
// "surfaced by BigInt()", which surfaced almost nothing — see that function.
|
|
76
104
|
const paymentInfo = { ...c, salt: saltFromAtrHash(atrHash) };
|
|
77
105
|
return { ok: true, value: { paymentInfo } };
|
|
78
106
|
},
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,EAAE,MAAM,uCAAuC,CAAC;AAC9D,OAAO,EAAY,cAAc,EAAY,QAAQ,EAAE,MAAM,MAAM,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAwB,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,QAAQ,GACZ,yOAAyO,CAAC;AAE5O;0EAC0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAQ,QAAQ,CAAC;IAC7C,4DAA4D,QAAQ,uDAAuD;IAC3H,yDAAyD,QAAQ,2FAA2F;IAC5J,4GAA4G;IAC5G,sEAAsE;IACtE,yEAAyE;IACzE,gGAAgG;CACjG,CAAC,CAAC;AAkBH
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integraledger/lcp-binding-evm-escrow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Welds an ATR hash into an authorize-and-capture escrow settlement on EVM chains.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lcp",
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/IntegraLedger/integra-protocol/tree/main/packages/binding-evm-escrow#readme",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"
|
|
46
|
-
"@integraledger/lcp-binding-evm-common": "0.
|
|
47
|
-
"
|
|
45
|
+
"@integraledger/lcp-binding-core": "0.15.1",
|
|
46
|
+
"@integraledger/lcp-binding-evm-common": "0.15.1",
|
|
47
|
+
"viem": "2.55.19"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
+
"@integraledger/lcp-kernel": "0.15.1",
|
|
50
51
|
"@types/node": "24.13.3",
|
|
51
|
-
"vitest": "4.1.11"
|
|
52
|
-
"@integraledger/lcp-kernel": "0.14.0"
|
|
52
|
+
"vitest": "4.1.11"
|
|
53
53
|
},
|
|
54
54
|
"license": "Apache-2.0",
|
|
55
55
|
"engines": {
|
package/src/adapter.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
WeldAdapter,
|
|
13
13
|
} from "@integraledger/lcp-binding-core";
|
|
14
14
|
import { refOf } from "@integraledger/lcp-binding-evm-common";
|
|
15
|
+
import { canonicalAtrHash } from "@integraledger/lcp-kernel";
|
|
15
16
|
import { type Abi, decodeEventLog, type Log, parseAbi } from "viem";
|
|
16
17
|
import { AUTH_CAPTURE_ESCROW } from "./collectors.js";
|
|
17
18
|
import { type EscrowEventName, EVENT_TO_STATE } from "./lifecycle.js";
|
|
@@ -47,12 +48,40 @@ export interface PaymentInfo {
|
|
|
47
48
|
salt: bigint;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* `salt = uint256(atrHash)` — the 32-byte atrHash reinterpreted as a uint256.
|
|
53
|
+
*
|
|
54
|
+
* ⛔ **VALIDATED, because `BigInt` is not a validation.** This was a bare `BigInt(atrHash)` on the
|
|
55
|
+
* strength of a comment saying a malformed value would be "surfaced by BigInt() (fail-fast)". `BigInt`
|
|
56
|
+
* accepts any parseable numeral — a decimal string, a binary or octal literal, a whitespace-padded value,
|
|
57
|
+
* a hash of the wrong length — so it fails fast on almost nothing, and this was the only EVM rail with no
|
|
58
|
+
* atrHash check anywhere in it.
|
|
59
|
+
*
|
|
60
|
+
* The harm is a SILENT ROUND TRIP rather than a crash. A 31-byte value welds and comes back out of
|
|
61
|
+
* {@link atrHashFromSalt} zero-extended — a DIFFERENT hash — so a verifier reports a mismatch against a
|
|
62
|
+
* settlement that welded exactly what it was handed. `"12345"` welds as `0x…3039`.
|
|
63
|
+
*
|
|
64
|
+
* THROWS rather than refusing, which is {@link canonicalAtrHash}'s contract for an emit path and what the
|
|
65
|
+
* original comment meant to arrange: writing a canonical form of a non-hash puts a fabricated reference
|
|
66
|
+
* on a wire. Uppercase hex DIGITS are accepted and lowercased — the ATR canon is case-insensitive on the
|
|
67
|
+
* digits, so a counterparty spelling its own hash that way is conformant.
|
|
68
|
+
*/
|
|
51
69
|
export function saltFromAtrHash(atrHash: `0x${string}`): bigint {
|
|
52
|
-
return BigInt(atrHash);
|
|
70
|
+
return BigInt(canonicalAtrHash(atrHash, "saltFromAtrHash"));
|
|
53
71
|
}
|
|
54
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Recover the atrHash from a `PaymentInfo.salt` — the reverse (lowercase 0x, 32 bytes).
|
|
74
|
+
*
|
|
75
|
+
* ⛔ The range is asserted for the same reason the forward direction validates: `padStart` pads and never
|
|
76
|
+
* truncates, so a salt outside `[0, 2^256)` returns a string LONGER than a bytes32, which then compares
|
|
77
|
+
* unequal to every real atrHash instead of being refused. Unreachable through the adapter — viem decodes
|
|
78
|
+
* `salt` as a uint256 — and reachable by any caller of this export.
|
|
79
|
+
*/
|
|
55
80
|
export function atrHashFromSalt(salt: bigint): `0x${string}` {
|
|
81
|
+
if (salt < 0n || salt >= 1n << 256n)
|
|
82
|
+
throw new Error(
|
|
83
|
+
`atrHashFromSalt: salt must fit a uint256, got ${salt.toString()}`,
|
|
84
|
+
);
|
|
56
85
|
return `0x${salt.toString(16).padStart(64, "0")}`;
|
|
57
86
|
}
|
|
58
87
|
|
|
@@ -179,8 +208,9 @@ export function createEscrowAdapter(config: EscrowAdapterConfig): WeldAdapter {
|
|
|
179
208
|
ctx: unknown,
|
|
180
209
|
): Promise<Outcome<EscrowProposal>> {
|
|
181
210
|
const c = ctx as EscrowProposalContext;
|
|
182
|
-
// The salt is filled from the atrHash — never re-derived. No value-level Refusal
|
|
183
|
-
//
|
|
211
|
+
// The salt is filled from the atrHash — never re-derived. No value-level Refusal on this path; a
|
|
212
|
+
// malformed atrHash is a programming error and `saltFromAtrHash` throws on one. It used to say
|
|
213
|
+
// "surfaced by BigInt()", which surfaced almost nothing — see that function.
|
|
184
214
|
const paymentInfo: PaymentInfo = { ...c, salt: saltFromAtrHash(atrHash) };
|
|
185
215
|
return { ok: true, value: { paymentInfo } };
|
|
186
216
|
},
|