@babylonlabs-io/ts-sdk 0.72.1 → 0.74.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/README.md +56 -13
- package/dist/BTCVaultRegistryKeyEpochs.abi-CrQiTLfA.cjs +2 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-CrQiTLfA.cjs.map +1 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-D8cIbMtH.js +229 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-D8cIbMtH.js.map +1 -0
- package/dist/PeginManager-C9RPOd0L.js +1216 -0
- package/dist/PeginManager-C9RPOd0L.js.map +1 -0
- package/dist/PeginManager-E-UHA1un.cjs +2 -0
- package/dist/PeginManager-E-UHA1un.cjs.map +1 -0
- package/dist/bip322Verify-B7_gIhRk.cjs +2 -0
- package/dist/bip322Verify-B7_gIhRk.cjs.map +1 -0
- package/dist/bip322Verify-D6sBBUHE.js +79 -0
- package/dist/bip322Verify-D6sBBUHE.js.map +1 -0
- package/dist/{buildAndBroadcastReclaim-QIN8Mcwq.js → buildAndBroadcastReclaim-BXclIcu_.js} +3 -3
- package/dist/{buildAndBroadcastReclaim-QIN8Mcwq.js.map → buildAndBroadcastReclaim-BXclIcu_.js.map} +1 -1
- package/dist/{buildAndBroadcastReclaim-HX2xQlbM.cjs → buildAndBroadcastReclaim-U-PyFfDg.cjs} +2 -2
- package/dist/{buildAndBroadcastReclaim-HX2xQlbM.cjs.map → buildAndBroadcastReclaim-U-PyFfDg.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +237 -228
- package/dist/index.js.map +1 -1
- package/dist/onChainBtcPubkey-BbxRrbvg.cjs +2 -0
- package/dist/onChainBtcPubkey-BbxRrbvg.cjs.map +1 -0
- package/dist/onChainBtcPubkey-C-6UWpD8.js +34 -0
- package/dist/onChainBtcPubkey-C-6UWpD8.js.map +1 -0
- package/dist/{parseFundingOutpoints-BkgGihaY.cjs → parseFundingOutpoints-B4iQeX6q.cjs} +2 -2
- package/dist/{parseFundingOutpoints-BkgGihaY.cjs.map → parseFundingOutpoints-B4iQeX6q.cjs.map} +1 -1
- package/dist/{parseFundingOutpoints-DlINgQ3X.js → parseFundingOutpoints-B67CoXpF.js} +2 -2
- package/dist/{parseFundingOutpoints-DlINgQ3X.js.map → parseFundingOutpoints-B67CoXpF.js.map} +1 -1
- package/dist/pegin-registration-client-6vLk2itL.cjs +2 -0
- package/dist/pegin-registration-client-6vLk2itL.cjs.map +1 -0
- package/dist/pegin-registration-client-BdRiR8br.js +2635 -0
- package/dist/pegin-registration-client-BdRiR8br.js.map +1 -0
- package/dist/primeVpAuth-DBHohVKM.cjs +2 -0
- package/dist/primeVpAuth-DBHohVKM.cjs.map +1 -0
- package/dist/primeVpAuth-DvaD45q_.js +745 -0
- package/dist/primeVpAuth-DvaD45q_.js.map +1 -0
- package/dist/psbtInputFields-B3e05Xe6.js +171 -0
- package/dist/psbtInputFields-B3e05Xe6.js.map +1 -0
- package/dist/psbtInputFields-BIxBpPj2.cjs +2 -0
- package/dist/psbtInputFields-BIxBpPj2.cjs.map +1 -0
- package/dist/sha2-CrlWM5S8.js +312 -0
- package/dist/{sha2-BYVxyZzX.js.map → sha2-CrlWM5S8.js.map} +1 -1
- package/dist/sha2-DI0-0SHr.cjs +2 -0
- package/dist/{sha2-DsrLC4NM.cjs.map → sha2-DI0-0SHr.cjs.map} +1 -1
- package/dist/{signPsbtsWithFallback-CCFTzE0o.js → signPsbtsWithFallback-0VBALhjS.js} +2 -2
- package/dist/{signPsbtsWithFallback-CCFTzE0o.js.map → signPsbtsWithFallback-0VBALhjS.js.map} +1 -1
- package/dist/{signPsbtsWithFallback-CrkvpSJz.cjs → signPsbtsWithFallback-DMSpIQWH.cjs} +2 -2
- package/dist/{signPsbtsWithFallback-CrkvpSJz.cjs.map → signPsbtsWithFallback-DMSpIQWH.cjs.map} +1 -1
- package/dist/tbv/core/clients/eth/__tests__/eth-import-boundary.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/eth-import-boundary.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/__tests__/onChainBtcPubkey.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/onChainBtcPubkey.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/__tests__/payout-script.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/payout-script.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-registration-calldata.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-registration-calldata.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-registration-client.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-registration-client.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-transaction.test.d.ts +2 -0
- package/dist/tbv/core/clients/eth/__tests__/pegin-transaction.test.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/index.cjs +2 -0
- package/dist/tbv/core/clients/eth/index.cjs.map +1 -0
- package/dist/tbv/core/clients/eth/index.d.ts +4 -0
- package/dist/tbv/core/clients/eth/index.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/index.js +22 -0
- package/dist/tbv/core/clients/eth/index.js.map +1 -0
- package/dist/tbv/core/clients/eth/onChainBtcPubkey.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/payout-script.d.ts +4 -0
- package/dist/tbv/core/clients/eth/payout-script.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/pegin-registration-client.d.ts +99 -0
- package/dist/tbv/core/clients/eth/pegin-registration-client.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/pegin-transaction.d.ts +14 -0
- package/dist/tbv/core/clients/eth/pegin-transaction.d.ts.map +1 -0
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +55 -48
- package/dist/tbv/core/clients/index.js.map +1 -1
- package/dist/tbv/core/clients/mempool/index.cjs +2 -0
- package/dist/tbv/core/clients/mempool/index.cjs.map +1 -0
- package/dist/tbv/core/clients/mempool/index.js +222 -0
- package/dist/tbv/core/clients/mempool/index.js.map +1 -0
- package/dist/tbv/core/contracts/index.cjs +1 -1
- package/dist/tbv/core/contracts/index.cjs.map +1 -1
- package/dist/tbv/core/contracts/index.js +491 -12
- package/dist/tbv/core/contracts/index.js.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.d.ts +4 -0
- package/dist/tbv/core/index.d.ts.map +1 -1
- package/dist/tbv/core/index.js +235 -226
- package/dist/tbv/core/index.js.map +1 -1
- package/dist/tbv/core/managers/PeginManager.d.ts +38 -30
- package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
- package/dist/tbv/core/managers/index.cjs +1 -1
- package/dist/tbv/core/managers/index.d.ts +2 -1
- package/dist/tbv/core/managers/index.d.ts.map +1 -1
- package/dist/tbv/core/managers/index.js +2 -2
- package/dist/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.golden.test.d.ts +62 -0
- package/dist/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.golden.test.d.ts.map +1 -0
- package/dist/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.test.d.ts +15 -0
- package/dist/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.test.d.ts.map +1 -0
- package/dist/tbv/core/pegin-fingerprint/index.d.ts +14 -0
- package/dist/tbv/core/pegin-fingerprint/index.d.ts.map +1 -0
- package/dist/tbv/core/pegin-fingerprint/peginFingerprint.d.ts +141 -0
- package/dist/tbv/core/pegin-fingerprint/peginFingerprint.d.ts.map +1 -0
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.js +2 -2
- package/dist/tbv/core/utils/eth/index.cjs +2 -0
- package/dist/tbv/core/utils/eth/index.cjs.map +1 -0
- package/dist/tbv/core/utils/eth/index.js +109 -0
- package/dist/tbv/core/utils/eth/index.js.map +1 -0
- package/dist/tbv/core/utils/index.cjs +1 -1
- package/dist/tbv/core/utils/index.js +41 -40
- package/dist/tbv/core/utils/index.js.map +1 -1
- package/dist/tbv/core/vault-secrets/index.cjs +1 -1
- package/dist/tbv/core/vault-secrets/index.js +1 -1
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +235 -226
- package/dist/tbv/index.js.map +1 -1
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/toRefundInputs-BwG6T0PP.cjs +2 -0
- package/dist/toRefundInputs-BwG6T0PP.cjs.map +1 -0
- package/dist/{toRefundInputs-BG-qHCEu.js → toRefundInputs-C3oIN0aW.js} +237 -139
- package/dist/toRefundInputs-C3oIN0aW.js.map +1 -0
- package/dist/types-CPDLZm3l.js +430 -0
- package/dist/types-CPDLZm3l.js.map +1 -0
- package/dist/types-DSlcXtog.cjs +2 -0
- package/dist/types-DSlcXtog.cjs.map +1 -0
- package/package.json +32 -3
- package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js +0 -111
- package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js.map +0 -1
- package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs +0 -2
- package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs.map +0 -1
- package/dist/PeginManager-Bwjqb0_6.cjs +0 -2
- package/dist/PeginManager-Bwjqb0_6.cjs.map +0 -1
- package/dist/PeginManager-DjatPUPS.js +0 -1503
- package/dist/PeginManager-DjatPUPS.js.map +0 -1
- package/dist/ProtocolParams.abi-C0TSRaHV.js +0 -486
- package/dist/ProtocolParams.abi-C0TSRaHV.js.map +0 -1
- package/dist/ProtocolParams.abi-CYZoV2EI.cjs +0 -2
- package/dist/ProtocolParams.abi-CYZoV2EI.cjs.map +0 -1
- package/dist/errors-Blc-JWnI.js +0 -121
- package/dist/errors-Blc-JWnI.js.map +0 -1
- package/dist/errors-CGcNP0rV.cjs +0 -2
- package/dist/errors-CGcNP0rV.cjs.map +0 -1
- package/dist/mempoolApi-BJvC9nPF.cjs +0 -2
- package/dist/mempoolApi-BJvC9nPF.cjs.map +0 -1
- package/dist/mempoolApi-_CoQH5vH.js +0 -612
- package/dist/mempoolApi-_CoQH5vH.js.map +0 -1
- package/dist/onChainBtcPubkey-B5ZvWCCF.cjs +0 -2
- package/dist/onChainBtcPubkey-B5ZvWCCF.cjs.map +0 -1
- package/dist/onChainBtcPubkey-DATNfAAl.js +0 -19
- package/dist/onChainBtcPubkey-DATNfAAl.js.map +0 -1
- package/dist/primeVpAuth-BI63kgdd.js +0 -1171
- package/dist/primeVpAuth-BI63kgdd.js.map +0 -1
- package/dist/primeVpAuth-D3xbar3j.cjs +0 -2
- package/dist/primeVpAuth-D3xbar3j.cjs.map +0 -1
- package/dist/sha2-BYVxyZzX.js +0 -274
- package/dist/sha2-DsrLC4NM.cjs +0 -2
- package/dist/toRefundInputs-BG-qHCEu.js.map +0 -1
- package/dist/toRefundInputs-kVR-3EdD.cjs +0 -2
- package/dist/toRefundInputs-kVR-3EdD.cjs.map +0 -1
- package/dist/waitForTransactionReceiptSmartAware-DpQ69ySe.cjs +0 -2
- package/dist/waitForTransactionReceiptSmartAware-DpQ69ySe.cjs.map +0 -1
- package/dist/waitForTransactionReceiptSmartAware-z3Xfmo44.js +0 -277
- package/dist/waitForTransactionReceiptSmartAware-z3Xfmo44.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../../../PeginManager-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../../../PeginManager-E-UHA1un.cjs"),a=require("../../../signPsbtsWithFallback-DMSpIQWH.cjs");exports.PeginManager=e.PeginManager;exports.estimateSubmitPeginRequestBatchGas=e.estimateSubmitPeginRequestBatchGas;exports.PayoutManager=a.PayoutManager;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* @module managers
|
|
22
22
|
*/
|
|
23
23
|
export { PeginManager, estimateSubmitPeginRequestBatchGas } from './PeginManager';
|
|
24
|
-
export type {
|
|
24
|
+
export type { PreparePeginResult, PreparePeginTransaction, PreparePeginDerivedSecrets, PreparePeginParams, PerVaultPeginData, PeginManagerConfig, RegisterPeginParams, RegisterPeginResult, SignAndBroadcastParams, BatchPeginRequestItem, RegisterPeginBatchParams, BatchPeginResultItem, RegisterPeginBatchResult, EstimateSubmitPeginRequestBatchGasParams, } from './PeginManager';
|
|
25
|
+
export type { PopSignature } from '../clients/eth';
|
|
25
26
|
export { PayoutManager } from './PayoutManager';
|
|
26
27
|
export type { PayoutManagerConfig, PayoutSignatureResult, SignPayoutParams, } from './PayoutManager';
|
|
27
28
|
export type { UTXO } from '../utils/utxo/selectUtxos';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tbv/core/managers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,kCAAkC,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tbv/core/managers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,kCAAkC,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,wCAAwC,GACzC,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACtD,YAAY,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,GAChB,MAAM,kDAAkD,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as t, e as r } from "../../../PeginManager-
|
|
2
|
-
import { P as o } from "../../../signPsbtsWithFallback-
|
|
1
|
+
import { P as t, e as r } from "../../../PeginManager-C9RPOd0L.js";
|
|
2
|
+
import { P as o } from "../../../signPsbtsWithFallback-0VBALhjS.js";
|
|
3
3
|
export {
|
|
4
4
|
o as PayoutManager,
|
|
5
5
|
t as PeginManager,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden vectors for the peg-in configuration fingerprint, pinning this
|
|
3
|
+
* encoder byte-for-byte against the vault contracts.
|
|
4
|
+
*
|
|
5
|
+
* ## What is being pinned, and how it could silently diverge
|
|
6
|
+
*
|
|
7
|
+
* The contract computes `keccak256(abi.encode(...))` over ten static fields.
|
|
8
|
+
* Under `abi.encode` every static field becomes one left-padded 32-byte word,
|
|
9
|
+
* so the declared integer WIDTH never reaches the output — encoding the tuple
|
|
10
|
+
* with all-`uint256` slots produces a byte-identical hash. What does change the
|
|
11
|
+
* bytes is the field ORDER, the field COUNT, and static-vs-dynamic type class.
|
|
12
|
+
* A transposition of two same-width fields is therefore invisible to type
|
|
13
|
+
* checking, invisible to a review that only reads the types, and invisible to
|
|
14
|
+
* any fixture whose fields share a value. It surfaces only here.
|
|
15
|
+
*
|
|
16
|
+
* That is why the vectors below give every numeric field of every vector a
|
|
17
|
+
* different non-zero value. The contract repository enforces the rule on its
|
|
18
|
+
* side with `test_peginFingerprintVectors_fieldsAreDistinctAndNonZero`; the
|
|
19
|
+
* fixture is consumed verbatim so the rule carries over rather than being
|
|
20
|
+
* restated.
|
|
21
|
+
*
|
|
22
|
+
* ## Oracle and provenance
|
|
23
|
+
*
|
|
24
|
+
* Source of truth: `_peginFingerprint` in `src/protocol/lib/PeginLogic.sol` of
|
|
25
|
+
* `babylonlabs-io/vault-contracts-aave-v4`, introduced by
|
|
26
|
+
* https://github.com/babylonlabs-io/vault-contracts-aave-v4/pull/555.
|
|
27
|
+
*
|
|
28
|
+
* `vectors/pegin_fingerprint_vectors.json` is that repository's
|
|
29
|
+
* `test/data/pegin_fingerprint_vectors.json`, vendored verbatim at commit
|
|
30
|
+
* `ec62ac62da7a590408ccdcd0a6339a2fa36126b0`. Not transcribed, not reformatted
|
|
31
|
+
* — byte-identity is what makes a re-vendor a diff, and what keeps this file
|
|
32
|
+
* and the Rust `depositor-cli` pinned to one artifact rather than two copies of
|
|
33
|
+
* one. Confirm it with:
|
|
34
|
+
*
|
|
35
|
+
* ```
|
|
36
|
+
* gh api "repos/babylonlabs-io/vault-contracts-aave-v4/contents/test/data/pegin_fingerprint_vectors.json?ref=ec62ac62da7a590408ccdcd0a6339a2fa36126b0" \
|
|
37
|
+
* --jq '.content' | base64 -d \
|
|
38
|
+
* | diff - src/tbv/core/pegin-fingerprint/__tests__/vectors/pegin_fingerprint_vectors.json
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Each vector was also recomputed independently with Foundry, which shares no
|
|
42
|
+
* code with either this encoder or the Solidity library that produced the file:
|
|
43
|
+
*
|
|
44
|
+
* ```
|
|
45
|
+
* cast abi-encode 'f(bytes32,uint256,address,bytes32,uint64,uint64,uint16,uint16,uint16,uint16)' \
|
|
46
|
+
* 0x7a76c7af21338f0474e4755a879f9ae8b6351b37d1a2e79e88e1ae95f20ea24b \
|
|
47
|
+
* 1 0x5FbDB2315678afecb367f032d93F642f64180aa3 \
|
|
48
|
+
* 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 \
|
|
49
|
+
* 3 5 7 11 13 17 | cast keccak
|
|
50
|
+
* # 0xe18d2cbf355cd69b44df7797eac6ad8c2dc522d328b63d20faa4f0be432cd73c
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* ## Failure modes this test is designed to catch
|
|
54
|
+
*
|
|
55
|
+
* If the contract's field order, field count or domain string changes, the
|
|
56
|
+
* vector file changes with it and these assertions fail — which is the signal
|
|
57
|
+
* to re-vendor and re-check, not to edit the expectations. If this encoder
|
|
58
|
+
* drifts instead, the `encoded` assertion fails before the hash assertion and
|
|
59
|
+
* names the diverging word.
|
|
60
|
+
*/
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=peginFingerprint.golden.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peginFingerprint.golden.test.d.ts","sourceRoot":"","sources":["../../../../../src/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.golden.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behaviour of the fingerprint encoder that the golden vectors cannot reach:
|
|
3
|
+
* that every field reaches the output, that out-of-range inputs are rejected by
|
|
4
|
+
* name, and that a non-checksummed address still encodes.
|
|
5
|
+
*
|
|
6
|
+
* Note what is NOT tested here. Field ORDER is pinned by the golden vectors and
|
|
7
|
+
* only by them — a test that swaps two inputs and asserts the hash moves passes
|
|
8
|
+
* just as happily against an encoder that transposes those same two fields
|
|
9
|
+
* internally. What the cases below do catch is a field that never reaches the
|
|
10
|
+
* encoding at all: dropped from the tuple, aliased to a neighbour, or shadowed
|
|
11
|
+
* by a constant. That failure is silent against a hand-written expectation and
|
|
12
|
+
* would otherwise surface only if a vector happened to vary that one field.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=peginFingerprint.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peginFingerprint.test.d.ts","sourceRoot":"","sources":["../../../../../src/tbv/core/pegin-fingerprint/__tests__/peginFingerprint.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Peg-in configuration fingerprint: the `keccak256(abi.encode(...))` commitment
|
|
3
|
+
* over the protocol state a Pre-PegIn transaction was built against, sent with
|
|
4
|
+
* the peg-in registration so the registry can reject a request whose protocol
|
|
5
|
+
* state moved between the build and inclusion.
|
|
6
|
+
*
|
|
7
|
+
* Reproduces `PeginLogic._peginFingerprint` from the vault contracts exactly;
|
|
8
|
+
* see {@link computePeginFingerprint} for the encoding rules that matter.
|
|
9
|
+
*
|
|
10
|
+
* @module pegin-fingerprint
|
|
11
|
+
*/
|
|
12
|
+
export { PEGIN_FINGERPRINT_DOMAIN, PEGIN_FINGERPRINT_DOMAIN_PREIMAGE, PeginFingerprintInputError, computePeginFingerprint, encodePeginFingerprintPreimage, } from './peginFingerprint';
|
|
13
|
+
export type { PeginFingerprintInput } from './peginFingerprint';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tbv/core/pegin-fingerprint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,wBAAwB,EACxB,iCAAiC,EACjC,0BAA0B,EAC1B,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Address, Hex } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* Domain-separation string hashed into every fingerprint, so the commitment
|
|
4
|
+
* cannot be replayed as a different one. Matches the contract's
|
|
5
|
+
* `PEGIN_FINGERPRINT_DOMAIN` preimage.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PEGIN_FINGERPRINT_DOMAIN_PREIMAGE = "TBV.PeginFingerprint.v1";
|
|
8
|
+
/**
|
|
9
|
+
* `keccak256("TBV.PeginFingerprint.v1")`, the first word of the encoded
|
|
10
|
+
* preimage.
|
|
11
|
+
*
|
|
12
|
+
* Derived from {@link PEGIN_FINGERPRINT_DOMAIN_PREIMAGE} rather than pasted as
|
|
13
|
+
* a hex literal, so the string that defines it stays visible. The golden test
|
|
14
|
+
* pins the derived value against the constant the contract's vector file
|
|
15
|
+
* publishes, so a change to either side is still caught.
|
|
16
|
+
*/
|
|
17
|
+
export declare const PEGIN_FINGERPRINT_DOMAIN: Hex;
|
|
18
|
+
/**
|
|
19
|
+
* Protocol state a Pre-PegIn transaction commits to, one field per encoded
|
|
20
|
+
* word.
|
|
21
|
+
*
|
|
22
|
+
* Declared in encoding order so the interface reads as the specification does.
|
|
23
|
+
* Reordering these fields does not change the output — the encoder names each
|
|
24
|
+
* one explicitly — but keeping them aligned makes a divergence from the
|
|
25
|
+
* contract visible on sight.
|
|
26
|
+
*/
|
|
27
|
+
export interface PeginFingerprintInput {
|
|
28
|
+
/** `block.chainid` of the chain the registry is deployed on. */
|
|
29
|
+
chainId: bigint;
|
|
30
|
+
/**
|
|
31
|
+
* The `BTCVaultRegistry` address, which the contract encodes as
|
|
32
|
+
* `address(this)`. EIP-55 checksum casing is irrelevant to the encoded word
|
|
33
|
+
* and is not required here; see {@link encodePeginFingerprintPreimage}.
|
|
34
|
+
*/
|
|
35
|
+
registryAddress: Address;
|
|
36
|
+
/**
|
|
37
|
+
* The vault provider's RESOLVED operation-BTC key, 32 bytes, `0x`-prefixed.
|
|
38
|
+
*
|
|
39
|
+
* The resolved key, not an epoch counter: the VP epoch is one registry-wide
|
|
40
|
+
* counter that ANY provider's key or payout append bumps, so committing to it
|
|
41
|
+
* would let any registered provider invalidate every in-flight Pre-PegIn
|
|
42
|
+
* protocol-wide. Only the chosen provider's key reaches the HTLC leaf, so
|
|
43
|
+
* that is what is committed.
|
|
44
|
+
*
|
|
45
|
+
* Note the SDK resolves this key as an x-only pubkey WITHOUT a `0x` prefix
|
|
46
|
+
* (`OnChainBtcPubkey`); callers add the prefix.
|
|
47
|
+
*/
|
|
48
|
+
vaultProviderBtcKey: Hex;
|
|
49
|
+
/** Vault-keeper operation-key epoch for this application (`uint64`). */
|
|
50
|
+
appKeeperKeyEpoch: bigint;
|
|
51
|
+
/** Universal-challenger operation-key epoch (`uint64`). */
|
|
52
|
+
ucKeyEpoch: bigint;
|
|
53
|
+
/** Roster version selecting which vault keepers are in the leaf (`uint16`). */
|
|
54
|
+
appVaultKeepersVersion: number;
|
|
55
|
+
/** Roster version selecting which universal challengers are in the leaf (`uint16`). */
|
|
56
|
+
universalChallengersVersion: number;
|
|
57
|
+
/** Off-chain params version: `tRefund` and `minPeginFeeRate` (`uint16`). */
|
|
58
|
+
offchainParamsVersion: number;
|
|
59
|
+
/** Vault core (tx-graph) version: the PegIn output count (`uint16`). */
|
|
60
|
+
vaultCoreVersion: number;
|
|
61
|
+
}
|
|
62
|
+
/** An input field is missing, malformed, or outside the width the contract declares for it. */
|
|
63
|
+
export declare class PeginFingerprintInputError extends Error {
|
|
64
|
+
constructor(message: string);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The encoded tuple, as one list so the ordering lives in exactly one place.
|
|
68
|
+
*
|
|
69
|
+
* Not re-exported from the module barrel — this is internal, and exists in
|
|
70
|
+
* this shape so the golden test can render it back into the type string the
|
|
71
|
+
* contract's vector file publishes and compare the two. That comparison is a
|
|
72
|
+
* second, independent check on the field order, one that does not depend on
|
|
73
|
+
* the sample values in the vectors.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PEGIN_FINGERPRINT_ABI_PARAMETERS: readonly [{
|
|
76
|
+
readonly name: "domain";
|
|
77
|
+
readonly type: "bytes32";
|
|
78
|
+
}, {
|
|
79
|
+
readonly name: "chainId";
|
|
80
|
+
readonly type: "uint256";
|
|
81
|
+
}, {
|
|
82
|
+
readonly name: "registry";
|
|
83
|
+
readonly type: "address";
|
|
84
|
+
}, {
|
|
85
|
+
readonly name: "vaultProviderBtcKey";
|
|
86
|
+
readonly type: "bytes32";
|
|
87
|
+
}, {
|
|
88
|
+
readonly name: "appKeeperKeyEpoch";
|
|
89
|
+
readonly type: "uint64";
|
|
90
|
+
}, {
|
|
91
|
+
readonly name: "ucKeyEpoch";
|
|
92
|
+
readonly type: "uint64";
|
|
93
|
+
}, {
|
|
94
|
+
readonly name: "appVaultKeepersVersion";
|
|
95
|
+
readonly type: "uint16";
|
|
96
|
+
}, {
|
|
97
|
+
readonly name: "universalChallengersVersion";
|
|
98
|
+
readonly type: "uint16";
|
|
99
|
+
}, {
|
|
100
|
+
readonly name: "offchainParamsVersion";
|
|
101
|
+
readonly type: "uint16";
|
|
102
|
+
}, {
|
|
103
|
+
readonly name: "vaultCoreVersion";
|
|
104
|
+
readonly type: "uint16";
|
|
105
|
+
}];
|
|
106
|
+
/**
|
|
107
|
+
* The `abi.encode` preimage the contract hashes — ten 32-byte words, 320 bytes.
|
|
108
|
+
*
|
|
109
|
+
* Exposed alongside {@link computePeginFingerprint} because a fingerprint
|
|
110
|
+
* mismatch is otherwise two opaque hashes: comparing preimages word by word
|
|
111
|
+
* localises the disagreement to a field. The contract's vector file ships the
|
|
112
|
+
* same preimage next to each hash for exactly that reason.
|
|
113
|
+
*
|
|
114
|
+
* Three fields are held to a tighter bound than the contract's own width — a
|
|
115
|
+
* zero `chainId`, a zero `registryAddress`, and a `vaultCoreVersion` below 1 —
|
|
116
|
+
* because for each of them a zero is unreachable on-chain and so can only mean
|
|
117
|
+
* a read that failed or was mis-decoded. No chain has id 0, no registry lives
|
|
118
|
+
* at the zero address, and
|
|
119
|
+
* `activeVaultCoreVersion()` is documented `uint16 >= 1` with a setter that
|
|
120
|
+
* rejects 0. Encoding any of them would produce a well-formed fingerprint that
|
|
121
|
+
* cannot ever match, turning a local mistake into an opaque on-chain revert.
|
|
122
|
+
*
|
|
123
|
+
* The three roster and params versions are NOT tightened: 0 is a legitimate
|
|
124
|
+
* value on those axes.
|
|
125
|
+
*
|
|
126
|
+
* @throws {PeginFingerprintInputError} If any field is missing, malformed, or
|
|
127
|
+
* outside the accepted range, naming the field and what was expected.
|
|
128
|
+
*/
|
|
129
|
+
export declare function encodePeginFingerprintPreimage(input: PeginFingerprintInput): Hex;
|
|
130
|
+
/**
|
|
131
|
+
* The fingerprint to send as `expectedFingerprint` on a peg-in registration.
|
|
132
|
+
*
|
|
133
|
+
* Must equal what the registry recomputes at inclusion, byte for byte — the
|
|
134
|
+
* comparison is exact equality, never "no older than", because resolving at a
|
|
135
|
+
* superseded epoch would bond a new vault to a retired key.
|
|
136
|
+
*
|
|
137
|
+
* @throws {PeginFingerprintInputError} If any field is outside the width the
|
|
138
|
+
* contract declares for it.
|
|
139
|
+
*/
|
|
140
|
+
export declare function computePeginFingerprint(input: PeginFingerprintInput): Hex;
|
|
141
|
+
//# sourceMappingURL=peginFingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peginFingerprint.d.ts","sourceRoot":"","sources":["../../../../src/tbv/core/pegin-fingerprint/peginFingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAEd;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,4BAA4B,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,EAAE,GAEtC,CAAC;AAsBF;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,mBAAmB,EAAE,GAAG,CAAC;IACzB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uFAAuF;IACvF,2BAA2B,EAAE,MAAM,CAAC;IACpC,4EAA4E;IAC5E,qBAAqB,EAAE,MAAM,CAAC;IAC9B,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,+FAA+F;AAC/F,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,OAAO,EAAE,MAAM;CAI5B;AAoFD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWnC,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,GAC3B,GAAG,CA+CL;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,GAAG,CAEzE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../../../signPsbtsWithFallback-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../../../signPsbtsWithFallback-DMSpIQWH.cjs"),t=require("../../../buildAndBroadcastReclaim-U-PyFfDg.cjs"),i=require("../../../peginState-eaQ4IO_R.cjs");exports.computeHashlock=e.computeHashlock;exports.validateSecretAgainstHashlock=e.validateSecretAgainstHashlock;exports.BIP68NotMatureError=t.BIP68NotMatureError;exports.ClaimerPegoutStatusValue=t.ClaimerPegoutStatusValue;exports.PEGIN_ETH_CONFIRMATIONS=t.PEGIN_ETH_CONFIRMATIONS;exports.ParticipantKeyDriftError=t.ParticipantKeyDriftError;exports.PeginRegistrationMissingError=t.PeginRegistrationMissingError;exports.PeginRegistrationNotFinalError=t.PeginRegistrationNotFinalError;exports.RECLAIM_MAX_FEE_FRACTION_DENOMINATOR=t.RECLAIM_MAX_FEE_FRACTION_DENOMINATOR;exports.RECLAIM_MAX_FEE_FRACTION_NUMERATOR=t.RECLAIM_MAX_FEE_FRACTION_NUMERATOR;exports.RECLAIM_MAX_FEE_RATE_SATS_VB=t.RECLAIM_MAX_FEE_RATE_SATS_VB;exports.RECLAIM_WARN_FEE_FRACTION_NUMERATOR=t.RECLAIM_WARN_FEE_FRACTION_NUMERATOR;exports.REFUND_MAX_FEE_FRACTION_DENOMINATOR=t.REFUND_MAX_FEE_FRACTION_DENOMINATOR;exports.REFUND_MAX_FEE_FRACTION_NUMERATOR=t.REFUND_MAX_FEE_FRACTION_NUMERATOR;exports.REFUND_MAX_FEE_RATE_SATS_VB=t.REFUND_MAX_FEE_RATE_SATS_VB;exports.REFUND_VSIZE=t.REFUND_VSIZE;exports.ReclaimUneconomicalError=t.ReclaimUneconomicalError;exports.RegisteredVaultVersionMismatchError=t.RegisteredVaultVersionMismatchError;exports.activateVault=t.activateVault;exports.activateVaultAndRedeem=t.activateVaultAndRedeem;exports.assertVaultProviderHintAccepted=t.assertVaultProviderHintAccepted;exports.buildAndBroadcastReclaim=t.buildAndBroadcastReclaim;exports.buildAndBroadcastRefund=t.buildAndBroadcastRefund;exports.estimateRefundFeeSats=t.estimateRefundFeeSats;exports.isDepositAmountValid=t.isDepositAmountValid;exports.isHintAccepted=t.isHintAccepted;exports.isParticipantKeyDriftError=t.isParticipantKeyDriftError;exports.isPeginRegistrationMissingError=t.isPeginRegistrationMissingError;exports.isPeginRegistrationNotFinalError=t.isPeginRegistrationNotFinalError;exports.isPegoutTerminalStatus=t.isPegoutTerminalStatus;exports.isRecognizedPegoutStatus=t.isRecognizedPegoutStatus;exports.isRegisteredVaultVersionMismatchError=t.isRegisteredVaultVersionMismatchError;exports.matchKeyHint=t.matchKeyHint;exports.matchKeySetHint=t.matchKeySetHint;exports.resolveCurrentParticipantKeys=t.resolveCurrentParticipantKeys;exports.resolveParticipantKeysAtEpochs=t.resolveParticipantKeysAtEpochs;exports.runDepositorPresignFlow=t.runDepositorPresignFlow;exports.signDepositorGraph=t.signDepositorGraph;exports.submitWotsPublicKey=t.submitWotsPublicKey;exports.validateDepositAmount=t.validateDepositAmount;exports.validateMultiVaultDepositInputs=t.validateMultiVaultDepositInputs;exports.validateOnChainParticipantKeys=t.validateOnChainParticipantKeys;exports.validateProviderSelection=t.validateProviderSelection;exports.validateRemainingCapacity=t.validateRemainingCapacity;exports.validateVaultAmounts=t.validateVaultAmounts;exports.validateVaultProviderPubkey=t.validateVaultProviderPubkey;exports.verifyRegisteredParticipantKeys=t.verifyRegisteredParticipantKeys;exports.verifyRegisteredVaultVersions=t.verifyRegisteredVaultVersions;exports.waitForPeginRegistrationDepth=t.waitForPeginRegistrationDepth;exports.waitForPeginStatus=t.waitForPeginStatus;exports.ContractStatus=i.ContractStatus;exports.PeginAction=i.PeginAction;exports.canPerformAction=i.canPerformAction;exports.getPeginProtocolState=i.getPeginProtocolState;exports.isActivationDeadlinePassedOnChain=i.isActivationDeadlinePassedOnChain;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as s, v as i } from "../../../signPsbtsWithFallback-
|
|
2
|
-
import { H as r, E as o, P as n, o as E, c as R, d as c, S as A, T as l, U as u, V as _, K as d, L as g, M as P, N as F, O as N, R as p, a as M, b as m, y as v, Q as C, I, J as T, g as V, z as O, p as S, i as D, e as y, G as h, F as f, t as K, A as U, B as H, C as b, D as B, r as X, s as L, f as k, h as w, j as x, v as G, k as z, l as W, m as j, n as q, q as J, u as Q, w as Z, x as Y } from "../../../buildAndBroadcastReclaim-
|
|
1
|
+
import { c as s, v as i } from "../../../signPsbtsWithFallback-0VBALhjS.js";
|
|
2
|
+
import { H as r, E as o, P as n, o as E, c as R, d as c, S as A, T as l, U as u, V as _, K as d, L as g, M as P, N as F, O as N, R as p, a as M, b as m, y as v, Q as C, I, J as T, g as V, z as O, p as S, i as D, e as y, G as h, F as f, t as K, A as U, B as H, C as b, D as B, r as X, s as L, f as k, h as w, j as x, v as G, k as z, l as W, m as j, n as q, q as J, u as Q, w as Z, x as Y } from "../../../buildAndBroadcastReclaim-BXclIcu_.js";
|
|
3
3
|
import { C as aa, P as ta, c as sa, g as ia, i as ea } from "../../../peginState-CxDiaKuk.js";
|
|
4
4
|
export {
|
|
5
5
|
r as BIP68NotMatureError,
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f={1:"https://safe-transaction-mainnet.safe.global",11155111:"https://safe-transaction-sepolia.safe.global"},w=5e3,d=14400*1e3,T=1e4,h="/api/v1/multisig-transactions",p=404,A=500,m=2,_="0xef0100",R=20,g=_.length+m*R;function I(e){return e.length===g&&e.toLowerCase().startsWith(_)}async function F(e){const{publicClient:t,walletAddress:a,hash:r,confirmations:i,timeout:c,safePollTimeoutMs:l=d,safePollIntervalMs:u=w}=e,s=await t.getCode({address:a});if(!(s!==void 0&&s!=="0x"&&!I(s)))return t.waitForTransactionReceipt({hash:r,confirmations:i,timeout:c});const o=await t.getChainId(),n=await L({chainId:o,publicClient:t,safeTxHash:r,pollIntervalMs:u,timeoutMs:l});return n.kind==="not-a-proposal"?t.waitForTransactionReceipt({hash:r,confirmations:i,timeout:c}):t.waitForTransactionReceipt({hash:n.transactionHash,confirmations:i})}async function C(e,t){return await e.getTransaction({hash:t}).catch(()=>null)!==null}async function L({chainId:e,publicClient:t,safeTxHash:a,pollIntervalMs:r,timeoutMs:i}){const c=f[e];if(!c)throw new Error(`Safe Transaction Service not configured for chainId ${e}. Connected wallet appears to be a smart-contract account, but this chain is not in the supported list. Either connect an EOA or extend SAFE_TX_SERVICE_BASE_URLS in waitForTransactionReceiptSmartAware.ts.`);const l=`${c}${h}/${a}/`,u=Date.now()+i;for(;Date.now()<u;){const s=new AbortController,E=setTimeout(()=>s.abort(),T);let o;try{o=await fetch(l,{signal:s.signal})}catch(n){console.warn(`Safe Transaction Service request failed (will retry in ${r}ms): `+(n instanceof Error?n.message:String(n))),await S(r);continue}finally{clearTimeout(E)}if(o.ok){const n=await o.json();if(n.isExecuted){if(n.isSuccessful===!1)throw new Error(`Safe transaction ${a} was executed on chain but reverted. Check the Safe queue UI for details.`);if(n.transactionHash)return{kind:"executed",transactionHash:n.transactionHash}}}else if(o.status===p){if(await C(t,a))return console.warn(`${a} is a real transaction, not a Safe proposal — the connected wallet submits its own transactions despite reporting contract bytecode. Waiting for its receipt directly.`),{kind:"not-a-proposal"}}else if(o.status>=A)console.warn(`Safe Transaction Service returned ${o.status} for ${a}; retrying in ${r}ms.`);else throw new Error(`Safe Transaction Service returned ${o.status} for ${a}.`);await S(r)}throw new Error(`Timed out after ${i}ms waiting for Safe transaction ${a} to reach quorum and execute. The proposal is still pending in the Safe queue — co-signers must sign and execute it before the dApp can proceed.`)}function S(e){return new Promise(t=>{setTimeout(t,e)})}exports.waitForTransactionReceiptSmartAware=F;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../../../src/tbv/core/utils/eth/waitForTransactionReceiptSmartAware.ts"],"sourcesContent":["/**\n * Smart-account-aware wrapper around viem's `waitForTransactionReceipt`.\n *\n * Externally Owned Accounts (EOAs) — wallets controlled by a single private\n * key, e.g. MetaMask or a hardware wallet. `eth_sendTransaction` returns a real\n * Ethereum tx hash, which viem can poll directly. This wrapper delegates\n * unchanged for them.\n *\n * Smart-contract accounts (e.g. Safe multisigs) — the wallet address is a\n * deployed contract that decides whether to accept a transaction. WalletConnect's\n * `eth_sendTransaction` returns a `safeTxHash` (an EIP-712 hash of the\n * *proposal*) rather than a real tx hash, and the proposal is held in Safe's\n * off-chain Transaction Service until quorum signs and executes it. We poll\n * that service for the proposal until execution, then wait for receipt on the\n * real Ethereum tx hash exposed in the service's response.\n *\n * The two are told apart by `eth_getCode`, but NOT by \"empty vs non-empty\":\n * an EIP-7702 delegated EOA reports `0xef0100 ‖ <delegate address>` and is\n * still an EOA — it signs and submits its own transactions, so\n * `eth_sendTransaction` returns a real tx hash. MetaMask upgrades accounts to\n * smart accounts this way by default, and treating one as a Safe means polling\n * the Transaction Service for a hash that is not a `safeTxHash`: a permanent\n * 404 that reads as \"proposal not yet indexed\" and hangs for the full poll\n * budget on a transaction that already succeeded. Delegation designators are\n * therefore classified as EOAs. As a backstop for any wallet that behaves this\n * way in future, a 404 from the Transaction Service is also checked against the\n * node: if it knows the hash as a real transaction, we were never waiting on a\n * proposal and switch to waiting for that transaction's receipt.\n *\n * @module utils/eth\n */\n\nimport type { Address, Hash, PublicClient, TransactionReceipt } from \"viem\";\n\n/**\n * Chains where the Safe Transaction Service is supported by this utility.\n * Extend the map as more Safe-enabled chains are needed.\n */\nconst SAFE_TX_SERVICE_BASE_URLS: Record<number, string> = {\n 1: \"https://safe-transaction-mainnet.safe.global\",\n 11155111: \"https://safe-transaction-sepolia.safe.global\",\n};\n\nconst DEFAULT_SAFE_POLL_INTERVAL_MS = 5_000;\nconst DEFAULT_SAFE_POLL_TIMEOUT_MS = 4 * 60 * 60 * 1_000;\nconst SAFE_TX_SERVICE_FETCH_TIMEOUT_MS = 10_000;\n\n/** Safe Transaction Service route for one multisig-transaction proposal. */\nconst SAFE_MULTISIG_TX_PATH = \"/api/v1/multisig-transactions\";\n/** The service answers 404 both for an unindexed proposal and an unknown Safe. */\nconst SAFE_TX_SERVICE_NOT_FOUND = 404;\n/** Statuses at or above this are server-side, so worth retrying. */\nconst SAFE_TX_SERVICE_SERVER_ERROR = 500;\n\n/** Two hex characters encode one byte in an `eth_getCode` result. */\nconst HEX_CHARS_PER_BYTE = 2;\n\n/**\n * EIP-7702 delegation designator: an EOA that has delegated its code to a\n * contract reports exactly `0xef0100 ‖ <20-byte delegate address>` from\n * `eth_getCode` (EIP-7702 §\"Delegation Designation\"). Both the prefix and the\n * exact length are checked so ordinary contract bytecode that merely happens to\n * start with these bytes is not mistaken for a delegation.\n */\nconst EIP_7702_DELEGATION_PREFIX = \"0xef0100\";\nconst EIP_7702_DELEGATION_ADDRESS_BYTES = 20;\nconst EIP_7702_DELEGATION_CODE_LENGTH =\n EIP_7702_DELEGATION_PREFIX.length +\n HEX_CHARS_PER_BYTE * EIP_7702_DELEGATION_ADDRESS_BYTES;\n\n/**\n * True when `eth_getCode` reports an EIP-7702 delegation designator rather than\n * a deployed contract. Such an account is still an EOA for our purposes: it\n * signs and submits its own transactions, so the hash we hold is a real tx hash.\n */\nfunction isEip7702DelegatedEoa(code: string): boolean {\n return (\n code.length === EIP_7702_DELEGATION_CODE_LENGTH &&\n code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)\n );\n}\n\nexport interface WaitForTransactionReceiptSmartAwareParams {\n publicClient: PublicClient;\n walletAddress: Address;\n hash: Hash;\n /**\n * Forwarded to viem verbatim.\n *\n * MUST NOT be used as a finality/reorg gate. viem fetches the receipt once\n * and then only compares block numbers against that cached copy — it never\n * re-checks that the receipt's block is still canonical, so it resolves\n * happily for a transaction that has been reorged out. Setting this buys a\n * delay, not a guarantee. For peg-in registration finality use\n * `waitForPeginRegistrationDepth`, which re-reads live contract state on\n * every poll.\n */\n confirmations?: number;\n /**\n * Forwarded to viem on the EOA (externally owned account) path, and on the\n * fallback where a supposed smart account turns out to submit its own\n * transactions — that is the EOA case too, however we arrived at it.\n *\n * Ignored only while waiting on a genuine Safe proposal, whose budget is\n * safePollTimeoutMs. It is not forwarded to the receipt wait that follows a\n * proposal's execution either: viem's own default applies there (180s as of\n * viem 2.38.2), so that wait is bounded too — a sufficiently slow node still\n * raises WaitForTransactionReceiptTimeoutError, just on viem's uniform bound\n * rather than on a caller's shorter one.\n */\n timeout?: number;\n /** Total budget for waiting on Safe quorum + execution. Default 4h. */\n safePollTimeoutMs?: number;\n /** Poll cadence against the Safe Transaction Service. Default 5s. */\n safePollIntervalMs?: number;\n}\n\nexport async function waitForTransactionReceiptSmartAware(\n params: WaitForTransactionReceiptSmartAwareParams,\n): Promise<TransactionReceipt> {\n const {\n publicClient,\n walletAddress,\n hash,\n confirmations,\n timeout,\n safePollTimeoutMs = DEFAULT_SAFE_POLL_TIMEOUT_MS,\n safePollIntervalMs = DEFAULT_SAFE_POLL_INTERVAL_MS,\n } = params;\n\n const code = await publicClient.getCode({ address: walletAddress });\n // An EIP-7702 delegated EOA has non-empty code but still submits its own\n // transactions, so it belongs on the EOA path — see the module docblock.\n const isSmartAccount =\n code !== undefined && code !== \"0x\" && !isEip7702DelegatedEoa(code);\n\n if (!isSmartAccount) {\n return publicClient.waitForTransactionReceipt({\n hash,\n confirmations,\n timeout,\n });\n }\n\n const chainId = await publicClient.getChainId();\n const outcome = await pollSafeTransactionServiceUntilExecuted({\n chainId,\n publicClient,\n safeTxHash: hash,\n pollIntervalMs: safePollIntervalMs,\n timeoutMs: safePollTimeoutMs,\n });\n\n // The wallet turned out to submit its own transactions, so this is the EOA\n // case after all — including the caller's `timeout`, which only ever meant to\n // be ignored while waiting on a genuine Safe proposal.\n if (outcome.kind === \"not-a-proposal\") {\n return publicClient.waitForTransactionReceipt({\n hash,\n confirmations,\n timeout,\n });\n }\n\n return publicClient.waitForTransactionReceipt({\n hash: outcome.transactionHash,\n confirmations,\n });\n}\n\n/**\n * How the Safe path ended. The two outcomes are not interchangeable, so they are\n * distinguished rather than both collapsing to a bare hash: `executed` is a real\n * Safe proposal that reached quorum, while `not-a-proposal` means the wallet was\n * never a Safe and we are really on the EOA path — which decides whether the\n * caller's `timeout` applies to the receipt wait that follows.\n */\ntype SafePollOutcome =\n | { kind: \"executed\"; transactionHash: Hash }\n | { kind: \"not-a-proposal\" };\n\ninterface SafeMultisigTransaction {\n isExecuted: boolean;\n isSuccessful: boolean | null;\n transactionHash: Hash | null;\n}\n\n/**\n * Decide whether a 404 from the Transaction Service means \"proposal not indexed\n * yet\" or \"this hash was never a proposal at all\".\n *\n * The Safe indexer cannot answer that: a genuine Safe and its freshly-submitted\n * proposal are both absent from it for a while, so its 404 proves nothing. The\n * NODE can. A `safeTxHash` is an EIP-712 digest of a proposal and is never a\n * transaction on chain, so if the node knows the hash as a real transaction then\n * this was never a proposal and we are on the wrong path entirely.\n *\n * Returns true only on that positive identification. Anything else — the node\n * has not seen it yet, or the lookup fails — is inconclusive and leaves the\n * caller polling, which is the correct behaviour for a Safe that is simply\n * still being indexed.\n */\nasync function hashIsRealTransaction(\n publicClient: PublicClient,\n hash: Hash,\n): Promise<boolean> {\n const transaction = await publicClient\n .getTransaction({ hash })\n .catch(() => null);\n return transaction !== null;\n}\n\nasync function pollSafeTransactionServiceUntilExecuted({\n chainId,\n publicClient,\n safeTxHash,\n pollIntervalMs,\n timeoutMs,\n}: {\n chainId: number;\n publicClient: PublicClient;\n safeTxHash: Hash;\n pollIntervalMs: number;\n timeoutMs: number;\n}): Promise<SafePollOutcome> {\n const baseUrl = SAFE_TX_SERVICE_BASE_URLS[chainId];\n if (!baseUrl) {\n throw new Error(\n `Safe Transaction Service not configured for chainId ${chainId}. ` +\n `Connected wallet appears to be a smart-contract account, but this ` +\n `chain is not in the supported list. Either connect an EOA or extend ` +\n `SAFE_TX_SERVICE_BASE_URLS in waitForTransactionReceiptSmartAware.ts.`,\n );\n }\n\n const url = `${baseUrl}${SAFE_MULTISIG_TX_PATH}/${safeTxHash}/`;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const controller = new AbortController();\n const fetchTimeoutId = setTimeout(\n () => controller.abort(),\n SAFE_TX_SERVICE_FETCH_TIMEOUT_MS,\n );\n\n let response: Response;\n try {\n response = await fetch(url, { signal: controller.signal });\n } catch (err) {\n // Transient failure (AbortError on per-request timeout, DNS hiccup,\n // connection reset, etc.). Log and continue to the next poll iteration\n // instead of consuming the entire safePollTimeoutMs budget on one blip.\n // The outer `while (Date.now() < deadline)` is what enforces the overall\n // budget; this catch deliberately preserves it.\n console.warn(\n `Safe Transaction Service request failed (will retry in ${pollIntervalMs}ms): ` +\n (err instanceof Error ? err.message : String(err)),\n );\n await sleep(pollIntervalMs);\n continue;\n } finally {\n clearTimeout(fetchTimeoutId);\n }\n\n if (response.ok) {\n const data = (await response.json()) as SafeMultisigTransaction;\n if (data.isExecuted) {\n if (data.isSuccessful === false) {\n throw new Error(\n `Safe transaction ${safeTxHash} was executed on chain but reverted. ` +\n `Check the Safe queue UI for details.`,\n );\n }\n if (data.transactionHash) {\n return { kind: \"executed\", transactionHash: data.transactionHash };\n }\n }\n } else if (response.status === SAFE_TX_SERVICE_NOT_FOUND) {\n // Usually \"proposal not indexed yet\", so keep polling. But the very same\n // 404 appears when the hash is not a safeTxHash at all — the case that\n // used to burn the whole budget on an already-mined transaction. Ask the\n // node: if it knows this hash, it is a real transaction, so stop treating\n // it as a proposal and let the caller wait on it directly.\n if (await hashIsRealTransaction(publicClient, safeTxHash)) {\n console.warn(\n `${safeTxHash} is a real transaction, not a Safe proposal — the ` +\n `connected wallet submits its own transactions despite reporting ` +\n `contract bytecode. Waiting for its receipt directly.`,\n );\n return { kind: \"not-a-proposal\" };\n }\n } else if (response.status >= SAFE_TX_SERVICE_SERVER_ERROR) {\n // Transient server error — same treatment as a hung connection: log and retry.\n console.warn(\n `Safe Transaction Service returned ${response.status} for ${safeTxHash}; retrying in ${pollIntervalMs}ms.`,\n );\n } else {\n // Other 4xx (403, 410, etc.) is likely permanent — surface immediately.\n throw new Error(\n `Safe Transaction Service returned ${response.status} for ${safeTxHash}.`,\n );\n }\n\n await sleep(pollIntervalMs);\n }\n\n throw new Error(\n `Timed out after ${timeoutMs}ms waiting for Safe transaction ${safeTxHash} ` +\n `to reach quorum and execute. The proposal is still pending in the Safe ` +\n `queue — co-signers must sign and execute it before the dApp can proceed.`,\n );\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"names":["SAFE_TX_SERVICE_BASE_URLS","DEFAULT_SAFE_POLL_INTERVAL_MS","DEFAULT_SAFE_POLL_TIMEOUT_MS","SAFE_TX_SERVICE_FETCH_TIMEOUT_MS","SAFE_MULTISIG_TX_PATH","SAFE_TX_SERVICE_NOT_FOUND","SAFE_TX_SERVICE_SERVER_ERROR","HEX_CHARS_PER_BYTE","EIP_7702_DELEGATION_PREFIX","EIP_7702_DELEGATION_ADDRESS_BYTES","EIP_7702_DELEGATION_CODE_LENGTH","isEip7702DelegatedEoa","code","waitForTransactionReceiptSmartAware","params","publicClient","walletAddress","hash","confirmations","timeout","safePollTimeoutMs","safePollIntervalMs","chainId","outcome","pollSafeTransactionServiceUntilExecuted","hashIsRealTransaction","safeTxHash","pollIntervalMs","timeoutMs","baseUrl","url","deadline","controller","fetchTimeoutId","response","err","sleep","data","ms","resolve"],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const f = {
|
|
2
|
+
1: "https://safe-transaction-mainnet.safe.global",
|
|
3
|
+
11155111: "https://safe-transaction-sepolia.safe.global"
|
|
4
|
+
}, w = 5e3, d = 14400 * 1e3, T = 1e4, h = "/api/v1/multisig-transactions", p = 404, A = 500, m = 2, _ = "0xef0100", R = 20, g = _.length + m * R;
|
|
5
|
+
function I(e) {
|
|
6
|
+
return e.length === g && e.toLowerCase().startsWith(_);
|
|
7
|
+
}
|
|
8
|
+
async function L(e) {
|
|
9
|
+
const {
|
|
10
|
+
publicClient: t,
|
|
11
|
+
walletAddress: a,
|
|
12
|
+
hash: r,
|
|
13
|
+
confirmations: i,
|
|
14
|
+
timeout: c,
|
|
15
|
+
safePollTimeoutMs: l = d,
|
|
16
|
+
safePollIntervalMs: u = w
|
|
17
|
+
} = e, s = await t.getCode({ address: a });
|
|
18
|
+
if (!(s !== void 0 && s !== "0x" && !I(s)))
|
|
19
|
+
return t.waitForTransactionReceipt({
|
|
20
|
+
hash: r,
|
|
21
|
+
confirmations: i,
|
|
22
|
+
timeout: c
|
|
23
|
+
});
|
|
24
|
+
const o = await t.getChainId(), n = await C({
|
|
25
|
+
chainId: o,
|
|
26
|
+
publicClient: t,
|
|
27
|
+
safeTxHash: r,
|
|
28
|
+
pollIntervalMs: u,
|
|
29
|
+
timeoutMs: l
|
|
30
|
+
});
|
|
31
|
+
return n.kind === "not-a-proposal" ? t.waitForTransactionReceipt({
|
|
32
|
+
hash: r,
|
|
33
|
+
confirmations: i,
|
|
34
|
+
timeout: c
|
|
35
|
+
}) : t.waitForTransactionReceipt({
|
|
36
|
+
hash: n.transactionHash,
|
|
37
|
+
confirmations: i
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async function F(e, t) {
|
|
41
|
+
return await e.getTransaction({ hash: t }).catch(() => null) !== null;
|
|
42
|
+
}
|
|
43
|
+
async function C({
|
|
44
|
+
chainId: e,
|
|
45
|
+
publicClient: t,
|
|
46
|
+
safeTxHash: a,
|
|
47
|
+
pollIntervalMs: r,
|
|
48
|
+
timeoutMs: i
|
|
49
|
+
}) {
|
|
50
|
+
const c = f[e];
|
|
51
|
+
if (!c)
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Safe Transaction Service not configured for chainId ${e}. Connected wallet appears to be a smart-contract account, but this chain is not in the supported list. Either connect an EOA or extend SAFE_TX_SERVICE_BASE_URLS in waitForTransactionReceiptSmartAware.ts.`
|
|
54
|
+
);
|
|
55
|
+
const l = `${c}${h}/${a}/`, u = Date.now() + i;
|
|
56
|
+
for (; Date.now() < u; ) {
|
|
57
|
+
const s = new AbortController(), E = setTimeout(
|
|
58
|
+
() => s.abort(),
|
|
59
|
+
T
|
|
60
|
+
);
|
|
61
|
+
let o;
|
|
62
|
+
try {
|
|
63
|
+
o = await fetch(l, { signal: s.signal });
|
|
64
|
+
} catch (n) {
|
|
65
|
+
console.warn(
|
|
66
|
+
`Safe Transaction Service request failed (will retry in ${r}ms): ` + (n instanceof Error ? n.message : String(n))
|
|
67
|
+
), await S(r);
|
|
68
|
+
continue;
|
|
69
|
+
} finally {
|
|
70
|
+
clearTimeout(E);
|
|
71
|
+
}
|
|
72
|
+
if (o.ok) {
|
|
73
|
+
const n = await o.json();
|
|
74
|
+
if (n.isExecuted) {
|
|
75
|
+
if (n.isSuccessful === !1)
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Safe transaction ${a} was executed on chain but reverted. Check the Safe queue UI for details.`
|
|
78
|
+
);
|
|
79
|
+
if (n.transactionHash)
|
|
80
|
+
return { kind: "executed", transactionHash: n.transactionHash };
|
|
81
|
+
}
|
|
82
|
+
} else if (o.status === p) {
|
|
83
|
+
if (await F(t, a))
|
|
84
|
+
return console.warn(
|
|
85
|
+
`${a} is a real transaction, not a Safe proposal — the connected wallet submits its own transactions despite reporting contract bytecode. Waiting for its receipt directly.`
|
|
86
|
+
), { kind: "not-a-proposal" };
|
|
87
|
+
} else if (o.status >= A)
|
|
88
|
+
console.warn(
|
|
89
|
+
`Safe Transaction Service returned ${o.status} for ${a}; retrying in ${r}ms.`
|
|
90
|
+
);
|
|
91
|
+
else
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Safe Transaction Service returned ${o.status} for ${a}.`
|
|
94
|
+
);
|
|
95
|
+
await S(r);
|
|
96
|
+
}
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Timed out after ${i}ms waiting for Safe transaction ${a} to reach quorum and execute. The proposal is still pending in the Safe queue — co-signers must sign and execute it before the dApp can proceed.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
function S(e) {
|
|
102
|
+
return new Promise((t) => {
|
|
103
|
+
setTimeout(t, e);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export {
|
|
107
|
+
L as waitForTransactionReceiptSmartAware
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/tbv/core/utils/eth/waitForTransactionReceiptSmartAware.ts"],"sourcesContent":["/**\n * Smart-account-aware wrapper around viem's `waitForTransactionReceipt`.\n *\n * Externally Owned Accounts (EOAs) — wallets controlled by a single private\n * key, e.g. MetaMask or a hardware wallet. `eth_sendTransaction` returns a real\n * Ethereum tx hash, which viem can poll directly. This wrapper delegates\n * unchanged for them.\n *\n * Smart-contract accounts (e.g. Safe multisigs) — the wallet address is a\n * deployed contract that decides whether to accept a transaction. WalletConnect's\n * `eth_sendTransaction` returns a `safeTxHash` (an EIP-712 hash of the\n * *proposal*) rather than a real tx hash, and the proposal is held in Safe's\n * off-chain Transaction Service until quorum signs and executes it. We poll\n * that service for the proposal until execution, then wait for receipt on the\n * real Ethereum tx hash exposed in the service's response.\n *\n * The two are told apart by `eth_getCode`, but NOT by \"empty vs non-empty\":\n * an EIP-7702 delegated EOA reports `0xef0100 ‖ <delegate address>` and is\n * still an EOA — it signs and submits its own transactions, so\n * `eth_sendTransaction` returns a real tx hash. MetaMask upgrades accounts to\n * smart accounts this way by default, and treating one as a Safe means polling\n * the Transaction Service for a hash that is not a `safeTxHash`: a permanent\n * 404 that reads as \"proposal not yet indexed\" and hangs for the full poll\n * budget on a transaction that already succeeded. Delegation designators are\n * therefore classified as EOAs. As a backstop for any wallet that behaves this\n * way in future, a 404 from the Transaction Service is also checked against the\n * node: if it knows the hash as a real transaction, we were never waiting on a\n * proposal and switch to waiting for that transaction's receipt.\n *\n * @module utils/eth\n */\n\nimport type { Address, Hash, PublicClient, TransactionReceipt } from \"viem\";\n\n/**\n * Chains where the Safe Transaction Service is supported by this utility.\n * Extend the map as more Safe-enabled chains are needed.\n */\nconst SAFE_TX_SERVICE_BASE_URLS: Record<number, string> = {\n 1: \"https://safe-transaction-mainnet.safe.global\",\n 11155111: \"https://safe-transaction-sepolia.safe.global\",\n};\n\nconst DEFAULT_SAFE_POLL_INTERVAL_MS = 5_000;\nconst DEFAULT_SAFE_POLL_TIMEOUT_MS = 4 * 60 * 60 * 1_000;\nconst SAFE_TX_SERVICE_FETCH_TIMEOUT_MS = 10_000;\n\n/** Safe Transaction Service route for one multisig-transaction proposal. */\nconst SAFE_MULTISIG_TX_PATH = \"/api/v1/multisig-transactions\";\n/** The service answers 404 both for an unindexed proposal and an unknown Safe. */\nconst SAFE_TX_SERVICE_NOT_FOUND = 404;\n/** Statuses at or above this are server-side, so worth retrying. */\nconst SAFE_TX_SERVICE_SERVER_ERROR = 500;\n\n/** Two hex characters encode one byte in an `eth_getCode` result. */\nconst HEX_CHARS_PER_BYTE = 2;\n\n/**\n * EIP-7702 delegation designator: an EOA that has delegated its code to a\n * contract reports exactly `0xef0100 ‖ <20-byte delegate address>` from\n * `eth_getCode` (EIP-7702 §\"Delegation Designation\"). Both the prefix and the\n * exact length are checked so ordinary contract bytecode that merely happens to\n * start with these bytes is not mistaken for a delegation.\n */\nconst EIP_7702_DELEGATION_PREFIX = \"0xef0100\";\nconst EIP_7702_DELEGATION_ADDRESS_BYTES = 20;\nconst EIP_7702_DELEGATION_CODE_LENGTH =\n EIP_7702_DELEGATION_PREFIX.length +\n HEX_CHARS_PER_BYTE * EIP_7702_DELEGATION_ADDRESS_BYTES;\n\n/**\n * True when `eth_getCode` reports an EIP-7702 delegation designator rather than\n * a deployed contract. Such an account is still an EOA for our purposes: it\n * signs and submits its own transactions, so the hash we hold is a real tx hash.\n */\nfunction isEip7702DelegatedEoa(code: string): boolean {\n return (\n code.length === EIP_7702_DELEGATION_CODE_LENGTH &&\n code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)\n );\n}\n\nexport interface WaitForTransactionReceiptSmartAwareParams {\n publicClient: PublicClient;\n walletAddress: Address;\n hash: Hash;\n /**\n * Forwarded to viem verbatim.\n *\n * MUST NOT be used as a finality/reorg gate. viem fetches the receipt once\n * and then only compares block numbers against that cached copy — it never\n * re-checks that the receipt's block is still canonical, so it resolves\n * happily for a transaction that has been reorged out. Setting this buys a\n * delay, not a guarantee. For peg-in registration finality use\n * `waitForPeginRegistrationDepth`, which re-reads live contract state on\n * every poll.\n */\n confirmations?: number;\n /**\n * Forwarded to viem on the EOA (externally owned account) path, and on the\n * fallback where a supposed smart account turns out to submit its own\n * transactions — that is the EOA case too, however we arrived at it.\n *\n * Ignored only while waiting on a genuine Safe proposal, whose budget is\n * safePollTimeoutMs. It is not forwarded to the receipt wait that follows a\n * proposal's execution either: viem's own default applies there (180s as of\n * viem 2.38.2), so that wait is bounded too — a sufficiently slow node still\n * raises WaitForTransactionReceiptTimeoutError, just on viem's uniform bound\n * rather than on a caller's shorter one.\n */\n timeout?: number;\n /** Total budget for waiting on Safe quorum + execution. Default 4h. */\n safePollTimeoutMs?: number;\n /** Poll cadence against the Safe Transaction Service. Default 5s. */\n safePollIntervalMs?: number;\n}\n\nexport async function waitForTransactionReceiptSmartAware(\n params: WaitForTransactionReceiptSmartAwareParams,\n): Promise<TransactionReceipt> {\n const {\n publicClient,\n walletAddress,\n hash,\n confirmations,\n timeout,\n safePollTimeoutMs = DEFAULT_SAFE_POLL_TIMEOUT_MS,\n safePollIntervalMs = DEFAULT_SAFE_POLL_INTERVAL_MS,\n } = params;\n\n const code = await publicClient.getCode({ address: walletAddress });\n // An EIP-7702 delegated EOA has non-empty code but still submits its own\n // transactions, so it belongs on the EOA path — see the module docblock.\n const isSmartAccount =\n code !== undefined && code !== \"0x\" && !isEip7702DelegatedEoa(code);\n\n if (!isSmartAccount) {\n return publicClient.waitForTransactionReceipt({\n hash,\n confirmations,\n timeout,\n });\n }\n\n const chainId = await publicClient.getChainId();\n const outcome = await pollSafeTransactionServiceUntilExecuted({\n chainId,\n publicClient,\n safeTxHash: hash,\n pollIntervalMs: safePollIntervalMs,\n timeoutMs: safePollTimeoutMs,\n });\n\n // The wallet turned out to submit its own transactions, so this is the EOA\n // case after all — including the caller's `timeout`, which only ever meant to\n // be ignored while waiting on a genuine Safe proposal.\n if (outcome.kind === \"not-a-proposal\") {\n return publicClient.waitForTransactionReceipt({\n hash,\n confirmations,\n timeout,\n });\n }\n\n return publicClient.waitForTransactionReceipt({\n hash: outcome.transactionHash,\n confirmations,\n });\n}\n\n/**\n * How the Safe path ended. The two outcomes are not interchangeable, so they are\n * distinguished rather than both collapsing to a bare hash: `executed` is a real\n * Safe proposal that reached quorum, while `not-a-proposal` means the wallet was\n * never a Safe and we are really on the EOA path — which decides whether the\n * caller's `timeout` applies to the receipt wait that follows.\n */\ntype SafePollOutcome =\n | { kind: \"executed\"; transactionHash: Hash }\n | { kind: \"not-a-proposal\" };\n\ninterface SafeMultisigTransaction {\n isExecuted: boolean;\n isSuccessful: boolean | null;\n transactionHash: Hash | null;\n}\n\n/**\n * Decide whether a 404 from the Transaction Service means \"proposal not indexed\n * yet\" or \"this hash was never a proposal at all\".\n *\n * The Safe indexer cannot answer that: a genuine Safe and its freshly-submitted\n * proposal are both absent from it for a while, so its 404 proves nothing. The\n * NODE can. A `safeTxHash` is an EIP-712 digest of a proposal and is never a\n * transaction on chain, so if the node knows the hash as a real transaction then\n * this was never a proposal and we are on the wrong path entirely.\n *\n * Returns true only on that positive identification. Anything else — the node\n * has not seen it yet, or the lookup fails — is inconclusive and leaves the\n * caller polling, which is the correct behaviour for a Safe that is simply\n * still being indexed.\n */\nasync function hashIsRealTransaction(\n publicClient: PublicClient,\n hash: Hash,\n): Promise<boolean> {\n const transaction = await publicClient\n .getTransaction({ hash })\n .catch(() => null);\n return transaction !== null;\n}\n\nasync function pollSafeTransactionServiceUntilExecuted({\n chainId,\n publicClient,\n safeTxHash,\n pollIntervalMs,\n timeoutMs,\n}: {\n chainId: number;\n publicClient: PublicClient;\n safeTxHash: Hash;\n pollIntervalMs: number;\n timeoutMs: number;\n}): Promise<SafePollOutcome> {\n const baseUrl = SAFE_TX_SERVICE_BASE_URLS[chainId];\n if (!baseUrl) {\n throw new Error(\n `Safe Transaction Service not configured for chainId ${chainId}. ` +\n `Connected wallet appears to be a smart-contract account, but this ` +\n `chain is not in the supported list. Either connect an EOA or extend ` +\n `SAFE_TX_SERVICE_BASE_URLS in waitForTransactionReceiptSmartAware.ts.`,\n );\n }\n\n const url = `${baseUrl}${SAFE_MULTISIG_TX_PATH}/${safeTxHash}/`;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const controller = new AbortController();\n const fetchTimeoutId = setTimeout(\n () => controller.abort(),\n SAFE_TX_SERVICE_FETCH_TIMEOUT_MS,\n );\n\n let response: Response;\n try {\n response = await fetch(url, { signal: controller.signal });\n } catch (err) {\n // Transient failure (AbortError on per-request timeout, DNS hiccup,\n // connection reset, etc.). Log and continue to the next poll iteration\n // instead of consuming the entire safePollTimeoutMs budget on one blip.\n // The outer `while (Date.now() < deadline)` is what enforces the overall\n // budget; this catch deliberately preserves it.\n console.warn(\n `Safe Transaction Service request failed (will retry in ${pollIntervalMs}ms): ` +\n (err instanceof Error ? err.message : String(err)),\n );\n await sleep(pollIntervalMs);\n continue;\n } finally {\n clearTimeout(fetchTimeoutId);\n }\n\n if (response.ok) {\n const data = (await response.json()) as SafeMultisigTransaction;\n if (data.isExecuted) {\n if (data.isSuccessful === false) {\n throw new Error(\n `Safe transaction ${safeTxHash} was executed on chain but reverted. ` +\n `Check the Safe queue UI for details.`,\n );\n }\n if (data.transactionHash) {\n return { kind: \"executed\", transactionHash: data.transactionHash };\n }\n }\n } else if (response.status === SAFE_TX_SERVICE_NOT_FOUND) {\n // Usually \"proposal not indexed yet\", so keep polling. But the very same\n // 404 appears when the hash is not a safeTxHash at all — the case that\n // used to burn the whole budget on an already-mined transaction. Ask the\n // node: if it knows this hash, it is a real transaction, so stop treating\n // it as a proposal and let the caller wait on it directly.\n if (await hashIsRealTransaction(publicClient, safeTxHash)) {\n console.warn(\n `${safeTxHash} is a real transaction, not a Safe proposal — the ` +\n `connected wallet submits its own transactions despite reporting ` +\n `contract bytecode. Waiting for its receipt directly.`,\n );\n return { kind: \"not-a-proposal\" };\n }\n } else if (response.status >= SAFE_TX_SERVICE_SERVER_ERROR) {\n // Transient server error — same treatment as a hung connection: log and retry.\n console.warn(\n `Safe Transaction Service returned ${response.status} for ${safeTxHash}; retrying in ${pollIntervalMs}ms.`,\n );\n } else {\n // Other 4xx (403, 410, etc.) is likely permanent — surface immediately.\n throw new Error(\n `Safe Transaction Service returned ${response.status} for ${safeTxHash}.`,\n );\n }\n\n await sleep(pollIntervalMs);\n }\n\n throw new Error(\n `Timed out after ${timeoutMs}ms waiting for Safe transaction ${safeTxHash} ` +\n `to reach quorum and execute. The proposal is still pending in the Safe ` +\n `queue — co-signers must sign and execute it before the dApp can proceed.`,\n );\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"names":["SAFE_TX_SERVICE_BASE_URLS","DEFAULT_SAFE_POLL_INTERVAL_MS","DEFAULT_SAFE_POLL_TIMEOUT_MS","SAFE_TX_SERVICE_FETCH_TIMEOUT_MS","SAFE_MULTISIG_TX_PATH","SAFE_TX_SERVICE_NOT_FOUND","SAFE_TX_SERVICE_SERVER_ERROR","HEX_CHARS_PER_BYTE","EIP_7702_DELEGATION_PREFIX","EIP_7702_DELEGATION_ADDRESS_BYTES","EIP_7702_DELEGATION_CODE_LENGTH","isEip7702DelegatedEoa","code","waitForTransactionReceiptSmartAware","params","publicClient","walletAddress","hash","confirmations","timeout","safePollTimeoutMs","safePollIntervalMs","chainId","outcome","pollSafeTransactionServiceUntilExecuted","hashIsRealTransaction","safeTxHash","pollIntervalMs","timeoutMs","baseUrl","url","deadline","controller","fetchTimeoutId","response","err","sleep","data","ms","resolve"],"mappings":"AAsCA,MAAMA,IAAoD;AAAA,EACxD,GAAG;AAAA,EACH,UAAU;AACZ,GAEMC,IAAgC,KAChCC,IAA+B,QAAc,KAC7CC,IAAmC,KAGnCC,IAAwB,iCAExBC,IAA4B,KAE5BC,IAA+B,KAG/BC,IAAqB,GASrBC,IAA6B,YAC7BC,IAAoC,IACpCC,IACJF,EAA2B,SAC3BD,IAAqBE;AAOvB,SAASE,EAAsBC,GAAuB;AACpD,SACEA,EAAK,WAAWF,KAChBE,EAAK,YAAA,EAAc,WAAWJ,CAA0B;AAE5D;AAqCA,eAAsBK,EACpBC,GAC6B;AAC7B,QAAM;AAAA,IACJ,cAAAC;AAAA,IACA,eAAAC;AAAA,IACA,MAAAC;AAAA,IACA,eAAAC;AAAA,IACA,SAAAC;AAAA,IACA,mBAAAC,IAAoBlB;AAAA,IACpB,oBAAAmB,IAAqBpB;AAAA,EAAA,IACnBa,GAEEF,IAAO,MAAMG,EAAa,QAAQ,EAAE,SAASC,GAAe;AAMlE,MAAI,EAFFJ,MAAS,UAAaA,MAAS,QAAQ,CAACD,EAAsBC,CAAI;AAGlE,WAAOG,EAAa,0BAA0B;AAAA,MAC5C,MAAAE;AAAA,MACA,eAAAC;AAAA,MACA,SAAAC;AAAA,IAAA,CACD;AAGH,QAAMG,IAAU,MAAMP,EAAa,WAAA,GAC7BQ,IAAU,MAAMC,EAAwC;AAAA,IAC5D,SAAAF;AAAA,IACA,cAAAP;AAAA,IACA,YAAYE;AAAA,IACZ,gBAAgBI;AAAA,IAChB,WAAWD;AAAA,EAAA,CACZ;AAKD,SAAIG,EAAQ,SAAS,mBACZR,EAAa,0BAA0B;AAAA,IAC5C,MAAAE;AAAA,IACA,eAAAC;AAAA,IACA,SAAAC;AAAA,EAAA,CACD,IAGIJ,EAAa,0BAA0B;AAAA,IAC5C,MAAMQ,EAAQ;AAAA,IACd,eAAAL;AAAA,EAAA,CACD;AACH;AAkCA,eAAeO,EACbV,GACAE,GACkB;AAIlB,SAHoB,MAAMF,EACvB,eAAe,EAAE,MAAAE,GAAM,EACvB,MAAM,MAAM,IAAI,MACI;AACzB;AAEA,eAAeO,EAAwC;AAAA,EACrD,SAAAF;AAAA,EACA,cAAAP;AAAA,EACA,YAAAW;AAAA,EACA,gBAAAC;AAAA,EACA,WAAAC;AACF,GAM6B;AAC3B,QAAMC,IAAU7B,EAA0BsB,CAAO;AACjD,MAAI,CAACO;AACH,UAAM,IAAI;AAAA,MACR,uDAAuDP,CAAO;AAAA,IAAA;AAOlE,QAAMQ,IAAM,GAAGD,CAAO,GAAGzB,CAAqB,IAAIsB,CAAU,KACtDK,IAAW,KAAK,IAAA,IAAQH;AAE9B,SAAO,KAAK,IAAA,IAAQG,KAAU;AAC5B,UAAMC,IAAa,IAAI,gBAAA,GACjBC,IAAiB;AAAA,MACrB,MAAMD,EAAW,MAAA;AAAA,MACjB7B;AAAA,IAAA;AAGF,QAAI+B;AACJ,QAAI;AACF,MAAAA,IAAW,MAAM,MAAMJ,GAAK,EAAE,QAAQE,EAAW,QAAQ;AAAA,IAC3D,SAASG,GAAK;AAMZ,cAAQ;AAAA,QACN,0DAA0DR,CAAc,WACrEQ,aAAe,QAAQA,EAAI,UAAU,OAAOA,CAAG;AAAA,MAAA,GAEpD,MAAMC,EAAMT,CAAc;AAC1B;AAAA,IACF,UAAA;AACE,mBAAaM,CAAc;AAAA,IAC7B;AAEA,QAAIC,EAAS,IAAI;AACf,YAAMG,IAAQ,MAAMH,EAAS,KAAA;AAC7B,UAAIG,EAAK,YAAY;AACnB,YAAIA,EAAK,iBAAiB;AACxB,gBAAM,IAAI;AAAA,YACR,oBAAoBX,CAAU;AAAA,UAAA;AAIlC,YAAIW,EAAK;AACP,iBAAO,EAAE,MAAM,YAAY,iBAAiBA,EAAK,gBAAA;AAAA,MAErD;AAAA,IACF,WAAWH,EAAS,WAAW7B;AAM7B,UAAI,MAAMoB,EAAsBV,GAAcW,CAAU;AACtD,uBAAQ;AAAA,UACN,GAAGA,CAAU;AAAA,QAAA,GAIR,EAAE,MAAM,iBAAA;AAAA,eAERQ,EAAS,UAAU5B;AAE5B,cAAQ;AAAA,QACN,qCAAqC4B,EAAS,MAAM,QAAQR,CAAU,iBAAiBC,CAAc;AAAA,MAAA;AAAA;AAIvG,YAAM,IAAI;AAAA,QACR,qCAAqCO,EAAS,MAAM,QAAQR,CAAU;AAAA,MAAA;AAI1E,UAAMU,EAAMT,CAAc;AAAA,EAC5B;AAEA,QAAM,IAAI;AAAA,IACR,mBAAmBC,CAAS,mCAAmCF,CAAU;AAAA,EAAA;AAI7E;AAEA,SAASU,EAAME,GAA2B;AACxC,SAAO,IAAI,QAAQ,CAACC,MAAY;AAC9B,eAAWA,GAASD,CAAE;AAAA,EACxB,CAAC;AACH;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("../../../abortSignals-msbmbqFe.cjs"),a=require("../../../signing-BJ3X66b-.cjs"),_=require("../../../validation-C6XTfZak.cjs"),n=require("./eth/index.cjs"),e=require("../../../psbtInputFields-BIxBpPj2.cjs"),t=require("../../../fundPeginTransaction-BLD8FRL9.cjs"),E=require("../../../reservation-Dr2HLCxx.cjs"),T=require("../../../bitcoin-D-O2GjbC.cjs");exports.combineAbortSignals=i.combineAbortSignals;exports.calculateBtcTxHash=a.calculateBtcTxHash;exports.createTaprootScriptPathSignOptions=a.createTaprootScriptPathSignOptions;exports.BITCOIN_ADDRESS_RE=_.BITCOIN_ADDRESS_RE;exports.COMPRESSED_PUBKEY_HEX_LEN=_.COMPRESSED_PUBKEY_HEX_LEN;exports.HEX_RE=_.HEX_RE;exports.KNOWN_SCRIPT_PREFIXES=_.KNOWN_SCRIPT_PREFIXES;exports.MAX_REASONABLE_FEE_SATS=_.MAX_REASONABLE_FEE_SATS;exports.TXID_RE=_.TXID_RE;exports.X_ONLY_PUBKEY_HEX_LEN=_.X_ONLY_PUBKEY_HEX_LEN;exports.waitForTransactionReceiptSmartAware=n.waitForTransactionReceiptSmartAware;exports.BitcoinScriptType=e.BitcoinScriptType;exports.applyChangeOutputPolicy=e.applyChangeOutputPolicy;exports.computeChangeOutputFeeSats=e.computeChangeOutputFeeSats;exports.computeMaxDeposit=e.computeMaxDeposit;exports.computePeginBaseFeeSats=e.computePeginBaseFeeSats;exports.getDustThreshold=e.getDustThreshold;exports.getPsbtInputFields=e.getPsbtInputFields;exports.getScriptType=e.getScriptType;exports.selectUtxosForPegin=e.selectUtxosForPegin;exports.shouldAddChangeOutput=e.shouldAddChangeOutput;exports.BTC_DUST_SAT=t.BTC_DUST_SAT;exports.DUST_THRESHOLD=t.DUST_THRESHOLD;exports.LOW_RATE_ESTIMATION_ACCURACY_BUFFER=t.LOW_RATE_ESTIMATION_ACCURACY_BUFFER;exports.MAX_NON_LEGACY_OUTPUT_SIZE=t.MAX_NON_LEGACY_OUTPUT_SIZE;exports.MAX_REASONABLE_PEGIN_VBYTES=t.MAX_REASONABLE_PEGIN_VBYTES;exports.P2TR_INPUT_SIZE=t.P2TR_INPUT_SIZE;exports.PEGIN_AUTH_ANCHOR_OUTPUTS=t.PEGIN_AUTH_ANCHOR_OUTPUTS;exports.PEGIN_FIXED_OUTPUTS=t.PEGIN_FIXED_OUTPUTS;exports.SPLIT_TX_FEE_SAFETY_MULTIPLIER=t.SPLIT_TX_FEE_SAFETY_MULTIPLIER;exports.TX_BUFFER_SIZE_OVERHEAD=t.TX_BUFFER_SIZE_OVERHEAD;exports.WALLET_RELAY_FEE_RATE_THRESHOLD=t.WALLET_RELAY_FEE_RATE_THRESHOLD;exports.fundPeginTransaction=t.fundPeginTransaction;exports.parseUnfundedWasmTransaction=t.parseUnfundedWasmTransaction;exports.peginOutputCount=t.peginOutputCount;exports.rateBasedTxBufferFee=t.rateBasedTxBufferFee;exports.UtxoNotAvailableError=E.UtxoNotAvailableError;exports.assertUtxosAvailable=E.assertUtxosAvailable;exports.extractInputsFromTransaction=E.extractInputsFromTransaction;exports.findOverlappingPendingVaults=E.findOverlappingPendingVaults;exports.validateUtxosAvailable=E.validateUtxosAvailable;exports.getNetwork=T.getNetwork;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|