@smartledger/bsv 3.4.2 → 3.4.4
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/CHANGELOG.md +336 -0
- package/README.md +72 -72
- package/SECURITY.md +88 -0
- package/bin/cli.js +13 -8
- package/bsv-covenant.min.js +4 -4
- package/bsv-gdaf.min.js +5 -5
- package/bsv-ltp.min.js +7 -7
- package/bsv-smartcontract.min.js +5 -5
- package/bsv.bundle.js +5 -5
- package/bsv.d.ts +486 -9
- package/bsv.min.js +5 -5
- package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +2 -2
- package/docs/MODULE_REFERENCE_COMPLETE.md +61 -58
- package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +3 -3
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +30 -30
- package/docs/getting-started/QUICK_START.md +18 -18
- package/docs/migration/FROM_BSV_1_5_6.md +16 -10
- package/gdaf-entry.js +1 -2
- package/index.js +20 -7
- package/lib/smart_contract/covenant.js +10 -1
- package/lib/smartutxo.js +20 -12
- package/lib/transaction/transaction.js +7 -0
- package/ltp-entry.js +1 -2
- package/package.json +3 -3
- package/utilities/blockchain-state.js +32 -23
- package/demos/README.md +0 -188
- package/demos/architecture_demo.js +0 -247
- package/demos/browser-test.html +0 -1208
- package/demos/bsv_wallet_demo.js +0 -242
- package/demos/complete_ltp_demo.js +0 -511
- package/demos/debug_tools_demo.js +0 -87
- package/demos/demo_features.js +0 -123
- package/demos/easy_interface_demo.js +0 -109
- package/demos/ecies_demo.js +0 -182
- package/demos/gdaf_demo.js +0 -237
- package/demos/ltp_demo.js +0 -361
- package/demos/ltp_primitives_demo.js +0 -403
- package/demos/message_demo.js +0 -209
- package/demos/preimage_separation_demo.js +0 -383
- package/demos/script_helper_demo.js +0 -289
- package/demos/security_demo.js +0 -287
- package/demos/shamir_demo.js +0 -121
- package/demos/simple_demo.js +0 -204
- package/demos/simple_p2pkh_demo.js +0 -169
- package/demos/simple_utxo_preimage_demo.js +0 -196
- package/demos/smart_contract_demo.html +0 -1347
- package/demos/smart_contract_demo.js +0 -910
- package/demos/utxo_generator_demo.js +0 -244
- package/demos/validation_pipeline_demo.js +0 -155
- package/demos/web3keys.html +0 -740
- package/examples/README.md +0 -200
- package/examples/basic/transaction-creation.js +0 -534
- package/examples/basic/transaction_signature_api_gap.js +0 -178
- package/examples/complete_workflow_demo.js +0 -783
- package/examples/covenants/advanced_covenant_demo.js +0 -219
- package/examples/covenants/covenant_interface_demo.js +0 -270
- package/examples/covenants/covenant_manual_signature_resolved.js +0 -212
- package/examples/covenants/covenant_signature_template.js +0 -117
- package/examples/covenants2/covenant_bidirectional_example.js +0 -262
- package/examples/covenants2/covenant_utils_demo.js +0 -120
- package/examples/covenants2/preimage_covenant_utils.js +0 -287
- package/examples/covenants2/production_integration.js +0 -256
- package/examples/data/covenant_utxos.json +0 -28
- package/examples/data/utxos.json +0 -26
- package/examples/definitive_working_demo.js +0 -261
- package/examples/final_working_contracts.js +0 -338
- package/examples/legacy/README.md +0 -11
- package/examples/legacy/smart_contract_test_integration.js +0 -269
- package/examples/legacy/test_builtin_verify.js +0 -117
- package/examples/legacy/test_debug_integration.js +0 -71
- package/examples/legacy/test_ecdsa_little.js +0 -70
- package/examples/legacy/test_shamir.js +0 -221
- package/examples/legacy/test_smartverify_der.js +0 -110
- package/examples/preimage/README.md +0 -178
- package/examples/preimage/extract_preimage_bidirectional.js +0 -421
- package/examples/preimage/generate_sample_preimage.js +0 -208
- package/examples/preimage/generate_sighash_examples.js +0 -152
- package/examples/preimage/parse_preimage.js +0 -117
- package/examples/preimage/test_preimage_extractor.js +0 -53
- package/examples/preimage/test_varint_extraction.js +0 -95
- package/examples/scripts/custom_script_helper_example.js +0 -273
- package/examples/scripts/script_interpreter.js +0 -193
- package/examples/smart_contract/complete_workflow_demo.js +0 -343
- package/examples/smart_contract/covenant_builder_demo.js +0 -176
- package/examples/smart_contract/script_testing_integration.js +0 -198
- package/examples/smart_contract_templates.js +0 -718
- package/examples/working_smart_contracts.js +0 -348
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Working Smart Contract Examples - Fixed Version
|
|
3
|
-
* ==============================================
|
|
4
|
-
*
|
|
5
|
-
* This file contains working, tested smart contract examples that properly
|
|
6
|
-
* integrate with smartledger-bsv's preimage validation system.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const bsv = require('../index.js')
|
|
10
|
-
|
|
11
|
-
// Enable colored output if available
|
|
12
|
-
let chalk
|
|
13
|
-
try {
|
|
14
|
-
chalk = require('chalk')
|
|
15
|
-
} catch (e) {
|
|
16
|
-
chalk = {
|
|
17
|
-
green: (text) => `✅ ${text}`,
|
|
18
|
-
red: (text) => `❌ ${text}`,
|
|
19
|
-
yellow: (text) => `⚠️ ${text}`,
|
|
20
|
-
blue: (text) => `ℹ️ ${text}`,
|
|
21
|
-
magenta: (text) => `🔮 ${text}`,
|
|
22
|
-
cyan: (text) => `🌊 ${text}`,
|
|
23
|
-
bold: (text) => `**${text}**`
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
console.log(chalk.bold.blue('\n🔧 Working Smart Contract Examples (Fixed)\n'))
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* WorkingAmountContract - A properly functioning amount validation contract
|
|
31
|
-
*/
|
|
32
|
-
class WorkingAmountContract {
|
|
33
|
-
constructor(expectedAmount) {
|
|
34
|
-
this.expectedAmount = expectedAmount
|
|
35
|
-
this.privateKey = new bsv.PrivateKey()
|
|
36
|
-
|
|
37
|
-
// Create the contract script using the quick covenant method
|
|
38
|
-
this.script = this._createWorkingScript()
|
|
39
|
-
this.address = bsv.SmartContract.utils.createCovenantAddress(this.script)
|
|
40
|
-
|
|
41
|
-
console.log(chalk.green(`✅ WorkingAmountContract created`))
|
|
42
|
-
console.log(chalk.blue(` Expected Amount: ${expectedAmount} satoshis`))
|
|
43
|
-
console.log(chalk.blue(` Contract Address: ${this.address.toString()}`))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
_createWorkingScript() {
|
|
47
|
-
// Use the createQuickCovenant method which is known to work
|
|
48
|
-
const covenant = bsv.SmartContract.createQuickCovenant('value_lock', {
|
|
49
|
-
value: this.expectedAmount
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// Convert the ASM to a proper BSV Script
|
|
53
|
-
return bsv.Script.fromASM(covenant.asm)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Test validation with a real preimage
|
|
57
|
-
validatePayment(preimageHex) {
|
|
58
|
-
try {
|
|
59
|
-
console.log(chalk.yellow('🔍 Testing payment validation with working script...'))
|
|
60
|
-
|
|
61
|
-
const result = bsv.SmartContract.testScript(
|
|
62
|
-
preimageHex,
|
|
63
|
-
this.script.toHex(),
|
|
64
|
-
{ verbose: true }
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
if (result.valid) {
|
|
68
|
-
console.log(chalk.green('✅ Payment validation PASSED'))
|
|
69
|
-
} else {
|
|
70
|
-
console.log(chalk.red('❌ Payment validation FAILED'))
|
|
71
|
-
console.log(chalk.red(` Error: ${result.error || 'Unknown error'}`))
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
success: result.valid,
|
|
76
|
-
error: result.error,
|
|
77
|
-
details: result
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.log(chalk.red('❌ Validation error:', error.message))
|
|
81
|
-
return {
|
|
82
|
-
success: false,
|
|
83
|
-
error: error.message
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Create a proper test preimage for this contract
|
|
89
|
-
createTestPreimage(inputAmount) {
|
|
90
|
-
try {
|
|
91
|
-
console.log(chalk.yellow('📝 Creating test preimage...'))
|
|
92
|
-
|
|
93
|
-
// Create a mock transaction that would spend from this contract
|
|
94
|
-
const mockTx = new bsv.Transaction()
|
|
95
|
-
|
|
96
|
-
// Add input from contract (mock)
|
|
97
|
-
mockTx.addInput({
|
|
98
|
-
prevTxId: 'a'.repeat(64),
|
|
99
|
-
outputIndex: 0,
|
|
100
|
-
script: this.script.toHex(),
|
|
101
|
-
sequenceNumber: 0xffffffff
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
// Add output with the input amount
|
|
105
|
-
mockTx.addOutput({
|
|
106
|
-
script: bsv.Script.buildPublicKeyHashOut(new bsv.Address('1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2')).toHex(),
|
|
107
|
-
satoshis: inputAmount
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
// Generate preimage
|
|
111
|
-
const preimage = bsv.Transaction.sighash.sighashPreimage(
|
|
112
|
-
mockTx,
|
|
113
|
-
bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID,
|
|
114
|
-
0,
|
|
115
|
-
this.script,
|
|
116
|
-
new bsv.crypto.BN(inputAmount + 1000) // Contract input amount
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
console.log(chalk.blue(` Generated preimage: ${preimage.toString('hex').substring(0, 64)}...`))
|
|
120
|
-
return preimage.toString('hex')
|
|
121
|
-
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.log(chalk.red('❌ Preimage generation error:', error.message))
|
|
124
|
-
return null
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Complete test of the contract
|
|
129
|
-
runCompleteTest() {
|
|
130
|
-
console.log(chalk.cyan('\n🧪 Running Complete Contract Test'))
|
|
131
|
-
console.log(chalk.cyan('==================================='))
|
|
132
|
-
|
|
133
|
-
// Test with correct amount
|
|
134
|
-
console.log(chalk.yellow('\n1. Testing with CORRECT amount'))
|
|
135
|
-
const correctPreimage = this.createTestPreimage(this.expectedAmount)
|
|
136
|
-
if (correctPreimage) {
|
|
137
|
-
const correctResult = this.validatePayment(correctPreimage)
|
|
138
|
-
console.log(chalk.blue(` Result: ${correctResult.success ? 'PASS' : 'FAIL'}`))
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Test with incorrect amount
|
|
142
|
-
console.log(chalk.yellow('\n2. Testing with INCORRECT amount'))
|
|
143
|
-
const incorrectPreimage = this.createTestPreimage(this.expectedAmount - 10000)
|
|
144
|
-
if (incorrectPreimage) {
|
|
145
|
-
const incorrectResult = this.validatePayment(incorrectPreimage)
|
|
146
|
-
console.log(chalk.blue(` Result: ${incorrectResult.success ? 'UNEXPECTED PASS' : 'EXPECTED FAIL'}`))
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
console.log(chalk.cyan('\n✅ Complete test finished'))
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
getContractInfo() {
|
|
153
|
-
return {
|
|
154
|
-
expectedAmount: this.expectedAmount,
|
|
155
|
-
address: this.address.toString(),
|
|
156
|
-
script: {
|
|
157
|
-
hex: this.script.toHex(),
|
|
158
|
-
asm: this.script.toASM(),
|
|
159
|
-
size: this.script.toBuffer().length
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* SimpleFieldExtractionDemo - Shows how field extraction actually works
|
|
167
|
-
*/
|
|
168
|
-
class SimpleFieldExtractionDemo {
|
|
169
|
-
constructor() {
|
|
170
|
-
console.log(chalk.bold.magenta('\n🔬 Field Extraction Demo\n'))
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
demonstrateFieldExtraction() {
|
|
174
|
-
console.log(chalk.cyan('Testing Field Extraction with Real Preimage'))
|
|
175
|
-
console.log(chalk.cyan('===========================================\n'))
|
|
176
|
-
|
|
177
|
-
// Create a simple transaction to get a real preimage
|
|
178
|
-
try {
|
|
179
|
-
const tx = new bsv.Transaction()
|
|
180
|
-
.from({
|
|
181
|
-
txId: 'a'.repeat(64),
|
|
182
|
-
outputIndex: 0,
|
|
183
|
-
script: bsv.Script.buildPublicKeyHashOut(new bsv.Address('1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2')).toHex(),
|
|
184
|
-
satoshis: 100000
|
|
185
|
-
})
|
|
186
|
-
.to('1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2', 90000)
|
|
187
|
-
|
|
188
|
-
const preimage = bsv.Transaction.sighash.sighashPreimage(
|
|
189
|
-
tx,
|
|
190
|
-
bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID,
|
|
191
|
-
0,
|
|
192
|
-
bsv.Script.buildPublicKeyHashOut(new bsv.Address('1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2')),
|
|
193
|
-
new bsv.crypto.BN(100000)
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
console.log(chalk.blue(`Generated preimage: ${preimage.toString('hex').substring(0, 64)}...`))
|
|
197
|
-
|
|
198
|
-
// Test field extraction
|
|
199
|
-
const fields = ['value', 'nVersion', 'nLocktime', 'hashOutputs']
|
|
200
|
-
|
|
201
|
-
fields.forEach(field => {
|
|
202
|
-
console.log(chalk.yellow(`\nTesting ${field} extraction:`))
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
const result = bsv.SmartContract.testFieldExtraction(
|
|
206
|
-
preimage.toString('hex'),
|
|
207
|
-
field
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
if (result.success) {
|
|
211
|
-
console.log(chalk.green(`✅ ${field} extraction successful`))
|
|
212
|
-
if (result.fieldExtraction) {
|
|
213
|
-
console.log(chalk.blue(` Value: ${result.fieldExtraction.value}`))
|
|
214
|
-
if (result.fieldExtraction.interpretation) {
|
|
215
|
-
console.log(chalk.blue(` Interpreted: ${result.fieldExtraction.interpretation.description || result.fieldExtraction.interpretation.satoshis || 'N/A'}`))
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} else {
|
|
219
|
-
console.log(chalk.red(`❌ ${field} extraction failed`))
|
|
220
|
-
console.log(chalk.red(` Error: ${result.error || 'Unknown error'}`))
|
|
221
|
-
}
|
|
222
|
-
} catch (error) {
|
|
223
|
-
console.log(chalk.red(`❌ ${field} extraction error: ${error.message}`))
|
|
224
|
-
}
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
} catch (error) {
|
|
228
|
-
console.log(chalk.red('❌ Demo error:', error.message))
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* CovenantBuilderTest - Test the covenant builder functionality
|
|
235
|
-
*/
|
|
236
|
-
class CovenantBuilderTest {
|
|
237
|
-
constructor() {
|
|
238
|
-
console.log(chalk.bold.magenta('\n🏗️ Covenant Builder Test\n'))
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
testCovenantBuilder() {
|
|
242
|
-
console.log(chalk.cyan('Testing CovenantBuilder Functionality'))
|
|
243
|
-
console.log(chalk.cyan('===================================\n'))
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
// Test 1: Simple covenant using CovenantTemplates
|
|
247
|
-
console.log(chalk.yellow('1. Testing CovenantTemplates.valueLock'))
|
|
248
|
-
|
|
249
|
-
const valueLockCovenant = bsv.SmartContract.CovenantTemplates.valueLock('50c3000000000000') // 50000 satoshis in little-endian hex
|
|
250
|
-
const builtCovenant = valueLockCovenant.build()
|
|
251
|
-
|
|
252
|
-
console.log(chalk.blue(` ASM: ${builtCovenant.cleanedASM}`))
|
|
253
|
-
console.log(chalk.blue(` Hex: ${builtCovenant.hex}`))
|
|
254
|
-
console.log(chalk.blue(` Size: ${builtCovenant.size} operations`))
|
|
255
|
-
|
|
256
|
-
// Test 2: Custom covenant using CovenantBuilder
|
|
257
|
-
console.log(chalk.yellow('\n2. Testing Custom CovenantBuilder'))
|
|
258
|
-
|
|
259
|
-
const customBuilder = new bsv.SmartContract.CovenantBuilder()
|
|
260
|
-
const customCovenant = customBuilder
|
|
261
|
-
.comment('Simple value validation')
|
|
262
|
-
.extractField('value')
|
|
263
|
-
.push(100000)
|
|
264
|
-
.greaterThanOrEqual()
|
|
265
|
-
.verify()
|
|
266
|
-
.build()
|
|
267
|
-
|
|
268
|
-
console.log(chalk.blue(` Custom ASM: ${customCovenant.cleanedASM}`))
|
|
269
|
-
console.log(chalk.blue(` Custom Hex: ${customCovenant.hex}`))
|
|
270
|
-
|
|
271
|
-
// Test 3: Quick covenant creation
|
|
272
|
-
console.log(chalk.yellow('\n3. Testing Quick Covenant Creation'))
|
|
273
|
-
|
|
274
|
-
const quickCovenant = bsv.SmartContract.createQuickCovenant('value_lock', {
|
|
275
|
-
value: 75000
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
console.log(chalk.blue(` Quick ASM: ${quickCovenant.asm}`))
|
|
279
|
-
console.log(chalk.blue(` Quick Hex: ${quickCovenant.hex}`))
|
|
280
|
-
|
|
281
|
-
console.log(chalk.green('\n✅ All covenant builder tests completed'))
|
|
282
|
-
|
|
283
|
-
} catch (error) {
|
|
284
|
-
console.log(chalk.red('❌ Covenant builder test error:', error.message))
|
|
285
|
-
console.error(error.stack)
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Main execution function
|
|
292
|
-
*/
|
|
293
|
-
async function main() {
|
|
294
|
-
try {
|
|
295
|
-
console.log(chalk.bold.blue('Working Smart Contract Examples'))
|
|
296
|
-
console.log(chalk.blue('===============================\n'))
|
|
297
|
-
|
|
298
|
-
// 1. Test field extraction first
|
|
299
|
-
const fieldDemo = new SimpleFieldExtractionDemo()
|
|
300
|
-
fieldDemo.demonstrateFieldExtraction()
|
|
301
|
-
|
|
302
|
-
// 2. Test covenant builder
|
|
303
|
-
const builderTest = new CovenantBuilderTest()
|
|
304
|
-
builderTest.testCovenantBuilder()
|
|
305
|
-
|
|
306
|
-
// 3. Test working contract
|
|
307
|
-
console.log(chalk.bold.magenta('\n💰 Working Amount Contract Test\n'))
|
|
308
|
-
|
|
309
|
-
const workingContract = new WorkingAmountContract(100000) // 100k sats
|
|
310
|
-
workingContract.runCompleteTest()
|
|
311
|
-
|
|
312
|
-
// 4. Show contract info
|
|
313
|
-
console.log(chalk.bold.yellow('\n📋 Contract Information'))
|
|
314
|
-
console.log(chalk.yellow('======================='))
|
|
315
|
-
|
|
316
|
-
const info = workingContract.getContractInfo()
|
|
317
|
-
console.log(chalk.blue(`Expected Amount: ${info.expectedAmount} satoshis`))
|
|
318
|
-
console.log(chalk.blue(`Contract Address: ${info.address}`))
|
|
319
|
-
console.log(chalk.blue(`Script Size: ${info.script.size} bytes`))
|
|
320
|
-
console.log(chalk.blue(`Script ASM: ${info.script.asm}`))
|
|
321
|
-
|
|
322
|
-
console.log(chalk.bold.green('\n🎉 All working examples completed successfully!'))
|
|
323
|
-
|
|
324
|
-
// Usage instructions
|
|
325
|
-
console.log(chalk.bold.yellow('\n📚 Key Learnings:'))
|
|
326
|
-
console.log(chalk.yellow('1. Use bsv.SmartContract.createQuickCovenant() for simple contracts'))
|
|
327
|
-
console.log(chalk.yellow('2. Field extraction works with proper preimage format'))
|
|
328
|
-
console.log(chalk.yellow('3. CovenantBuilder.build() returns an object, not a Script'))
|
|
329
|
-
console.log(chalk.yellow('4. Convert covenant ASM to Script using bsv.Script.fromASM()'))
|
|
330
|
-
console.log(chalk.yellow('5. Test with real preimages for accurate validation'))
|
|
331
|
-
|
|
332
|
-
} catch (error) {
|
|
333
|
-
console.error(chalk.bold.red('\nDemo Error:'), error.message)
|
|
334
|
-
console.error(chalk.red('Stack:'), error.stack)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Export for use in other modules
|
|
339
|
-
module.exports = {
|
|
340
|
-
WorkingAmountContract,
|
|
341
|
-
SimpleFieldExtractionDemo,
|
|
342
|
-
CovenantBuilderTest
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Run demo if executed directly
|
|
346
|
-
if (require.main === module) {
|
|
347
|
-
main().catch(console.error)
|
|
348
|
-
}
|