bitbadgesjs-sdk 0.30.0 → 0.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +258 -47
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/signing/BitBadgesSigningClient.d.ts +32 -0
- package/dist/cjs/signing/BitBadgesSigningClient.d.ts.map +1 -0
- package/dist/cjs/signing/BitBadgesSigningClient.js +270 -0
- package/dist/cjs/signing/BitBadgesSigningClient.js.map +1 -0
- package/dist/cjs/signing/BitBadgesSigningClient.spec.d.ts +2 -0
- package/dist/cjs/signing/BitBadgesSigningClient.spec.d.ts.map +1 -0
- package/dist/cjs/signing/BitBadgesSigningClient.spec.js +182 -0
- package/dist/cjs/signing/BitBadgesSigningClient.spec.js.map +1 -0
- package/dist/cjs/signing/adapters/GenericCosmosAdapter.d.ts +73 -0
- package/dist/cjs/signing/adapters/GenericCosmosAdapter.d.ts.map +1 -0
- package/dist/cjs/signing/adapters/GenericCosmosAdapter.js +189 -0
- package/dist/cjs/signing/adapters/GenericCosmosAdapter.js.map +1 -0
- package/dist/cjs/signing/adapters/GenericEvmAdapter.d.ts +37 -0
- package/dist/cjs/signing/adapters/GenericEvmAdapter.d.ts.map +1 -0
- package/dist/cjs/signing/adapters/GenericEvmAdapter.js +71 -0
- package/dist/cjs/signing/adapters/GenericEvmAdapter.js.map +1 -0
- package/dist/cjs/signing/adapters/WalletAdapter.d.ts +23 -0
- package/dist/cjs/signing/adapters/WalletAdapter.d.ts.map +1 -0
- package/dist/cjs/signing/adapters/WalletAdapter.js +16 -0
- package/dist/cjs/signing/adapters/WalletAdapter.js.map +1 -0
- package/dist/cjs/signing/adapters/index.d.ts +4 -0
- package/dist/cjs/signing/adapters/index.d.ts.map +1 -0
- package/dist/cjs/signing/adapters/index.js +10 -0
- package/dist/cjs/signing/adapters/index.js.map +1 -0
- package/dist/cjs/signing/index.d.ts +4 -0
- package/dist/cjs/signing/index.d.ts.map +1 -0
- package/dist/cjs/signing/index.js +10 -0
- package/dist/cjs/signing/index.js.map +1 -0
- package/dist/cjs/signing/types.d.ts +68 -0
- package/dist/cjs/signing/types.d.ts.map +1 -0
- package/dist/cjs/signing/types.js +3 -0
- package/dist/cjs/signing/types.js.map +1 -0
- package/dist/cjs/tsconfig.build.tsbuildinfo +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/signing/BitBadgesSigningClient.d.ts +32 -0
- package/dist/esm/signing/BitBadgesSigningClient.d.ts.map +1 -0
- package/dist/esm/signing/BitBadgesSigningClient.js +275 -0
- package/dist/esm/signing/BitBadgesSigningClient.js.map +1 -0
- package/dist/esm/signing/BitBadgesSigningClient.spec.d.ts +2 -0
- package/dist/esm/signing/BitBadgesSigningClient.spec.d.ts.map +1 -0
- package/dist/esm/signing/BitBadgesSigningClient.spec.js +176 -0
- package/dist/esm/signing/BitBadgesSigningClient.spec.js.map +1 -0
- package/dist/esm/signing/adapters/GenericCosmosAdapter.d.ts +73 -0
- package/dist/esm/signing/adapters/GenericCosmosAdapter.d.ts.map +1 -0
- package/dist/esm/signing/adapters/GenericCosmosAdapter.js +162 -0
- package/dist/esm/signing/adapters/GenericCosmosAdapter.js.map +1 -0
- package/dist/esm/signing/adapters/GenericEvmAdapter.d.ts +37 -0
- package/dist/esm/signing/adapters/GenericEvmAdapter.d.ts.map +1 -0
- package/dist/esm/signing/adapters/GenericEvmAdapter.js +70 -0
- package/dist/esm/signing/adapters/GenericEvmAdapter.js.map +1 -0
- package/dist/esm/signing/adapters/WalletAdapter.d.ts +23 -0
- package/dist/esm/signing/adapters/WalletAdapter.d.ts.map +1 -0
- package/dist/esm/signing/adapters/WalletAdapter.js +12 -0
- package/dist/esm/signing/adapters/WalletAdapter.js.map +1 -0
- package/dist/esm/signing/adapters/index.d.ts +4 -0
- package/dist/esm/signing/adapters/index.d.ts.map +1 -0
- package/dist/esm/signing/adapters/index.js +4 -0
- package/dist/esm/signing/adapters/index.js.map +1 -0
- package/dist/esm/signing/index.d.ts +4 -0
- package/dist/esm/signing/index.d.ts.map +1 -0
- package/dist/esm/signing/index.js +3 -0
- package/dist/esm/signing/index.js.map +1 -0
- package/dist/esm/signing/types.d.ts +68 -0
- package/dist/esm/signing/types.d.ts.map +1 -0
- package/dist/esm/signing/types.js +2 -0
- package/dist/esm/signing/types.js.map +1 -0
- package/dist/esm/tsconfig-esm.build.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,70 +1,281 @@
|
|
|
1
|
-
#
|
|
1
|
+
# BitBadges SDK
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The official TypeScript SDK for interacting with the BitBadges blockchain, API, and indexer.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/bitbadgesjs-sdk)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Installation
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
```bash
|
|
10
|
+
npm install bitbadgesjs-sdk
|
|
11
|
+
# or
|
|
12
|
+
bun add bitbadgesjs-sdk
|
|
13
|
+
```
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
## Quick Start
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
### 1. Initialize the API Client
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { BitBadgesAPI, BigIntify } from 'bitbadgesjs-sdk';
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
const api = new BitBadgesAPI({
|
|
23
|
+
convertFunction: BigIntify,
|
|
24
|
+
apiKey: 'your-api-key', // Get from https://bitbadges.io/developer
|
|
25
|
+
apiUrl: 'https://api.bitbadges.io' // Optional, defaults to production
|
|
26
|
+
});
|
|
27
|
+
```
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
| ----------------------- | ----------------- | ---------- |
|
|
20
|
-
| v12 | 0.18.x | ✅ Current |
|
|
21
|
-
| v13 | 0.19.x | ✅ Current |
|
|
22
|
-
| v14 | 0.20.x | ✅ Current |
|
|
23
|
-
| v15 | 0.20.x | ✅ Current |
|
|
24
|
-
| v16 | 0.21.x | ✅ Current |
|
|
25
|
-
| v18 | 0.23.x | ✅ Current |
|
|
26
|
-
| v19 | 0.24.x | ✅ Current |
|
|
27
|
-
| v20 | 0.25.x | ✅ Current |
|
|
28
|
-
| v21 | 0.26.x | ✅ Current |
|
|
29
|
-
| v22 | 0.27.x | ✅ Current |
|
|
30
|
-
| v23 | 0.28.x | ✅ Current |
|
|
29
|
+
### 2. Fetch a Collection
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
```typescript
|
|
32
|
+
const response = await api.getCollections({
|
|
33
|
+
collectionsToFetch: [
|
|
34
|
+
{
|
|
35
|
+
collectionId: '1',
|
|
36
|
+
metadataToFetch: {
|
|
37
|
+
tokenIds: [{ start: 1n, end: 10n }]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
});
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
const collection = response.collections[0]?.collection;
|
|
44
|
+
console.log('Name:', collection?.collectionMetadataTimeline?.[0]?.collectionMetadata?.name);
|
|
45
|
+
```
|
|
35
46
|
|
|
36
|
-
###
|
|
47
|
+
### 3. Check a User's Balance
|
|
37
48
|
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
```typescript
|
|
50
|
+
const balance = await api.getBalanceByAddress(
|
|
51
|
+
'1', // collectionId
|
|
52
|
+
'bb1abc...', // address
|
|
53
|
+
{}
|
|
54
|
+
);
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
console.log('Token IDs:', balance.balances.map(b => b.badgeIds));
|
|
57
|
+
console.log('Amounts:', balance.balances.map(b => b.amount));
|
|
44
58
|
```
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
### 4. Get Token Activity
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
```typescript
|
|
63
|
+
const activity = await api.getTokenActivity('1', '1', { bookmark: '' });
|
|
64
|
+
|
|
65
|
+
for (const item of activity.activity) {
|
|
66
|
+
console.log(`${item.from} -> ${item.to}: ${item.balances}`);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Browser vs Node.js Usage
|
|
71
|
+
|
|
72
|
+
The SDK works in both browser and Node.js environments. Environment detection is handled automatically.
|
|
73
|
+
|
|
74
|
+
### Node.js
|
|
49
75
|
|
|
50
76
|
```typescript
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
77
|
+
// API key can be set via environment variable
|
|
78
|
+
process.env.BITBADGES_API_KEY = 'your-api-key';
|
|
79
|
+
|
|
80
|
+
const api = new BitBadgesAPI({
|
|
81
|
+
convertFunction: BigIntify
|
|
82
|
+
// apiKey will be read from BITBADGES_API_KEY env var
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Browser
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// In browsers, you MUST pass the apiKey explicitly
|
|
90
|
+
const api = new BitBadgesAPI({
|
|
91
|
+
convertFunction: BigIntify,
|
|
92
|
+
apiKey: 'your-api-key' // Required in browser - no env var access
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **Note**: The SDK uses defensive checks (`typeof process !== 'undefined'`) to support both environments. No polyfills needed.
|
|
97
|
+
|
|
98
|
+
## Core Concepts
|
|
99
|
+
|
|
100
|
+
### Number Types
|
|
101
|
+
|
|
102
|
+
The SDK uses a flexible `NumberType` system supporting `bigint`, `number`, and `string` to handle large blockchain values safely.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { BigIntify, Stringify, Numberify } from 'bitbadgesjs-sdk';
|
|
106
|
+
|
|
107
|
+
// Always use BigIntify for large numbers (recommended)
|
|
108
|
+
const collectionId = BigIntify('12345678901234567890');
|
|
109
|
+
|
|
110
|
+
// Stringify for JSON serialization
|
|
111
|
+
const idString = Stringify(12345678901234567890n);
|
|
112
|
+
|
|
113
|
+
// Numberify only for small, safe integers
|
|
114
|
+
const smallNum = Numberify('100');
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Type System
|
|
118
|
+
|
|
119
|
+
The SDK has three type layers:
|
|
120
|
+
|
|
121
|
+
| Type | Example | Use Case |
|
|
122
|
+
|------|---------|----------|
|
|
123
|
+
| **Interface** (`iType`) | `iBalance<bigint>` | Type annotations, function parameters |
|
|
124
|
+
| **Class** | `Balance` | Most SDK operations - has utility methods |
|
|
125
|
+
| **Proto** | `proto.Balance` | Blockchain serialization (strings only) |
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Balance, UintRange } from 'bitbadgesjs-sdk';
|
|
129
|
+
|
|
130
|
+
// Create instances with classes
|
|
131
|
+
const balance = new Balance({
|
|
132
|
+
amount: 100n,
|
|
133
|
+
badgeIds: [{ start: 1n, end: 10n }],
|
|
134
|
+
ownershipTimes: [{ start: 1n, end: 1000n }]
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Convert between number types
|
|
138
|
+
const stringBalance = balance.convert(Stringify);
|
|
139
|
+
|
|
140
|
+
// Convert to proto for blockchain
|
|
141
|
+
const protoBalance = balance.toProto();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Common Patterns
|
|
145
|
+
|
|
146
|
+
### Pagination
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
let bookmark = '';
|
|
150
|
+
let hasMore = true;
|
|
151
|
+
|
|
152
|
+
while (hasMore) {
|
|
153
|
+
const response = await api.getTokenActivity('1', '1', { bookmark });
|
|
154
|
+
|
|
155
|
+
// Process results
|
|
156
|
+
console.log(response.activity);
|
|
157
|
+
|
|
158
|
+
// Get next page
|
|
159
|
+
hasMore = response.pagination.hasMore;
|
|
160
|
+
bookmark = response.pagination.bookmark;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Error Handling
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
try {
|
|
168
|
+
const response = await api.getCollections({ collectionsToFetch: [{ collectionId: '1' }] });
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error.errorMessage) {
|
|
171
|
+
console.error('API Error:', error.errorMessage);
|
|
172
|
+
}
|
|
173
|
+
if (error.unauthorized) {
|
|
174
|
+
console.error('Authentication required');
|
|
175
|
+
}
|
|
59
176
|
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Address Utilities
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { convertToBitBadgesAddress, isAddressValid } from 'bitbadgesjs-sdk';
|
|
183
|
+
|
|
184
|
+
// Validate a BitBadges address
|
|
185
|
+
const isValid = isAddressValid('bb1abc...');
|
|
186
|
+
|
|
187
|
+
// Convert to BitBadges format (bb-prefixed only)
|
|
188
|
+
const bbAddress = convertToBitBadgesAddress('bb1abc...');
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Module Structure
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
bitbadgesjs-sdk/
|
|
195
|
+
├── core/ # Balance, UintRange, Approvals, Permissions
|
|
196
|
+
├── api-indexer/ # BitBadgesAPI client and response types
|
|
197
|
+
├── transactions/ # Message builders (MsgTransferTokens, etc.)
|
|
198
|
+
├── address-converter/ # Address utilities
|
|
199
|
+
├── interfaces/ # TypeScript type definitions
|
|
200
|
+
├── proto/ # Protocol buffer types
|
|
201
|
+
├── common/ # Number conversion utilities
|
|
202
|
+
└── gamm/ # AMM pool utilities
|
|
203
|
+
```
|
|
60
204
|
|
|
61
|
-
|
|
62
|
-
const broadcastPost = await fetch(
|
|
63
|
-
broadcastEndpoint,
|
|
64
|
-
postOptions,
|
|
65
|
-
)
|
|
205
|
+
### Key Exports
|
|
66
206
|
|
|
67
|
-
|
|
207
|
+
```typescript
|
|
208
|
+
// API Client
|
|
209
|
+
import { BitBadgesAPI } from 'bitbadgesjs-sdk';
|
|
210
|
+
|
|
211
|
+
// Number Conversion
|
|
212
|
+
import { BigIntify, Stringify, Numberify } from 'bitbadgesjs-sdk';
|
|
213
|
+
|
|
214
|
+
// Core Classes
|
|
215
|
+
import { Balance, UintRange, Transfer, CollectionApproval } from 'bitbadgesjs-sdk';
|
|
216
|
+
|
|
217
|
+
// Address Utilities
|
|
218
|
+
import { convertToBitBadgesAddress, isAddressValid } from 'bitbadgesjs-sdk';
|
|
219
|
+
|
|
220
|
+
// Transaction Messages
|
|
221
|
+
import { MsgTransferTokens, MsgCreateCollection } from 'bitbadgesjs-sdk';
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Version Compatibility
|
|
225
|
+
|
|
226
|
+
| BitBadges Chain | SDK Version | Status |
|
|
227
|
+
|-----------------|-------------|--------|
|
|
228
|
+
| v25 | 0.30.x | Current |
|
|
229
|
+
| v24 | 0.29.x | Supported |
|
|
230
|
+
| v23 | 0.28.x | Supported |
|
|
231
|
+
| v22 | 0.27.x | Supported |
|
|
232
|
+
| v21 | 0.26.x | Supported |
|
|
233
|
+
| v20 | 0.25.x | Supported |
|
|
234
|
+
| v19 | 0.24.x | Supported |
|
|
235
|
+
| v18 | 0.23.x | Supported |
|
|
236
|
+
| v16 | 0.21.x | Supported |
|
|
237
|
+
| v14-15 | 0.20.x | Supported |
|
|
238
|
+
| v13 | 0.19.x | Supported |
|
|
239
|
+
| v12 | 0.18.x | Supported |
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Install specific version for your chain
|
|
243
|
+
npm install bitbadgesjs-sdk@^0.30.0
|
|
68
244
|
```
|
|
69
245
|
|
|
70
|
-
|
|
246
|
+
## Troubleshooting
|
|
247
|
+
|
|
248
|
+
### "BigInt is not defined"
|
|
249
|
+
Ensure you're running Node.js 10.4+ or a modern browser. BigInt is required.
|
|
250
|
+
|
|
251
|
+
### Precision loss with large numbers
|
|
252
|
+
Always use `BigIntify` instead of `Numberify` for collection IDs and token IDs.
|
|
253
|
+
|
|
254
|
+
### Browser: "process is not defined"
|
|
255
|
+
This shouldn't occur - the SDK checks for `process` existence. If it does, ensure you're using the latest SDK version.
|
|
256
|
+
|
|
257
|
+
### API authentication errors
|
|
258
|
+
- Verify your API key at https://bitbadges.io/developer
|
|
259
|
+
- In browsers, pass `apiKey` explicitly (env vars don't work)
|
|
260
|
+
- For authenticated endpoints, use `api.setAccessToken(token)`
|
|
261
|
+
|
|
262
|
+
### Transaction failures
|
|
263
|
+
1. Always simulate first: `await api.simulateTx(payload)`
|
|
264
|
+
2. Verify account has sufficient balance for fees
|
|
265
|
+
3. Check sequence number is correct
|
|
266
|
+
|
|
267
|
+
## Additional Resources
|
|
268
|
+
|
|
269
|
+
- **Detailed Patterns & Examples**: See [AI_AGENT_GUIDE.md](./AI_AGENT_GUIDE.md) for comprehensive patterns
|
|
270
|
+
- **API Documentation**: https://docs.bitbadges.io/for-developers/bitbadges-api/api
|
|
271
|
+
- **GitHub**: https://github.com/bitbadges/bitbadgesjs
|
|
272
|
+
- **Broadcast Helper**: https://bitbadges.io/dev/broadcast
|
|
273
|
+
|
|
274
|
+
### Reference Implementations
|
|
275
|
+
|
|
276
|
+
- [BitBadges Frontend](https://github.com/BitBadges/bitbadges-frontend) - Next.js web app
|
|
277
|
+
- [BitBadges Indexer](https://github.com/BitBadges/bitbadges-indexer) - Express.js API
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
See [LICENSE](./LICENSE) for details.
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,MAAM,IAAI,MAAM,CAAC;KAClB;CACF;AAaD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAEjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,MAAM,IAAI,MAAM,CAAC;KAClB;CACF;AAaD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAEjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -55,4 +55,5 @@ __exportStar(require("./transactions/index.js"), exports);
|
|
|
55
55
|
__exportStar(require("./address-converter/index.js"), exports);
|
|
56
56
|
__exportStar(require("./node-rest-api/index.js"), exports);
|
|
57
57
|
__exportStar(require("./gamm/index.js"), exports);
|
|
58
|
+
__exportStar(require("./signing/index.js"), exports);
|
|
58
59
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG;IACxB,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;AACzB,CAAC,CAAC;AAGF,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;AAErC,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,MAAM,CAAC;AAC3C,CAAC;AAED,kDAAgC;AAChC,yDAAuC;AACvC,oDAAkC;AAClC,wDAAsC;AACtC,0DAA0C;AAC1C,mDAAiC;AAEjC,0DAAwC;AACxC,+DAA6C;AAC7C,2DAAyC;AACzC,kDAAgC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG;IACxB,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;AACzB,CAAC,CAAC;AAGF,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;AAErC,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,MAAM,CAAC;AAC3C,CAAC;AAED,kDAAgC;AAChC,yDAAuC;AACvC,oDAAkC;AAClC,wDAAsC;AACtC,0DAA0C;AAC1C,mDAAiC;AAEjC,0DAAwC;AACxC,+DAA6C;AAC7C,2DAAyC;AACzC,kDAAgC;AAChC,qDAAmC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AccountInfo, BroadcastResult, SignAndBroadcastOptions, SigningClientOptions, SimulateResult, TransactionMessage } from './types.js';
|
|
2
|
+
export declare class BitBadgesSigningClient {
|
|
3
|
+
private readonly adapter;
|
|
4
|
+
private readonly apiUrl;
|
|
5
|
+
private readonly nodeUrl;
|
|
6
|
+
private readonly testnet;
|
|
7
|
+
private readonly chainIdOverride?;
|
|
8
|
+
private readonly sequenceRetryEnabled;
|
|
9
|
+
private readonly maxSequenceRetries;
|
|
10
|
+
private readonly gasMultiplier;
|
|
11
|
+
private readonly defaultGasLimit;
|
|
12
|
+
private readonly evmPrecompileGasLimit;
|
|
13
|
+
private readonly apiKey?;
|
|
14
|
+
private readonly axiosInstance;
|
|
15
|
+
private cachedAccountInfo;
|
|
16
|
+
constructor(options: SigningClientOptions);
|
|
17
|
+
get address(): string;
|
|
18
|
+
get chainType(): 'cosmos' | 'evm';
|
|
19
|
+
private get chainId();
|
|
20
|
+
getAccountInfo(forceRefresh?: boolean): Promise<AccountInfo>;
|
|
21
|
+
clearCache(): void;
|
|
22
|
+
private calculateFee;
|
|
23
|
+
simulate(messages: TransactionMessage[], options?: {
|
|
24
|
+
memo?: string;
|
|
25
|
+
}): Promise<SimulateResult>;
|
|
26
|
+
private normalizeMessages;
|
|
27
|
+
signAndBroadcast(messages: TransactionMessage[], options?: SignAndBroadcastOptions): Promise<BroadcastResult>;
|
|
28
|
+
private signAndBroadcastCosmos;
|
|
29
|
+
private isSequenceMismatchError;
|
|
30
|
+
private signAndBroadcastEvm;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=BitBadgesSigningClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BitBadgesSigningClient.d.ts","sourceRoot":"","sources":["../../../src/signing/BitBadgesSigningClient.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,oBAAoB,EAEpB,cAAc,EACd,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAmDpB,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAG9C,OAAO,CAAC,iBAAiB,CAA4B;gBAOzC,OAAO,EAAE,oBAAoB;IA4BzC,IAAI,OAAO,IAAI,MAAM,CAOpB;IAKD,IAAI,SAAS,IAAI,QAAQ,GAAG,KAAK,CAEhC;IAKD,OAAO,KAAK,OAAO,GAKlB;IASK,cAAc,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAoChE,UAAU,IAAI,IAAI;IAOlB,OAAO,CAAC,YAAY;IAgBd,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA4CpG,OAAO,CAAC,iBAAiB;IAgBnB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,eAAe,CAAC;YAarG,sBAAsB;IAgHpC,OAAO,CAAC,uBAAuB;YAQjB,mBAAmB;CAkDlC"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BitBadgesSigningClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const converter_js_1 = require("../address-converter/converter.js");
|
|
9
|
+
const constants_js_1 = require("../common/constants.js");
|
|
10
|
+
const account_js_1 = require("../node-rest-api/account.js");
|
|
11
|
+
const base_js_1 = require("../transactions/messages/base.js");
|
|
12
|
+
const DEFAULT_API_URL = 'https://api.bitbadges.io';
|
|
13
|
+
const TESTNET_API_URL = 'https://api.bitbadges.io/testnet';
|
|
14
|
+
const DEFAULT_NODE_URL = 'https://lcd.bitbadges.io';
|
|
15
|
+
const TESTNET_NODE_URL = 'https://lcd-testnet.bitbadges.io';
|
|
16
|
+
const DEFAULT_GAS_LIMIT = 400000;
|
|
17
|
+
const DEFAULT_EVM_PRECOMPILE_GAS_LIMIT = 2000000;
|
|
18
|
+
const DEFAULT_GAS_MULTIPLIER = 1.3;
|
|
19
|
+
const DEFAULT_MAX_SEQUENCE_RETRIES = 3;
|
|
20
|
+
const DEFAULT_FEE_DENOM = 'ubadge';
|
|
21
|
+
const DEFAULT_GAS_PRICE = 0.025;
|
|
22
|
+
class BitBadgesSigningClient {
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.cachedAccountInfo = null;
|
|
25
|
+
this.adapter = options.adapter;
|
|
26
|
+
this.testnet = options.testnet || false;
|
|
27
|
+
this.apiUrl = options.apiUrl || (this.testnet ? TESTNET_API_URL : DEFAULT_API_URL);
|
|
28
|
+
this.nodeUrl = options.nodeUrl || (this.testnet ? TESTNET_NODE_URL : DEFAULT_NODE_URL);
|
|
29
|
+
this.chainIdOverride = options.chainIdOverride;
|
|
30
|
+
this.sequenceRetryEnabled = options.sequenceRetryEnabled !== false;
|
|
31
|
+
this.maxSequenceRetries = options.maxSequenceRetries || DEFAULT_MAX_SEQUENCE_RETRIES;
|
|
32
|
+
this.gasMultiplier = options.gasMultiplier || DEFAULT_GAS_MULTIPLIER;
|
|
33
|
+
this.defaultGasLimit = options.defaultGasLimit || DEFAULT_GAS_LIMIT;
|
|
34
|
+
this.evmPrecompileGasLimit = options.evmPrecompileGasLimit || DEFAULT_EVM_PRECOMPILE_GAS_LIMIT;
|
|
35
|
+
this.apiKey = options.apiKey;
|
|
36
|
+
this.axiosInstance = axios_1.default.create({
|
|
37
|
+
headers: {
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
...(this.apiKey && { 'x-api-key': this.apiKey })
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
get address() {
|
|
44
|
+
const addr = this.adapter.address;
|
|
45
|
+
if (addr.startsWith('0x')) {
|
|
46
|
+
return (0, converter_js_1.convertToBitBadgesAddress)(addr);
|
|
47
|
+
}
|
|
48
|
+
return addr;
|
|
49
|
+
}
|
|
50
|
+
get chainType() {
|
|
51
|
+
return this.adapter.chainType;
|
|
52
|
+
}
|
|
53
|
+
get chainId() {
|
|
54
|
+
if (this.chainIdOverride) {
|
|
55
|
+
return this.chainIdOverride;
|
|
56
|
+
}
|
|
57
|
+
return this.testnet ? constants_js_1.TESTNET_CHAIN_DETAILS.cosmosChainId : constants_js_1.MAINNET_CHAIN_DETAILS.cosmosChainId;
|
|
58
|
+
}
|
|
59
|
+
async getAccountInfo(forceRefresh = false) {
|
|
60
|
+
if (this.cachedAccountInfo && !forceRefresh) {
|
|
61
|
+
return this.cachedAccountInfo;
|
|
62
|
+
}
|
|
63
|
+
const bbAddress = this.address;
|
|
64
|
+
const endpoint = (0, account_js_1.generateEndpointAccount)(bbAddress);
|
|
65
|
+
const response = await this.axiosInstance.get(`${this.nodeUrl}${endpoint}`);
|
|
66
|
+
const baseAccount = response.data.account.base_account;
|
|
67
|
+
let publicKey = baseAccount.pub_key?.key || '';
|
|
68
|
+
if (!publicKey) {
|
|
69
|
+
try {
|
|
70
|
+
publicKey = await this.adapter.getPublicKey();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.cachedAccountInfo = {
|
|
76
|
+
address: bbAddress,
|
|
77
|
+
accountNumber: parseInt(baseAccount.account_number, 10),
|
|
78
|
+
sequence: parseInt(baseAccount.sequence, 10),
|
|
79
|
+
publicKey
|
|
80
|
+
};
|
|
81
|
+
return this.cachedAccountInfo;
|
|
82
|
+
}
|
|
83
|
+
clearCache() {
|
|
84
|
+
this.cachedAccountInfo = null;
|
|
85
|
+
}
|
|
86
|
+
calculateFee(gasLimit) {
|
|
87
|
+
const amount = Math.ceil(gasLimit * DEFAULT_GAS_PRICE);
|
|
88
|
+
return {
|
|
89
|
+
amount: amount.toString(),
|
|
90
|
+
denom: DEFAULT_FEE_DENOM,
|
|
91
|
+
gas: gasLimit.toString()
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async simulate(messages, options) {
|
|
95
|
+
const accountInfo = await this.getAccountInfo();
|
|
96
|
+
if (!accountInfo.publicKey) {
|
|
97
|
+
throw new Error('Public key is required for simulation. Sign a transaction first to register the public key on chain.');
|
|
98
|
+
}
|
|
99
|
+
const protoMessages = this.normalizeMessages(messages);
|
|
100
|
+
const dummySignature = '0'.repeat(128);
|
|
101
|
+
const txContext = {
|
|
102
|
+
testnet: this.testnet,
|
|
103
|
+
chainIdOverride: this.chainIdOverride,
|
|
104
|
+
sender: {
|
|
105
|
+
address: this.address,
|
|
106
|
+
sequence: accountInfo.sequence,
|
|
107
|
+
accountNumber: accountInfo.accountNumber,
|
|
108
|
+
publicKey: accountInfo.publicKey
|
|
109
|
+
},
|
|
110
|
+
fee: this.calculateFee(this.defaultGasLimit),
|
|
111
|
+
memo: options?.memo || ''
|
|
112
|
+
};
|
|
113
|
+
const broadcastBody = (0, base_js_1.createTxBroadcastBody)(txContext, protoMessages, dummySignature);
|
|
114
|
+
const response = await this.axiosInstance.post(`${this.apiUrl}/api/v0/simulate`, JSON.parse(broadcastBody));
|
|
115
|
+
const gasUsed = parseInt(response.data.gas_info?.gas_used || '0', 10);
|
|
116
|
+
const gasLimit = Math.ceil(gasUsed * this.gasMultiplier);
|
|
117
|
+
return {
|
|
118
|
+
gasUsed,
|
|
119
|
+
gasLimit,
|
|
120
|
+
fee: this.calculateFee(gasLimit)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
normalizeMessages(messages) {
|
|
124
|
+
return messages.map((msg) => {
|
|
125
|
+
if (msg && typeof msg.toProto === 'function') {
|
|
126
|
+
return msg.toProto();
|
|
127
|
+
}
|
|
128
|
+
return msg;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
async signAndBroadcast(messages, options) {
|
|
132
|
+
if (this.adapter.chainType === 'evm') {
|
|
133
|
+
return this.signAndBroadcastEvm(messages, options);
|
|
134
|
+
}
|
|
135
|
+
return this.signAndBroadcastCosmos(messages, options);
|
|
136
|
+
}
|
|
137
|
+
async signAndBroadcastCosmos(messages, options, retryCount = 0) {
|
|
138
|
+
const accountInfo = await this.getAccountInfo();
|
|
139
|
+
if (!accountInfo.publicKey) {
|
|
140
|
+
const pubKey = await this.adapter.getPublicKey();
|
|
141
|
+
if (!pubKey) {
|
|
142
|
+
throw new Error('Public key is required for Cosmos transactions');
|
|
143
|
+
}
|
|
144
|
+
accountInfo.publicKey = pubKey;
|
|
145
|
+
this.cachedAccountInfo = accountInfo;
|
|
146
|
+
}
|
|
147
|
+
const protoMessages = this.normalizeMessages(messages);
|
|
148
|
+
let fee;
|
|
149
|
+
if (options?.fee) {
|
|
150
|
+
fee = options.fee;
|
|
151
|
+
}
|
|
152
|
+
else if (options?.simulate !== false) {
|
|
153
|
+
try {
|
|
154
|
+
const simResult = await this.simulate(messages, { memo: options?.memo });
|
|
155
|
+
const multiplier = options?.gasMultiplier || this.gasMultiplier;
|
|
156
|
+
const adjustedGas = Math.ceil(simResult.gasUsed * multiplier);
|
|
157
|
+
fee = this.calculateFee(adjustedGas);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
fee = this.calculateFee(this.defaultGasLimit);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
fee = this.calculateFee(this.defaultGasLimit);
|
|
165
|
+
}
|
|
166
|
+
const txContext = {
|
|
167
|
+
testnet: this.testnet,
|
|
168
|
+
chainIdOverride: this.chainIdOverride,
|
|
169
|
+
sender: {
|
|
170
|
+
address: this.address,
|
|
171
|
+
sequence: accountInfo.sequence,
|
|
172
|
+
accountNumber: accountInfo.accountNumber,
|
|
173
|
+
publicKey: accountInfo.publicKey
|
|
174
|
+
},
|
|
175
|
+
fee,
|
|
176
|
+
memo: options?.memo || ''
|
|
177
|
+
};
|
|
178
|
+
const payload = (0, base_js_1.createTransactionPayload)(txContext, protoMessages);
|
|
179
|
+
if (!this.adapter.signDirect) {
|
|
180
|
+
throw new Error('Cosmos adapter must implement signDirect');
|
|
181
|
+
}
|
|
182
|
+
const signResult = await this.adapter.signDirect(payload, accountInfo.accountNumber);
|
|
183
|
+
const broadcastBody = (0, base_js_1.createTxBroadcastBody)(txContext, protoMessages, signResult.signature);
|
|
184
|
+
try {
|
|
185
|
+
const response = await this.axiosInstance.post(`${this.apiUrl}/api/v0/broadcast`, JSON.parse(broadcastBody));
|
|
186
|
+
const txResponse = response.data.tx_response;
|
|
187
|
+
const code = txResponse?.code || 0;
|
|
188
|
+
if (code !== 0 && this.isSequenceMismatchError(txResponse?.raw_log)) {
|
|
189
|
+
if (this.sequenceRetryEnabled && retryCount < this.maxSequenceRetries) {
|
|
190
|
+
this.clearCache();
|
|
191
|
+
return this.signAndBroadcastCosmos(messages, options, retryCount + 1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (code === 0 && this.cachedAccountInfo) {
|
|
195
|
+
this.cachedAccountInfo.sequence += 1;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
txHash: txResponse?.txhash || '',
|
|
199
|
+
rawResponse: response.data,
|
|
200
|
+
success: code === 0,
|
|
201
|
+
error: code !== 0 ? txResponse?.raw_log : undefined,
|
|
202
|
+
code
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
const rawLog = error?.response?.data?.tx_response?.raw_log || error?.message || '';
|
|
207
|
+
if (this.isSequenceMismatchError(rawLog)) {
|
|
208
|
+
if (this.sequenceRetryEnabled && retryCount < this.maxSequenceRetries) {
|
|
209
|
+
this.clearCache();
|
|
210
|
+
return this.signAndBroadcastCosmos(messages, options, retryCount + 1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
txHash: '',
|
|
215
|
+
rawResponse: error?.response?.data,
|
|
216
|
+
success: false,
|
|
217
|
+
error: error?.message || 'Unknown error',
|
|
218
|
+
code: error?.response?.data?.tx_response?.code || -1
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
isSequenceMismatchError(message) {
|
|
223
|
+
if (!message)
|
|
224
|
+
return false;
|
|
225
|
+
return message.includes('account sequence mismatch') || message.includes('incorrect account sequence');
|
|
226
|
+
}
|
|
227
|
+
async signAndBroadcastEvm(messages, options) {
|
|
228
|
+
if (!this.adapter.sendEvmTransaction) {
|
|
229
|
+
throw new Error('EVM adapter must implement sendEvmTransaction');
|
|
230
|
+
}
|
|
231
|
+
const protoMessages = this.normalizeMessages(messages);
|
|
232
|
+
const evmAddress = this.adapter.address;
|
|
233
|
+
const txContext = {
|
|
234
|
+
testnet: this.testnet,
|
|
235
|
+
chainIdOverride: this.chainIdOverride,
|
|
236
|
+
evmAddress,
|
|
237
|
+
fee: this.calculateFee(this.evmPrecompileGasLimit),
|
|
238
|
+
memo: options?.memo || ''
|
|
239
|
+
};
|
|
240
|
+
const payload = (0, base_js_1.createTransactionPayload)(txContext, protoMessages);
|
|
241
|
+
if (!payload.evmTx) {
|
|
242
|
+
throw new Error('Messages are not supported for EVM precompile conversion');
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const txHash = await this.adapter.sendEvmTransaction({
|
|
246
|
+
to: payload.evmTx.to,
|
|
247
|
+
data: payload.evmTx.data,
|
|
248
|
+
value: payload.evmTx.value,
|
|
249
|
+
gasLimit: this.evmPrecompileGasLimit
|
|
250
|
+
});
|
|
251
|
+
return {
|
|
252
|
+
txHash,
|
|
253
|
+
rawResponse: { evmTx: payload.evmTx },
|
|
254
|
+
success: true,
|
|
255
|
+
code: 0
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
return {
|
|
260
|
+
txHash: '',
|
|
261
|
+
rawResponse: null,
|
|
262
|
+
success: false,
|
|
263
|
+
error: error?.message || 'EVM transaction failed',
|
|
264
|
+
code: -1
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.BitBadgesSigningClient = BitBadgesSigningClient;
|
|
270
|
+
//# sourceMappingURL=BitBadgesSigningClient.js.map
|