signet.js 0.0.1-beta.7 → 0.0.1-beta.9
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/browser/index.browser.cjs +12 -0
- package/browser/index.browser.cjs.map +1 -0
- package/browser/index.browser.js +3927 -0
- package/browser/index.browser.js.map +1 -0
- package/node/index.node.cjs +19 -0
- package/node/index.node.cjs.map +1 -0
- package/node/index.node.js +4099 -0
- package/node/index.node.js.map +1 -0
- package/package.json +18 -12
- package/types/chains/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.d.ts +10 -0
- package/types/chains/Bitcoin/BTCRpcAdapter/Mempool/Mempool.d.ts +15 -0
- package/types/chains/Bitcoin/BTCRpcAdapter/Mempool/index.d.ts +1 -0
- package/types/chains/Bitcoin/BTCRpcAdapter/Mempool/types.d.ts +69 -0
- package/types/chains/Bitcoin/BTCRpcAdapter/index.d.ts +5 -0
- package/types/chains/Bitcoin/Bitcoin.d.ts +42 -0
- package/types/chains/Bitcoin/types.d.ts +42 -0
- package/types/chains/Bitcoin/utils.d.ts +2 -0
- package/types/chains/Chain.d.ts +21 -0
- package/types/chains/ChainSignatureContract.d.ts +18 -0
- package/types/chains/Cosmos/Cosmos.d.ts +38 -0
- package/types/chains/Cosmos/types.d.ts +30 -0
- package/types/chains/Cosmos/utils.d.ts +2 -0
- package/types/chains/EVM/EVM.d.ts +32 -0
- package/types/chains/EVM/types.d.ts +5 -0
- package/types/chains/EVM/utils.d.ts +7 -0
- package/types/chains/index.d.ts +11 -0
- package/types/chains/types.d.ts +18 -0
- package/types/index.d.ts +2 -0
- package/types/utils/chains/index.d.ts +1 -0
- package/types/utils/chains/near/ChainSignatureContract.d.ts +35 -0
- package/types/utils/chains/near/account.d.ts +13 -0
- package/types/utils/chains/near/constants.d.ts +3 -0
- package/types/utils/chains/near/index.d.ts +3 -0
- package/types/utils/chains/near/relayer/index.d.ts +1 -0
- package/types/utils/chains/near/relayer/relayer.d.ts +3 -0
- package/types/utils/chains/near/relayer/types.d.ts +22 -0
- package/types/utils/chains/near/signAndSend/index.d.ts +1 -0
- package/types/utils/chains/near/signAndSend/keypair.d.ts +5 -0
- package/types/utils/chains/near/transactionBuilder.d.ts +26 -0
- package/types/utils/chains/near/types.d.ts +54 -0
- package/types/utils/cryptography.d.ts +3 -0
- package/types/utils/index.d.ts +2 -0
- package/.eslintrc.json +0 -55
- package/.prettierrc +0 -1
- package/babel.config.js +0 -6
- package/docs/pages/chain-signatures-contract.mdx +0 -56
- package/docs/pages/chain.mdx +0 -45
- package/docs/pages/chains/bitcoin/bitcoin.mdx +0 -191
- package/docs/pages/chains/bitcoin/btc-rpc-adapter.mdx +0 -307
- package/docs/pages/chains/cosmos.mdx +0 -181
- package/docs/pages/chains/evm.mdx +0 -189
- package/docs/pages/index.mdx +0 -99
- package/docs/snippets/contract.ts +0 -21
- package/docs/snippets/env.ts +0 -13
- package/jest.config.ts +0 -199
- package/src/chains/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.ts +0 -11
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/Mempool.ts +0 -96
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/index.ts +0 -1
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/types.ts +0 -72
- package/src/chains/Bitcoin/BTCRpcAdapter/index.ts +0 -6
- package/src/chains/Bitcoin/Bitcoin.ts +0 -301
- package/src/chains/Bitcoin/types.ts +0 -45
- package/src/chains/Bitcoin/utils.ts +0 -14
- package/src/chains/Chain.ts +0 -96
- package/src/chains/ChainSignatureContract.ts +0 -48
- package/src/chains/Cosmos/Cosmos.ts +0 -279
- package/src/chains/Cosmos/types.ts +0 -35
- package/src/chains/Cosmos/utils.ts +0 -45
- package/src/chains/EVM/EVM.ts +0 -180
- package/src/chains/EVM/types.ts +0 -7
- package/src/chains/EVM/utils.ts +0 -26
- package/src/chains/index.ts +0 -34
- package/src/chains/types.ts +0 -35
- package/src/chains/utils.ts +0 -40
- package/src/index.ts +0 -2
- package/src/utils/chains/index.ts +0 -1
- package/src/utils/chains/near/ChainSignatureContract.ts +0 -195
- package/src/utils/chains/near/account.ts +0 -42
- package/src/utils/chains/near/constants.ts +0 -4
- package/src/utils/chains/near/index.ts +0 -3
- package/src/utils/chains/near/relayer/index.ts +0 -1
- package/src/utils/chains/near/relayer/relayer.ts +0 -39
- package/src/utils/chains/near/relayer/types.ts +0 -24
- package/src/utils/chains/near/signAndSend/index.ts +0 -1
- package/src/utils/chains/near/signAndSend/keypair.ts +0 -180
- package/src/utils/chains/near/transactionBuilder.ts +0 -138
- package/src/utils/chains/near/types.ts +0 -67
- package/src/utils/index.ts +0 -1
- package/tsconfig.eslint.json +0 -8
- package/tsconfig.json +0 -116
- package/vite.config.ts +0 -47
- package/vocs.config.ts +0 -60
package/.eslintrc.json
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es2021": true
|
|
5
|
-
},
|
|
6
|
-
"extends": [
|
|
7
|
-
"standard-with-typescript",
|
|
8
|
-
"plugin:import/typescript",
|
|
9
|
-
"plugin:prettier/recommended"
|
|
10
|
-
],
|
|
11
|
-
"parserOptions": {
|
|
12
|
-
"project": ["./tsconfig.json", "./tsconfig.eslint.json"]
|
|
13
|
-
},
|
|
14
|
-
"rules": {
|
|
15
|
-
"@typescript-eslint/strict-boolean-expressions": "off",
|
|
16
|
-
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
|
17
|
-
"import/order": [
|
|
18
|
-
"error",
|
|
19
|
-
{
|
|
20
|
-
"groups": [
|
|
21
|
-
"builtin",
|
|
22
|
-
"external",
|
|
23
|
-
"internal",
|
|
24
|
-
"parent",
|
|
25
|
-
"sibling",
|
|
26
|
-
"index"
|
|
27
|
-
],
|
|
28
|
-
"pathGroups": [
|
|
29
|
-
{
|
|
30
|
-
"pattern": "@chains",
|
|
31
|
-
"group": "internal"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"pattern": "@chains/**",
|
|
35
|
-
"group": "internal"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"pattern": "@utils",
|
|
39
|
-
"group": "internal"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"pattern": "@utils/**",
|
|
43
|
-
"group": "internal"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
"pathGroupsExcludedImportTypes": ["builtin"],
|
|
47
|
-
"newlines-between": "always",
|
|
48
|
-
"alphabetize": {
|
|
49
|
-
"order": "asc",
|
|
50
|
-
"caseInsensitive": true
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
}
|
|
55
|
-
}
|
package/.prettierrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "singleQuote": true, "trailingComma": "es5", "semi": false }
|
package/babel.config.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Implementing a Custom Chain Signature Contract
|
|
2
|
-
|
|
3
|
-
This guide explains how to implement a custom Chain Signature Contract to provide as argument when instantiating a Chain instance.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The `ChainSignatureContract` is an abstract class that defines the interface for interacting with the Sig Network infrastructure.
|
|
8
|
-
|
|
9
|
-
- Key Derivation: Derive the child key from the root key using Sig Network key derivation function
|
|
10
|
-
- Sign: Sigs the given payload using Sig Network MPC
|
|
11
|
-
- Current Fee: Gets the current signature deposit that handles network congestion
|
|
12
|
-
|
|
13
|
-
While the library includes a default implementation for the NEAR protocol, you have the flexibility to implement your own contract for other blockchain networks.
|
|
14
|
-
|
|
15
|
-
## Using the NEAR Implementation
|
|
16
|
-
|
|
17
|
-
```ts twoslash
|
|
18
|
-
// [!include ~/snippets/env.ts]
|
|
19
|
-
// ---cut---
|
|
20
|
-
import { utils, EVM } from 'signet.js'
|
|
21
|
-
|
|
22
|
-
const contract = new utils.chains.near.ChainSignatureContract({
|
|
23
|
-
networkId: 'testnet',
|
|
24
|
-
contractId: 'v1.signer-prod.testnet',
|
|
25
|
-
accountId,
|
|
26
|
-
keypair,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const evmChain = new EVM({
|
|
30
|
-
rpcUrl: 'https://mainnet.infura.io/v3/YOUR-PROJECT-ID',
|
|
31
|
-
contract,
|
|
32
|
-
})
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Currently the contracts are available on the following Near addresses:
|
|
36
|
-
|
|
37
|
-
- Mainnet:
|
|
38
|
-
- `v1.signer`
|
|
39
|
-
- Testnet:
|
|
40
|
-
- `v1.signer-prod.testnet`
|
|
41
|
-
|
|
42
|
-
## Implementing a Custom Chain Signature Contract
|
|
43
|
-
|
|
44
|
-
To create your own implementation, your contract must implement the `ChainSignatureContract` interface.
|
|
45
|
-
|
|
46
|
-
```ts twoslash
|
|
47
|
-
// [!include ~/../src/chains/ChainSignatureContract.ts]
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Example: NEAR Implementation
|
|
51
|
-
|
|
52
|
-
Below is the reference implementation for the NEAR, which you can use as a guide for implementing your own chain signature contract:
|
|
53
|
-
|
|
54
|
-
```ts twoslash
|
|
55
|
-
// [!include ~/../src/utils/chains/near/ChainSignatureContract.ts]
|
|
56
|
-
```
|
package/docs/pages/chain.mdx
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Chain
|
|
2
|
-
|
|
3
|
-
Chain is the most basic interface of the signet.js library. It provides a standard set of methods that all chains must implement.
|
|
4
|
-
|
|
5
|
-
With this interface you will be able to interact with Sig Network smart contracts in a standard way to:
|
|
6
|
-
|
|
7
|
-
- getBalance
|
|
8
|
-
- deriveAddressAndPublicKey
|
|
9
|
-
- setTransaction
|
|
10
|
-
- getTransaction
|
|
11
|
-
- getMPCPayloadAndTransaction
|
|
12
|
-
- addSignature
|
|
13
|
-
- broadcastTx
|
|
14
|
-
|
|
15
|
-
If you wanna have a look this is the chain interface with a brief description of each method:
|
|
16
|
-
|
|
17
|
-
```ts twoslash
|
|
18
|
-
// [!include ~/../src/chains/Chain.ts]
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
# Implementing a New Chain
|
|
22
|
-
|
|
23
|
-
This guide explains how to implement support for a new blockchain network in the signet.js library.
|
|
24
|
-
|
|
25
|
-
## Overview
|
|
26
|
-
|
|
27
|
-
To add support for a new blockchain, you need to implement the `Chain` interface:
|
|
28
|
-
|
|
29
|
-
## Step-by-Step Guide
|
|
30
|
-
|
|
31
|
-
### 1. Create the Chain Types
|
|
32
|
-
|
|
33
|
-
First, define the transaction types for your chain:
|
|
34
|
-
|
|
35
|
-
```ts twoslash
|
|
36
|
-
// [!include ~/../src/chains/EVM/types.ts]
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### 2. Implement the Chain Interface
|
|
40
|
-
|
|
41
|
-
Create a new class that implements the `Chain` interface:
|
|
42
|
-
|
|
43
|
-
```ts twoslash
|
|
44
|
-
// [!include ~/../src/chains/EVM/EVM.ts]
|
|
45
|
-
```
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# Bitcoin Chain Implementation
|
|
2
|
-
|
|
3
|
-
The Bitcoin chain implementation supports both Bitcoin mainnet and testnet networks, with a focus on P2WPKH (Native SegWit) transactions.
|
|
4
|
-
|
|
5
|
-
## Configuration
|
|
6
|
-
|
|
7
|
-
```ts twoslash filename="base.ts"
|
|
8
|
-
// [!include ~/snippets/contract.ts]
|
|
9
|
-
// ---cut---
|
|
10
|
-
import { Bitcoin, BTCRpcAdapters } from 'signet.js'
|
|
11
|
-
|
|
12
|
-
// Initialize the RPC adapter using Mempool
|
|
13
|
-
const btcRpcAdapter = new BTCRpcAdapters.Mempool('https://mempool.space/api')
|
|
14
|
-
|
|
15
|
-
// Initialize the chain
|
|
16
|
-
const bitcoinChain = new Bitcoin({
|
|
17
|
-
network: 'testnet', // 'mainnet' | 'testnet' | 'regtest'
|
|
18
|
-
contract,
|
|
19
|
-
btcRpcAdapter,
|
|
20
|
-
})
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## RPC Adapter
|
|
24
|
-
|
|
25
|
-
The RPC adapter is a class that provides an interface for interacting with the Bitcoin network. It handles essential operations such as:
|
|
26
|
-
|
|
27
|
-
- Fetching UTXOs (Unspent Transaction Outputs)
|
|
28
|
-
- Retrieving transaction details
|
|
29
|
-
- Getting current network fees
|
|
30
|
-
- Broadcasting transactions
|
|
31
|
-
- Querying address balances
|
|
32
|
-
|
|
33
|
-
The adapter abstracts away the complexity of different Bitcoin API providers, allowing you to easily switch between services like Mempool.space, BlockCypher, or your own Bitcoin node.
|
|
34
|
-
|
|
35
|
-
For detailed implementation and configuration options, see the [RPC Adapter](./btc-rpc-adapter) documentation.
|
|
36
|
-
|
|
37
|
-
## Methods
|
|
38
|
-
|
|
39
|
-
### getBalance
|
|
40
|
-
|
|
41
|
-
Gets the BTC balance of an address.
|
|
42
|
-
|
|
43
|
-
```ts twoslash
|
|
44
|
-
// [!include base.ts]
|
|
45
|
-
// ---cut---
|
|
46
|
-
const balance = await bitcoinChain.getBalance(
|
|
47
|
-
'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh'
|
|
48
|
-
)
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Parameters:**
|
|
52
|
-
|
|
53
|
-
- `address`: The Bitcoin address to check
|
|
54
|
-
|
|
55
|
-
**Returns:**
|
|
56
|
-
|
|
57
|
-
- The balance in BTC as a string
|
|
58
|
-
|
|
59
|
-
### deriveAddressAndPublicKey
|
|
60
|
-
|
|
61
|
-
Derives a Bitcoin address and public key for a given path.
|
|
62
|
-
|
|
63
|
-
```ts twoslash
|
|
64
|
-
// [!include base.ts]
|
|
65
|
-
// ---cut---
|
|
66
|
-
const { address, publicKey } = await bitcoinChain.deriveAddressAndPublicKey(
|
|
67
|
-
'predecessor_id',
|
|
68
|
-
'any_string'
|
|
69
|
-
)
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Parameters:**
|
|
73
|
-
|
|
74
|
-
- `predecessor`: The ID of the signer to derive from
|
|
75
|
-
- `path`: The derivation path to use
|
|
76
|
-
|
|
77
|
-
**Returns:**
|
|
78
|
-
|
|
79
|
-
- Object containing:
|
|
80
|
-
- `address`: The derived Bitcoin P2WPKH address
|
|
81
|
-
- `publicKey`: The corresponding compressed public key
|
|
82
|
-
|
|
83
|
-
### getMPCPayloadAndTransaction
|
|
84
|
-
|
|
85
|
-
Prepares a transaction for MPC signing.
|
|
86
|
-
|
|
87
|
-
```ts twoslash filename="unsigned-transaction.ts"
|
|
88
|
-
// [!include base.ts]
|
|
89
|
-
// ---cut---
|
|
90
|
-
import { BTCTransactionRequest } from 'signet.js'
|
|
91
|
-
|
|
92
|
-
// Simple transfer format
|
|
93
|
-
const transactionRequest: BTCTransactionRequest = {
|
|
94
|
-
from: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
|
|
95
|
-
to: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
|
|
96
|
-
value: '0.001', // 0.001 BTC
|
|
97
|
-
publicKey: '0235a3...',
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const { transaction: unsignedTransaction, mpcPayloads } =
|
|
101
|
-
await bitcoinChain.getMPCPayloadAndTransaction(transactionRequest)
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Parameters:**
|
|
105
|
-
|
|
106
|
-
- `transactionRequest`: Either:
|
|
107
|
-
- Simple format:
|
|
108
|
-
```ts
|
|
109
|
-
{
|
|
110
|
-
from: string // Source address
|
|
111
|
-
to: string // Destination address
|
|
112
|
-
value: string // Amount in BTC
|
|
113
|
-
publicKey: string // Signer's public key
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
- Advanced format (manual UTXO selection):
|
|
117
|
-
```ts
|
|
118
|
-
{
|
|
119
|
-
inputs: BTCInput[] // Selected UTXOs
|
|
120
|
-
outputs: BTCOutput[] // Transaction outputs
|
|
121
|
-
publicKey: string // Signer's public key
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Returns:**
|
|
126
|
-
|
|
127
|
-
- Object containing:
|
|
128
|
-
- `transaction`: The unsigned transaction with PSBT
|
|
129
|
-
- `mpcPayloads`: Array of payloads to be signed
|
|
130
|
-
|
|
131
|
-
### addSignature
|
|
132
|
-
|
|
133
|
-
Adds signatures to a PSBT.
|
|
134
|
-
|
|
135
|
-
```ts twoslash filename="add-signature.ts"
|
|
136
|
-
// [!include unsigned-transaction.ts]
|
|
137
|
-
// ---cut---
|
|
138
|
-
import { RSVSignature } from 'signet.js'
|
|
139
|
-
|
|
140
|
-
// Ideally it would be a request to the Sig Network Smart Contract
|
|
141
|
-
const mpcSignatures: RSVSignature[] = [
|
|
142
|
-
{
|
|
143
|
-
r: '0x...',
|
|
144
|
-
s: '0x...',
|
|
145
|
-
v: 27,
|
|
146
|
-
},
|
|
147
|
-
]
|
|
148
|
-
|
|
149
|
-
const signedTx = bitcoinChain.addSignature({
|
|
150
|
-
transaction: unsignedTransaction,
|
|
151
|
-
mpcSignatures,
|
|
152
|
-
})
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
**Parameters:**
|
|
156
|
-
|
|
157
|
-
- `transaction`: The unsigned transaction with PSBT
|
|
158
|
-
- `mpcSignatures`: Array of RSV signatures from MPC
|
|
159
|
-
|
|
160
|
-
**Returns:**
|
|
161
|
-
|
|
162
|
-
- The serialized signed transaction in hex format
|
|
163
|
-
|
|
164
|
-
### broadcastTx
|
|
165
|
-
|
|
166
|
-
Broadcasts a signed transaction to the network.
|
|
167
|
-
|
|
168
|
-
```ts twoslash filename="broadcast-tx.ts"
|
|
169
|
-
// [!include add-signature.ts]
|
|
170
|
-
// ---cut---
|
|
171
|
-
const txid = await bitcoinChain.broadcastTx(signedTx)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Parameters:**
|
|
175
|
-
|
|
176
|
-
- `txSerialized`: The serialized transaction in hex format
|
|
177
|
-
|
|
178
|
-
**Returns:**
|
|
179
|
-
|
|
180
|
-
- The transaction ID (txid)
|
|
181
|
-
|
|
182
|
-
## Technical Details
|
|
183
|
-
|
|
184
|
-
The implementation:
|
|
185
|
-
|
|
186
|
-
- Uses `bitcoinjs-lib` for transaction handling
|
|
187
|
-
- Supports P2WPKH (Native SegWit) addresses
|
|
188
|
-
- Handles automatic UTXO selection and change outputs
|
|
189
|
-
- Supports custom fee rates through the RPC adapter
|
|
190
|
-
- Uses PSBT (Partially Signed Bitcoin Transactions)
|
|
191
|
-
- Supports both mainnet and testnet networks
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
# Implementing a Bitcoin RPC Adapter
|
|
2
|
-
|
|
3
|
-
This guide explains how to implement a custom RPC adapter for interacting with Bitcoin nodes or services.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The `BTCRpcAdapter` provides an abstraction layer for Bitcoin-specific operations like UTXO management, balance queries, and transaction broadcasting. You might want to implement a custom adapter when:
|
|
8
|
-
|
|
9
|
-
- Using a different Bitcoin node implementation
|
|
10
|
-
- Integrating with a specific blockchain service
|
|
11
|
-
- Adding support for custom transaction types
|
|
12
|
-
- Implementing specialized UTXO selection strategies
|
|
13
|
-
|
|
14
|
-
## Step-by-Step Guide
|
|
15
|
-
|
|
16
|
-
### 1. Define the Required Types
|
|
17
|
-
|
|
18
|
-
First, ensure you have the necessary types defined:
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
interface BTCInput {
|
|
22
|
-
txid: string
|
|
23
|
-
vout: number
|
|
24
|
-
value: number
|
|
25
|
-
address: string
|
|
26
|
-
scriptPubKey: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface BTCOutput {
|
|
30
|
-
address: string
|
|
31
|
-
value: number
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface BTCTransaction {
|
|
35
|
-
txid: string
|
|
36
|
-
vout: Array<{
|
|
37
|
-
scriptpubkey: string
|
|
38
|
-
value: number
|
|
39
|
-
}>
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### 2. Implement the BTCRpcAdapter
|
|
44
|
-
|
|
45
|
-
Create a new class that extends the `BTCRpcAdapter` abstract class:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
import { BTCRpcAdapter } from '../BTCRpcAdapter'
|
|
49
|
-
import { BTCInput, BTCOutput, BTCTransaction } from '../types'
|
|
50
|
-
|
|
51
|
-
export class CustomBTCAdapter extends BTCRpcAdapter {
|
|
52
|
-
constructor(
|
|
53
|
-
private readonly config: {
|
|
54
|
-
url: string
|
|
55
|
-
apiKey?: string
|
|
56
|
-
}
|
|
57
|
-
) {
|
|
58
|
-
super()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async getBalance(address: string): Promise<number> {
|
|
62
|
-
// Implement balance fetching
|
|
63
|
-
const response = await fetch(
|
|
64
|
-
`${this.config.url}/address/${address}/balance`,
|
|
65
|
-
{
|
|
66
|
-
headers: this.getHeaders(),
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
throw new Error(`Failed to fetch balance: ${await response.text()}`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const data = await response.json()
|
|
75
|
-
return data.balance // Return balance in satoshis
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async getTransaction(txid: string): Promise<BTCTransaction> {
|
|
79
|
-
// Implement transaction fetching
|
|
80
|
-
const response = await fetch(`${this.config.url}/tx/${txid}`, {
|
|
81
|
-
headers: this.getHeaders(),
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
if (!response.ok) {
|
|
85
|
-
throw new Error(`Failed to fetch transaction: ${await response.text()}`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return await response.json()
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async selectUTXOs(
|
|
92
|
-
from: string,
|
|
93
|
-
outputs: BTCOutput[],
|
|
94
|
-
confirmationTarget = 6
|
|
95
|
-
): Promise<{
|
|
96
|
-
inputs: BTCInput[]
|
|
97
|
-
outputs: BTCOutput[]
|
|
98
|
-
}> {
|
|
99
|
-
// 1. Fetch available UTXOs
|
|
100
|
-
const utxos = await this.fetchUTXOs(from)
|
|
101
|
-
|
|
102
|
-
// 2. Get current fee rate
|
|
103
|
-
const feeRate = await this.getFeeRate(confirmationTarget)
|
|
104
|
-
|
|
105
|
-
// 3. Use coinselect for UTXO selection
|
|
106
|
-
const { inputs, outputs } = coinselect(utxos, outputs, feeRate)
|
|
107
|
-
|
|
108
|
-
if (!inputs || !outputs) {
|
|
109
|
-
throw new Error('Failed to select UTXOs')
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return { inputs, outputs }
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async broadcastTransaction(txHex: string): Promise<string> {
|
|
116
|
-
// Implement transaction broadcasting
|
|
117
|
-
const response = await fetch(`${this.config.url}/tx`, {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
headers: this.getHeaders(),
|
|
120
|
-
body: txHex,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
if (!response.ok) {
|
|
124
|
-
throw new Error(
|
|
125
|
-
`Failed to broadcast transaction: ${await response.text()}`
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return await response.text() // Return txid
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Helper methods
|
|
133
|
-
private getHeaders(): Record<string, string> {
|
|
134
|
-
const headers: Record<string, string> = {
|
|
135
|
-
'Content-Type': 'application/json',
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (this.config.apiKey) {
|
|
139
|
-
headers['Authorization'] = `Bearer ${this.config.apiKey}`
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return headers
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private async fetchUTXOs(address: string): Promise<BTCInput[]> {
|
|
146
|
-
const response = await fetch(`${this.config.url}/address/${address}/utxo`, {
|
|
147
|
-
headers: this.getHeaders(),
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
if (!response.ok) {
|
|
151
|
-
throw new Error(`Failed to fetch UTXOs: ${await response.text()}`)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return await response.json()
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private async getFeeRate(confirmationTarget: number): Promise<number> {
|
|
158
|
-
const response = await fetch(`${this.config.url}/fees/recommended`, {
|
|
159
|
-
headers: this.getHeaders(),
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
if (!response.ok) {
|
|
163
|
-
throw new Error(`Failed to fetch fee rate: ${await response.text()}`)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const fees = await response.json()
|
|
167
|
-
return fees[`${confirmationTarget}BlockFee`]
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 3. Implement Error Handling
|
|
173
|
-
|
|
174
|
-
Add proper error handling for your adapter:
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
class BTCAdapterError extends Error {
|
|
178
|
-
constructor(
|
|
179
|
-
message: string,
|
|
180
|
-
public readonly code: string,
|
|
181
|
-
public readonly httpStatus?: number
|
|
182
|
-
) {
|
|
183
|
-
super(message)
|
|
184
|
-
this.name = 'BTCAdapterError'
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Usage in adapter methods
|
|
189
|
-
private async handleResponse<T>(
|
|
190
|
-
response: Response,
|
|
191
|
-
errorContext: string
|
|
192
|
-
): Promise<T> {
|
|
193
|
-
if (!response.ok) {
|
|
194
|
-
throw new BTCAdapterError(
|
|
195
|
-
`${errorContext}: ${await response.text()}`,
|
|
196
|
-
'API_ERROR',
|
|
197
|
-
response.status
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return await response.json()
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 4. Add UTXO Selection Strategy
|
|
206
|
-
|
|
207
|
-
Implement a custom UTXO selection strategy if needed:
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
interface UTXOSelectionStrategy {
|
|
211
|
-
select(
|
|
212
|
-
utxos: BTCInput[],
|
|
213
|
-
outputs: BTCOutput[],
|
|
214
|
-
feeRate: number
|
|
215
|
-
): {
|
|
216
|
-
inputs: BTCInput[]
|
|
217
|
-
outputs: BTCOutput[]
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
class LargestFirstStrategy implements UTXOSelectionStrategy {
|
|
222
|
-
select(
|
|
223
|
-
utxos: BTCInput[],
|
|
224
|
-
outputs: BTCOutput[],
|
|
225
|
-
feeRate: number
|
|
226
|
-
): {
|
|
227
|
-
inputs: BTCInput[]
|
|
228
|
-
outputs: BTCOutput[]
|
|
229
|
-
} {
|
|
230
|
-
// Sort UTXOs by value (largest first)
|
|
231
|
-
const sortedUtxos = [...utxos].sort((a, b) => b.value - a.value)
|
|
232
|
-
|
|
233
|
-
// Implement selection logic
|
|
234
|
-
// ...
|
|
235
|
-
|
|
236
|
-
return { inputs, outputs }
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
## Example Usage
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// Initialize the adapter
|
|
245
|
-
const btcAdapter = new CustomBTCAdapter({
|
|
246
|
-
url: 'https://api.bitcoin-service.com',
|
|
247
|
-
apiKey: 'your-api-key',
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
// Use in Bitcoin chain implementation
|
|
251
|
-
const bitcoinChain = new Bitcoin({
|
|
252
|
-
network: 'mainnet',
|
|
253
|
-
contract: new ChainSignatureContract(...),
|
|
254
|
-
btcRpcAdapter: btcAdapter,
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
// Direct usage
|
|
258
|
-
const balance = await btcAdapter.getBalance('bc1...')
|
|
259
|
-
|
|
260
|
-
const { inputs, outputs } = await btcAdapter.selectUTXOs(
|
|
261
|
-
'bc1...',
|
|
262
|
-
[{ address: 'bc1...', value: 100000 }]
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
const txid = await btcAdapter.broadcastTransaction(signedTxHex)
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Testing
|
|
269
|
-
|
|
270
|
-
Create comprehensive tests for your adapter:
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
describe('CustomBTCAdapter', () => {
|
|
274
|
-
let adapter: CustomBTCAdapter
|
|
275
|
-
let mockFetch: jest.Mock
|
|
276
|
-
|
|
277
|
-
beforeEach(() => {
|
|
278
|
-
mockFetch = jest.fn()
|
|
279
|
-
global.fetch = mockFetch
|
|
280
|
-
adapter = new CustomBTCAdapter({
|
|
281
|
-
url: 'https://test.api',
|
|
282
|
-
apiKey: 'test-key',
|
|
283
|
-
})
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
describe('getBalance', () => {
|
|
287
|
-
it('should return balance in satoshis', async () => {
|
|
288
|
-
mockFetch.mockResolvedValueOnce({
|
|
289
|
-
ok: true,
|
|
290
|
-
json: () => Promise.resolve({ balance: 100000 }),
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
const balance = await adapter.getBalance('bc1...')
|
|
294
|
-
expect(balance).toBe(100000)
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
it('should handle errors', async () => {
|
|
298
|
-
mockFetch.mockResolvedValueOnce({
|
|
299
|
-
ok: false,
|
|
300
|
-
text: () => Promise.resolve('API Error'),
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
await expect(adapter.getBalance('bc1...')).rejects.toThrow()
|
|
304
|
-
})
|
|
305
|
-
})
|
|
306
|
-
})
|
|
307
|
-
```
|