signet.js 0.0.1-beta.5 → 0.0.1-beta.7
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/.eslintrc.json +55 -0
- package/.prettierrc +1 -0
- package/LICENSE +19 -0
- package/README.md +42 -14
- package/babel.config.js +6 -0
- package/docs/pages/chain-signatures-contract.mdx +56 -0
- package/docs/pages/chain.mdx +45 -0
- package/docs/pages/chains/bitcoin/bitcoin.mdx +191 -0
- package/docs/pages/chains/bitcoin/btc-rpc-adapter.mdx +307 -0
- package/docs/pages/chains/cosmos.mdx +181 -0
- package/docs/pages/chains/evm.mdx +189 -0
- package/docs/pages/index.mdx +99 -0
- package/docs/snippets/contract.ts +21 -0
- package/docs/snippets/env.ts +13 -0
- package/jest.config.ts +199 -0
- package/package.json +21 -11
- package/src/chains/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.ts +11 -0
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/Mempool.ts +96 -0
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/index.ts +1 -0
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/types.ts +72 -0
- package/src/chains/Bitcoin/BTCRpcAdapter/index.ts +6 -0
- package/src/chains/Bitcoin/Bitcoin.ts +301 -0
- package/src/chains/Bitcoin/types.ts +45 -0
- package/src/chains/Bitcoin/utils.ts +14 -0
- package/src/chains/Chain.ts +96 -0
- package/src/chains/ChainSignatureContract.ts +48 -0
- package/src/chains/Cosmos/Cosmos.ts +279 -0
- package/src/chains/Cosmos/types.ts +35 -0
- package/src/chains/Cosmos/utils.ts +45 -0
- package/src/chains/EVM/EVM.ts +180 -0
- package/src/chains/EVM/types.ts +7 -0
- package/src/chains/EVM/utils.ts +26 -0
- package/src/chains/index.ts +34 -0
- package/src/chains/types.ts +35 -0
- package/src/chains/utils.ts +40 -0
- package/src/index.ts +2 -0
- package/src/utils/chains/index.ts +1 -0
- package/src/utils/chains/near/ChainSignatureContract.ts +195 -0
- package/src/utils/chains/near/account.ts +42 -0
- package/src/utils/chains/near/constants.ts +4 -0
- package/src/utils/chains/near/index.ts +3 -0
- package/src/utils/chains/near/relayer/index.ts +1 -0
- package/src/utils/chains/near/relayer/relayer.ts +39 -0
- package/src/utils/chains/near/relayer/types.ts +24 -0
- package/src/utils/chains/near/signAndSend/index.ts +1 -0
- package/src/utils/chains/near/signAndSend/keypair.ts +180 -0
- package/src/utils/chains/near/transactionBuilder.ts +138 -0
- package/src/utils/chains/near/types.ts +67 -0
- package/src/utils/index.ts +1 -0
- package/tsconfig.eslint.json +8 -0
- package/tsconfig.json +116 -0
- package/vite.config.ts +47 -0
- package/vocs.config.ts +60 -0
- package/src/chains/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.d.ts +0 -10
- package/src/chains/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.js +0 -2
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/Mempool.d.ts +0 -15
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/Mempool.js +0 -69
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/index.d.ts +0 -1
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/index.js +0 -1
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/types.d.ts +0 -69
- package/src/chains/Bitcoin/BTCRpcAdapter/Mempool/types.js +0 -1
- package/src/chains/Bitcoin/BTCRpcAdapter/index.d.ts +0 -5
- package/src/chains/Bitcoin/BTCRpcAdapter/index.js +0 -5
- package/src/chains/Bitcoin/Bitcoin.d.ts +0 -69
- package/src/chains/Bitcoin/Bitcoin.js +0 -198
- package/src/chains/Bitcoin/types.d.ts +0 -42
- package/src/chains/Bitcoin/types.js +0 -1
- package/src/chains/Bitcoin/utils.d.ts +0 -2
- package/src/chains/Bitcoin/utils.js +0 -13
- package/src/chains/Chain.d.ts +0 -89
- package/src/chains/Chain.js +0 -9
- package/src/chains/ChainSignatureContract.d.ts +0 -62
- package/src/chains/ChainSignatureContract.js +0 -7
- package/src/chains/Cosmos/Cosmos.d.ts +0 -51
- package/src/chains/Cosmos/Cosmos.js +0 -157
- package/src/chains/Cosmos/types.d.ts +0 -30
- package/src/chains/Cosmos/types.js +0 -1
- package/src/chains/Cosmos/utils.d.ts +0 -2
- package/src/chains/Cosmos/utils.js +0 -27
- package/src/chains/EVM/EVM.d.ts +0 -42
- package/src/chains/EVM/EVM.js +0 -109
- package/src/chains/EVM/types.d.ts +0 -5
- package/src/chains/EVM/types.js +0 -1
- package/src/chains/EVM/utils.d.ts +0 -7
- package/src/chains/EVM/utils.js +0 -14
- package/src/chains/index.d.ts +0 -12
- package/src/chains/index.js +0 -12
- package/src/chains/types.d.ts +0 -31
- package/src/chains/types.js +0 -1
- package/src/chains/utils.d.ts +0 -12
- package/src/chains/utils.js +0 -27
- package/src/index.d.ts +0 -2
- package/src/index.js +0 -2
- package/src/utils/chains/index.d.ts +0 -1
- package/src/utils/chains/index.js +0 -1
- package/src/utils/chains/near/account.d.ts +0 -13
- package/src/utils/chains/near/account.js +0 -22
- package/src/utils/chains/near/constants.d.ts +0 -3
- package/src/utils/chains/near/constants.js +0 -3
- package/src/utils/chains/near/contract.d.ts +0 -40
- package/src/utils/chains/near/contract.js +0 -102
- package/src/utils/chains/near/index.d.ts +0 -3
- package/src/utils/chains/near/index.js +0 -3
- package/src/utils/chains/near/relayer/index.d.ts +0 -1
- package/src/utils/chains/near/relayer/index.js +0 -1
- package/src/utils/chains/near/relayer/relayer.d.ts +0 -8
- package/src/utils/chains/near/relayer/relayer.js +0 -33
- package/src/utils/chains/near/relayer/types.d.ts +0 -22
- package/src/utils/chains/near/relayer/types.js +0 -1
- package/src/utils/chains/near/signAndSend/index.d.ts +0 -1
- package/src/utils/chains/near/signAndSend/index.js +0 -1
- package/src/utils/chains/near/signAndSend/keypair.d.ts +0 -6
- package/src/utils/chains/near/signAndSend/keypair.js +0 -127
- package/src/utils/chains/near/transactionBuilder.d.ts +0 -26
- package/src/utils/chains/near/transactionBuilder.js +0 -72
- package/src/utils/chains/near/types.d.ts +0 -50
- package/src/utils/chains/near/types.js +0 -1
- package/src/utils/index.d.ts +0 -1
- package/src/utils/index.js +0 -1
- package/vocs.config.d.ts +0 -3
- package/vocs.config.js +0 -71
|
@@ -0,0 +1,307 @@
|
|
|
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
|
+
```
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Cosmos Chain Implementation
|
|
2
|
+
|
|
3
|
+
The Cosmos chain implementation supports Cosmos SDK-based networks (Cosmos Hub, Osmosis, etc.) with a focus on standard transactions and IBC transfers.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```ts twoslash filename="base.ts"
|
|
8
|
+
// [!include ~/snippets/contract.ts]
|
|
9
|
+
// ---cut---
|
|
10
|
+
import { Cosmos } from 'signet.js'
|
|
11
|
+
|
|
12
|
+
const cosmosChain = new Cosmos({
|
|
13
|
+
chainId: 'cosmoshub-4', // Chain ID of the target network
|
|
14
|
+
contract,
|
|
15
|
+
})
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Methods
|
|
19
|
+
|
|
20
|
+
### getBalance
|
|
21
|
+
|
|
22
|
+
Gets the native token balance of an address.
|
|
23
|
+
|
|
24
|
+
```ts twoslash
|
|
25
|
+
// [!include base.ts]
|
|
26
|
+
// ---cut---
|
|
27
|
+
const balance = await cosmosChain.getBalance('cosmos1...')
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Parameters:**
|
|
31
|
+
|
|
32
|
+
- `address`: The Cosmos address to check
|
|
33
|
+
|
|
34
|
+
**Returns:**
|
|
35
|
+
|
|
36
|
+
- The balance formatted according to the chain's decimal places
|
|
37
|
+
|
|
38
|
+
### deriveAddressAndPublicKey
|
|
39
|
+
|
|
40
|
+
Derives a Cosmos address and public key for a given path.
|
|
41
|
+
|
|
42
|
+
```ts twoslash
|
|
43
|
+
// [!include base.ts]
|
|
44
|
+
// ---cut---
|
|
45
|
+
const { address, publicKey } = await cosmosChain.deriveAddressAndPublicKey(
|
|
46
|
+
'predecessor_id',
|
|
47
|
+
'any_string'
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
|
|
53
|
+
- `predecessor`: The ID of the signer to derive from
|
|
54
|
+
- `path`: The derivation path to use
|
|
55
|
+
|
|
56
|
+
**Returns:**
|
|
57
|
+
|
|
58
|
+
- Object containing:
|
|
59
|
+
- `address`: The derived Cosmos address (bech32 format)
|
|
60
|
+
- `publicKey`: The corresponding compressed public key
|
|
61
|
+
|
|
62
|
+
### getMPCPayloadAndTransaction
|
|
63
|
+
|
|
64
|
+
Prepares a transaction for MPC signing.
|
|
65
|
+
|
|
66
|
+
```ts twoslash filename="unsigned-transaction.ts"
|
|
67
|
+
// [!include base.ts]
|
|
68
|
+
// ---cut---
|
|
69
|
+
import { CosmosTransactionRequest } from 'signet.js'
|
|
70
|
+
import { MsgSend } from 'cosmjs-types/cosmos/bank/v1beta1/tx'
|
|
71
|
+
|
|
72
|
+
// Create a token transfer message
|
|
73
|
+
const sendMsg = {
|
|
74
|
+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
|
|
75
|
+
value: MsgSend.fromPartial({
|
|
76
|
+
fromAddress: 'cosmos1...',
|
|
77
|
+
toAddress: 'cosmos1...',
|
|
78
|
+
amount: [
|
|
79
|
+
{
|
|
80
|
+
denom: 'uatom',
|
|
81
|
+
amount: '1000000', // 1 ATOM (1,000,000 uatom)
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
}),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const transactionRequest: CosmosTransactionRequest = {
|
|
88
|
+
address: 'cosmos1...',
|
|
89
|
+
publicKey: '0235a3...',
|
|
90
|
+
messages: [sendMsg],
|
|
91
|
+
memo: 'Token transfer',
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { transaction: unsignedTransaction, mpcPayloads } =
|
|
95
|
+
await cosmosChain.getMPCPayloadAndTransaction(transactionRequest)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
|
|
100
|
+
- `transactionRequest`: Transaction configuration:
|
|
101
|
+
```ts
|
|
102
|
+
{
|
|
103
|
+
address: string // Sender's address
|
|
104
|
+
publicKey: string // Signer's public key
|
|
105
|
+
messages: Message[] // Array of Cosmos SDK messages
|
|
106
|
+
memo?: string // Optional transaction memo
|
|
107
|
+
gas?: number // Optional gas limit (default: 200,000)
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Returns:**
|
|
112
|
+
|
|
113
|
+
- Object containing:
|
|
114
|
+
- `transaction`: The unsigned transaction
|
|
115
|
+
- `mpcPayloads`: Array of payloads to be signed
|
|
116
|
+
|
|
117
|
+
### addSignature
|
|
118
|
+
|
|
119
|
+
Adds signatures to a transaction.
|
|
120
|
+
|
|
121
|
+
```ts twoslash filename="add-signature.ts"
|
|
122
|
+
// [!include unsigned-transaction.ts]
|
|
123
|
+
// ---cut---
|
|
124
|
+
import { RSVSignature } from 'signet.js'
|
|
125
|
+
|
|
126
|
+
// Ideally it would be a request to the Sig Network Smart Contract
|
|
127
|
+
const mpcSignatures: RSVSignature[] = [
|
|
128
|
+
{
|
|
129
|
+
r: '0x...',
|
|
130
|
+
s: '0x...',
|
|
131
|
+
v: 27,
|
|
132
|
+
},
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
const signedTx = cosmosChain.addSignature({
|
|
136
|
+
transaction: unsignedTransaction,
|
|
137
|
+
mpcSignatures,
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Parameters:**
|
|
142
|
+
|
|
143
|
+
- `transaction`: The unsigned transaction
|
|
144
|
+
- `mpcSignatures`: Array of RSV signatures from MPC
|
|
145
|
+
|
|
146
|
+
**Returns:**
|
|
147
|
+
|
|
148
|
+
- The serialized signed transaction in hex format
|
|
149
|
+
|
|
150
|
+
### broadcastTx
|
|
151
|
+
|
|
152
|
+
Broadcasts a signed transaction to the network.
|
|
153
|
+
|
|
154
|
+
```ts twoslash filename="broadcast-tx.ts"
|
|
155
|
+
// [!include add-signature.ts]
|
|
156
|
+
// ---cut---
|
|
157
|
+
const txHash = await cosmosChain.broadcastTx(signedTx)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Parameters:**
|
|
161
|
+
|
|
162
|
+
- `txSerialized`: The serialized transaction in hex format
|
|
163
|
+
|
|
164
|
+
**Returns:**
|
|
165
|
+
|
|
166
|
+
- The transaction hash
|
|
167
|
+
|
|
168
|
+
## Technical Details
|
|
169
|
+
|
|
170
|
+
The implementation:
|
|
171
|
+
|
|
172
|
+
- Uses `@cosmjs/stargate` for transaction handling
|
|
173
|
+
- Supports SIGN_MODE_DIRECT signing
|
|
174
|
+
- Uses Protobuf for message encoding
|
|
175
|
+
- Supports standard Cosmos SDK messages:
|
|
176
|
+
- Bank (Send, MultiSend)
|
|
177
|
+
- Staking (Delegate, Undelegate, Redelegate)
|
|
178
|
+
- Distribution (Withdraw Rewards)
|
|
179
|
+
- IBC (Transfer)
|
|
180
|
+
- Handles automatic fee calculation based on gas prices
|
|
181
|
+
- Supports custom message types through the Registry
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# EVM Chain Implementation
|
|
2
|
+
|
|
3
|
+
This implementation supports all EVM-compatible networks (Ethereum, Binance Smart Chain, Polygon, etc.).
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```ts twoslash filename="base.ts"
|
|
8
|
+
// [!include ~/snippets/contract.ts]
|
|
9
|
+
// ---cut---
|
|
10
|
+
import { EVM } from 'signet.js'
|
|
11
|
+
|
|
12
|
+
// Initialize the chain
|
|
13
|
+
const evmChain = new EVM({
|
|
14
|
+
rpcUrl: 'https://mainnet.infura.io/v3/YOUR-PROJECT-ID',
|
|
15
|
+
contract,
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Methods
|
|
20
|
+
|
|
21
|
+
### getBalance
|
|
22
|
+
|
|
23
|
+
Gets the native token balance of an address in ETH units.
|
|
24
|
+
|
|
25
|
+
```ts twoslash
|
|
26
|
+
// [!include base.ts]
|
|
27
|
+
// ---cut---
|
|
28
|
+
const balance = await evmChain.getBalance('0x...')
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Parameters:**
|
|
32
|
+
|
|
33
|
+
- `address`: The Ethereum address to check
|
|
34
|
+
|
|
35
|
+
**Returns:**
|
|
36
|
+
|
|
37
|
+
- The balance in ETH as a string
|
|
38
|
+
|
|
39
|
+
### deriveAddressAndPublicKey
|
|
40
|
+
|
|
41
|
+
Derives an Ethereum address and public key from a signer ID and derivation path.
|
|
42
|
+
|
|
43
|
+
```ts twoslash
|
|
44
|
+
// [!include base.ts]
|
|
45
|
+
// ---cut---
|
|
46
|
+
const { address, publicKey } = await evmChain.deriveAddressAndPublicKey(
|
|
47
|
+
'0x...',
|
|
48
|
+
'any_string'
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
|
|
54
|
+
- `predecessor`: The ID/address of the signer requesting the signature
|
|
55
|
+
- `path`: The derivation path to use
|
|
56
|
+
|
|
57
|
+
**Returns:**
|
|
58
|
+
|
|
59
|
+
- Object containing:
|
|
60
|
+
- `address`: The derived Ethereum address
|
|
61
|
+
- `publicKey`: The corresponding public key in SEC1 uncompressed format
|
|
62
|
+
|
|
63
|
+
### getMPCPayloadAndTransaction
|
|
64
|
+
|
|
65
|
+
Prepares a transaction for MPC signing.
|
|
66
|
+
|
|
67
|
+
```ts twoslash filename="unsigned-transaction.ts"
|
|
68
|
+
// [!include base.ts]
|
|
69
|
+
// ---cut---
|
|
70
|
+
import { EVMTransactionRequest } from 'signet.js'
|
|
71
|
+
|
|
72
|
+
const transactionRequest: EVMTransactionRequest = {
|
|
73
|
+
to: '0x...',
|
|
74
|
+
from: '0x...',
|
|
75
|
+
value: '100000000000000000',
|
|
76
|
+
data: '0x...',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const { transaction: unsignedTransaction, mpcPayloads } =
|
|
80
|
+
await evmChain.getMPCPayloadAndTransaction(transactionRequest)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The transaction is enhanced with:
|
|
84
|
+
|
|
85
|
+
- Gas estimation
|
|
86
|
+
- Nonce calculation
|
|
87
|
+
- Chain ID
|
|
88
|
+
- EIP-1559 fee parameters
|
|
89
|
+
|
|
90
|
+
### addSignature
|
|
91
|
+
|
|
92
|
+
Adds a signature to an unsigned transaction.
|
|
93
|
+
|
|
94
|
+
```ts twoslash filename="add-signature.ts"
|
|
95
|
+
// [!include unsigned-transaction.ts]
|
|
96
|
+
// ---cut---
|
|
97
|
+
import { RSVSignature } from 'signet.js'
|
|
98
|
+
|
|
99
|
+
// Ideally it would be a request to the Sig Network Smart Contract
|
|
100
|
+
const mpcSignatures: RSVSignature[] = [
|
|
101
|
+
{
|
|
102
|
+
r: '0x...',
|
|
103
|
+
s: '0x...',
|
|
104
|
+
v: 27,
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
const txSerialized = await evmChain.addSignature({
|
|
109
|
+
transaction: unsignedTransaction,
|
|
110
|
+
mpcSignatures,
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Parameters:**
|
|
115
|
+
|
|
116
|
+
- `transaction`: The unsigned transaction
|
|
117
|
+
- `mpcSignatures`: Array of RSV signatures from MPC
|
|
118
|
+
|
|
119
|
+
**Returns:**
|
|
120
|
+
|
|
121
|
+
- The serialized signed transaction
|
|
122
|
+
|
|
123
|
+
### broadcastTx
|
|
124
|
+
|
|
125
|
+
Broadcasts a signed transaction to the network.
|
|
126
|
+
|
|
127
|
+
```ts twoslash filename="broadcast-tx.ts"
|
|
128
|
+
// [!include add-signature.ts]
|
|
129
|
+
// ---cut---
|
|
130
|
+
const txHash = await evmChain.broadcastTx(txSerialized)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Parameters:**
|
|
134
|
+
|
|
135
|
+
- `txSerialized`: The serialized signed transaction
|
|
136
|
+
|
|
137
|
+
**Returns:**
|
|
138
|
+
|
|
139
|
+
- The transaction hash
|
|
140
|
+
|
|
141
|
+
## Adding New EVM Chains
|
|
142
|
+
|
|
143
|
+
To add support for a new EVM-compatible chain, you only need to configure the provider URL. The chain ID and network configuration are automatically retrieved from the provider.
|
|
144
|
+
|
|
145
|
+
```ts twoslash
|
|
146
|
+
// [!include ~/snippets/contract.ts]
|
|
147
|
+
// ---cut---
|
|
148
|
+
import { EVM } from 'signet.js'
|
|
149
|
+
|
|
150
|
+
// For Polygon (Matic)
|
|
151
|
+
const polygonChain = new EVM({
|
|
152
|
+
rpcUrl: 'https://polygon-rpc.com',
|
|
153
|
+
contract,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// For Binance Smart Chain
|
|
157
|
+
const bscChain = new EVM({
|
|
158
|
+
rpcUrl: 'https://bsc-dataseed.binance.org',
|
|
159
|
+
contract,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// For Arbitrum
|
|
163
|
+
const arbitrumChain = new EVM({
|
|
164
|
+
rpcUrl: 'https://arb1.arbitrum.io/rpc',
|
|
165
|
+
contract,
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Technical Details
|
|
170
|
+
|
|
171
|
+
The implementation:
|
|
172
|
+
|
|
173
|
+
- Uses `ethers.js` for transaction handling and RPC communication
|
|
174
|
+
- Supports both legacy and EIP-1559 transactions
|
|
175
|
+
- Handles automatic nonce management
|
|
176
|
+
- Supports contract interactions through ABI encoding
|
|
177
|
+
- Provides automatic gas estimation and fee calculation
|
|
178
|
+
- Compatible with all EVM-based networks
|
|
179
|
+
- Supports ENS name resolution on networks that implement it
|
|
180
|
+
- Handles transaction signing according to EIP-155
|
|
181
|
+
- Supports raw transaction data for custom contract interactions
|
|
182
|
+
|
|
183
|
+
## Types
|
|
184
|
+
|
|
185
|
+
The following types are used on the EVM chain:
|
|
186
|
+
|
|
187
|
+
```ts twoslash
|
|
188
|
+
// [!include ~/../src/chains/EVM/types.ts]
|
|
189
|
+
```
|