@gvnrdao/dh-sdk 0.0.274 → 0.0.276

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.
@@ -34,6 +34,8 @@ export interface ContractAddresses {
34
34
  feeRecipientRegistry?: string;
35
35
  /** PositionDelegateRegistry proxy; consumed by LIT Action authorization verifier as the third recovery arm for Safe-as-borrower flows. */
36
36
  positionDelegateRegistry?: string;
37
+ /** BitcoinWithdrawalAddressRegistry proxy; per-wallet allowlist that gates borrower-initiated BTC withdrawal destinations (24h time-lock). */
38
+ bitcoinWithdrawalAddressRegistry?: string;
37
39
  mockUsdcToken?: string;
38
40
  mockUsdcOwner?: string;
39
41
  mockUsdtToken?: string;
@@ -10,7 +10,7 @@
10
10
  * This module centralizes all contract interaction setup and provides
11
11
  * a clean interface for other modules to access contracts.
12
12
  */
13
- import { type Provider, type Signer } from "ethers";
13
+ import { Contract, type Provider, type Signer } from "ethers";
14
14
  import type { ContractAddresses } from "../../interfaces/chunks/config.i";
15
15
  import { type DeploymentContracts } from "../../constants/chunks/deployment-addresses";
16
16
  import { Result } from "../../types/result";
@@ -56,6 +56,8 @@ export interface ManagedContracts {
56
56
  termManager: ITermManager;
57
57
  circuitBreaker: CircuitBreakerModule;
58
58
  liquidationManager: ILiquidationManager;
59
+ /** Per-wallet approved-withdrawal-address allowlist. Untyped ethers Contract — methods accessed via WithdrawalAddressModule. */
60
+ bitcoinWithdrawalAddressRegistry: Contract;
59
61
  }
60
62
  /**
61
63
  * Contract Manager Module
@@ -108,6 +110,10 @@ export declare class ContractManager {
108
110
  * Get Liquidation Manager contract
109
111
  */
110
112
  getLiquidationManager(): Result<ILiquidationManager, SDKError>;
113
+ /**
114
+ * Get the BitcoinWithdrawalAddressRegistry contract (per-wallet approved-address allowlist).
115
+ */
116
+ getBitcoinWithdrawalAddressRegistry(): Result<Contract, SDKError>;
111
117
  /**
112
118
  * Get the provider instance
113
119
  */
@@ -11,6 +11,7 @@
11
11
  * - Dependency injection pattern
12
12
  * - Result-based error handling
13
13
  */
14
+ import { type Signer, type TransactionResponse } from "ethers";
14
15
  import { Result } from "../types/result";
15
16
  import { Satoshis } from "../types/branded/domain-values";
16
17
  import { SDKError } from "../utils/error-handler";
@@ -18,6 +19,7 @@ import type { CreateLoanRequest, CreateLoanResult, LoanDataDetail, UCDMintReques
18
19
  import type { DiamondHandsSDKConfig } from "../interfaces/chunks/config.i";
19
20
  import type { PKPData } from "../interfaces/chunks/pkp-integration.i";
20
21
  import { ContractManager } from "./contract/contract-manager.module";
22
+ import { WithdrawalAddressModule } from "./withdrawal-address/withdrawal-address.module";
21
23
  import { BitcoinOperations } from "./bitcoin/bitcoin-operations.module";
22
24
  import type { SupportedStablecoinData } from "../graphs/diamond-hands";
23
25
  type PositionDetailsView = {
@@ -69,6 +71,7 @@ export declare class DiamondHandsSDK {
69
71
  private readonly loanCreator;
70
72
  private readonly loanQuery;
71
73
  private readonly bitcoinOperations;
74
+ private readonly withdrawalAddressModule;
72
75
  private readonly mockTokenManager?;
73
76
  private readonly graphClient;
74
77
  /**
@@ -370,6 +373,25 @@ export declare class DiamondHandsSDK {
370
373
  * @returns Payment result with transaction details
371
374
  */
372
375
  makePayment(request: PartialPaymentRequest): Promise<PartialPaymentResult>;
376
+ /**
377
+ * Access the approved-withdrawal-address allowlist module (self-service
378
+ * add/remove + reads). The connected wallet manages its OWN addresses; a
379
+ * newly-added address is only usable after the registry's time-lock delay.
380
+ */
381
+ get withdrawalAddresses(): WithdrawalAddressModule;
382
+ /**
383
+ * Add a Bitcoin address to the connected wallet's approved-withdrawal allowlist.
384
+ * Usable only after the registry's delay (default 24h) elapses.
385
+ */
386
+ addApprovedWithdrawalAddress(btcAddress: string): Promise<Result<TransactionResponse, SDKError>>;
387
+ /** Remove a Bitcoin address from the connected wallet's allowlist (immediate). */
388
+ removeApprovedWithdrawalAddress(btcAddress: string): Promise<Result<TransactionResponse, SDKError>>;
389
+ /**
390
+ * Read the connected wallet's (or `user`'s) approved-address entries from the
391
+ * contract (hashes + timestamps + derived approval state). For human-readable
392
+ * address strings, query the subgraph `WithdrawalAddressBook`.
393
+ */
394
+ getApprovedWithdrawalAddresses(user?: string): Promise<Result<import("./withdrawal-address/withdrawal-address.module").WithdrawalAddressEntry[], SDKError>>;
373
395
  /**
374
396
  * Withdraw Bitcoin from a position
375
397
  *
@@ -650,6 +672,43 @@ export declare class DiamondHandsSDK {
650
672
  * @param stablecoinAddress - EVM address of the stablecoin to query.
651
673
  */
652
674
  getPSMAvailableReserves(stablecoinAddress: string): Promise<bigint>;
675
+ /**
676
+ * Execute a PSM stablecoin → UCD swap.
677
+ * Handles stablecoin approval to the PSM contract if the current allowance is insufficient.
678
+ *
679
+ * @param params.stablecoinAddress - ERC-20 address of the stablecoin to swap in
680
+ * @param params.amountWei - Stablecoin amount in native decimals (bigint)
681
+ * @param params.minUcdOutWei - Minimum UCD to receive; reverts if below this (1% slippage guard)
682
+ * @param params.signer - Connected signer for the approval and swap transactions
683
+ */
684
+ psmSwap(params: {
685
+ stablecoinAddress: string;
686
+ amountWei: bigint;
687
+ minUcdOutWei: bigint;
688
+ signer: Signer;
689
+ }): Promise<{
690
+ hash: string;
691
+ blockNumber: number;
692
+ }>;
693
+ /**
694
+ * Execute a PSM UCD → stablecoin redeem.
695
+ * Handles UCD approval to UCDController (not PSM) to satisfy the M-4 burn allowance guard:
696
+ * UCDToken.burn(from, amount) calls _spendAllowance(from, msg.sender=ucdController, amount).
697
+ *
698
+ * @param params.stablecoinAddress - ERC-20 address of the stablecoin to receive
699
+ * @param params.ucdAmountWei - UCD amount to redeem (18 decimals, bigint)
700
+ * @param params.minStablecoinOutWei - Minimum stablecoin to receive (slippage guard)
701
+ * @param params.signer - Connected signer
702
+ */
703
+ psmRedeem(params: {
704
+ stablecoinAddress: string;
705
+ ucdAmountWei: bigint;
706
+ minStablecoinOutWei: bigint;
707
+ signer: Signer;
708
+ }): Promise<{
709
+ hash: string;
710
+ blockNumber: number;
711
+ }>;
653
712
  /**
654
713
  * Wait for the subgraph to index up to (and including) the given block number.
655
714
  * Call after on-chain actions (createLoan, mintUCD, etc.) before querying the subgraph.
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Withdrawal Address Module
3
+ *
4
+ * Self-service management of a connected wallet's approved Bitcoin withdrawal
5
+ * destinations (BitcoinWithdrawalAddressRegistry). A user adds an address —
6
+ * usable only after the registry's time-lock delay (default 24h) — and may
7
+ * remove it immediately. Withdrawals to non-approved (or still-pending)
8
+ * addresses are rejected on-chain; this module also powers the SDK's
9
+ * early-reject so a doomed withdrawal never reaches the Lit Action.
10
+ *
11
+ * Display lists (with the original address strings) come from the subgraph —
12
+ * the contract stores only keccak256(address). This module exposes the
13
+ * authoritative contract reads (isApproved / hashes / timestamps) and the
14
+ * mutating txs.
15
+ */
16
+ import { type TransactionResponse } from "ethers";
17
+ import type { ContractManager } from "../contract/contract-manager.module";
18
+ import { Result } from "../../types/result";
19
+ import { SDKError } from "../../utils/error-handler";
20
+ export interface WithdrawalAddressModuleConfig {
21
+ contractManager: ContractManager;
22
+ debug?: boolean;
23
+ }
24
+ /** A single approved-address entry as read from the contract (no raw string — see subgraph for that). */
25
+ export interface WithdrawalAddressEntry {
26
+ /** keccak256(bytes(normalizedAddress)). */
27
+ addrHash: string;
28
+ /** Unix seconds when the address was added (0 if absent). */
29
+ addedAt: number;
30
+ /** Unix seconds when the address becomes usable (addedAt-at-add-time + delay). */
31
+ usableAt: number;
32
+ /**
33
+ * Authoritative approval from the contract's own `isApprovedByHash` (chain
34
+ * `block.timestamp` + CURRENT delay) — NOT derived from the client clock or
35
+ * the cached `usableAt`, so it stays correct even if the admin changes the
36
+ * delay after this entry was added.
37
+ */
38
+ approved: boolean;
39
+ }
40
+ export declare class WithdrawalAddressModule {
41
+ private readonly config;
42
+ constructor(config: WithdrawalAddressModuleConfig);
43
+ /** Resolve the registry contract, or fail if it isn't configured for this network. */
44
+ private getRegistry;
45
+ /** True iff the registry is wired for this network (enforcement is active). */
46
+ isConfigured(): boolean;
47
+ /** keccak256 of the canonicalized address — matches the on-chain key. */
48
+ static addressHash(btcAddress: string): string;
49
+ /**
50
+ * Add a Bitcoin address to the caller's allowlist. It becomes usable only
51
+ * after the registry's delay elapses. Returns the submitted tx.
52
+ */
53
+ addAddress(btcAddress: string): Promise<Result<TransactionResponse, SDKError>>;
54
+ /** Remove a Bitcoin address from the caller's allowlist (effective immediately). */
55
+ removeAddress(btcAddress: string): Promise<Result<TransactionResponse, SDKError>>;
56
+ /**
57
+ * Authoritative contract read: is `btcAddress` approved (present AND past its
58
+ * delay) for `user`?
59
+ */
60
+ isApproved(user: string, btcAddress: string): Promise<Result<boolean, SDKError>>;
61
+ /**
62
+ * Read the user's allowlist from the contract: hashes + timestamps + derived
63
+ * approval state. NOTE: the raw address strings are NOT on-chain — use the
64
+ * subgraph (WithdrawalAddressBook) to render human-readable addresses.
65
+ */
66
+ getEntries(user: string): Promise<Result<WithdrawalAddressEntry[], SDKError>>;
67
+ /** The current global delay (seconds) before a newly-added address is usable. */
68
+ getAddressDelay(): Promise<Result<number, SDKError>>;
69
+ /**
70
+ * Early-reject guard used by `withdrawBTC`. Resolves to a typed error if the
71
+ * destination is not approved for `borrower`. When the registry is not
72
+ * configured for the network, this is a no-op (the on-chain gate remains the
73
+ * hard guarantee).
74
+ */
75
+ assertApprovedForWithdrawal(borrower: string, btcAddress: string): Promise<Result<void, SDKError>>;
76
+ private txFailure;
77
+ }
78
+ export declare function createWithdrawalAddressModule(config: WithdrawalAddressModuleConfig): WithdrawalAddressModule;
@@ -30,6 +30,18 @@ export declare function safeGetBitcoinAddressesFromPkp(pkpId: string, maxRetries
30
30
  * @throws Clear error message if validation fails
31
31
  */
32
32
  export declare function safeValidateBitcoinAddress(address: string, network?: 'mainnet' | 'testnet' | 'regtest'): string;
33
+ /**
34
+ * Canonicalize a Bitcoin address so that the SAME string is used on both the
35
+ * approve path (registry.addAddress) and the withdraw path. The on-chain
36
+ * allowlist is keyed by keccak256(bytes(address)), so the two strings MUST
37
+ * byte-match. Bech32 (bc1/tb1/bcrt1) is lower-case canonical, so we lower-case
38
+ * it; Base58 (1.../3.../m.../n.../2...) is case-sensitive and is returned
39
+ * unchanged.
40
+ *
41
+ * @param address Bitcoin address to canonicalize
42
+ * @returns The canonical form to store/compare
43
+ */
44
+ export declare function normalizeBitcoinAddress(address: string): string;
33
45
  /**
34
46
  * Safely parse and validate a position ID
35
47
  * @param positionId Position ID to validate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gvnrdao/dh-sdk",
3
- "version": "0.0.274",
3
+ "version": "0.0.276",
4
4
  "description": "TypeScript SDK for Diamond Hands Protocol - Bitcoin-backed lending with LIT Protocol PKPs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -81,10 +81,10 @@
81
81
  },
82
82
  "sideEffects": false,
83
83
  "dependencies": {
84
- "@gvnrdao/dh-lit-actions": "^0.0.306",
85
- "@gvnrdao/dh-lit-ops": "^0.0.293",
84
+ "@gvnrdao/dh-lit-actions": "^0.0.307",
85
+ "@gvnrdao/dh-lit-ops": "^0.0.294",
86
86
  "@noble/hashes": "^1.5.0",
87
- "axios": "^1.15.2",
87
+ "axios": "^1.17.0",
88
88
  "bech32": "^2.0.0",
89
89
  "bip66": "^2.0.0",
90
90
  "bitcoinjs-lib": "^6.1.0",
@@ -98,7 +98,7 @@
98
98
  "viem": "^2.48.4"
99
99
  },
100
100
  "devDependencies": {
101
- "@babel/preset-env": "7.29.0",
101
+ "@babel/preset-env": "7.29.7",
102
102
  "@safe-global/protocol-kit": "^7.1.0",
103
103
  "@types/crypto-js": "^4.2.2",
104
104
  "@types/jest": "^29.0.0",