@smartledger/bsv 3.3.3 → 3.3.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 +20 -7
- package/README.md +18 -1
- package/bsv-covenant.min.js +5 -5
- package/bsv-gdaf.min.js +4 -4
- package/bsv-ltp.min.js +4 -4
- package/bsv-mnemonic.min.js +4 -4
- package/bsv-smartcontract.min.js +4 -4
- package/bsv.bundle.js +4 -4
- package/bsv.min.js +4 -4
- package/demos/README.md +188 -0
- package/demos/architecture_demo.js +247 -0
- package/demos/bsv_wallet_demo.js +242 -0
- package/demos/complete_ltp_demo.js +511 -0
- package/demos/debug_tools_demo.js +87 -0
- package/demos/demo_features.js +123 -0
- package/demos/easy_interface_demo.js +109 -0
- package/demos/ecies_demo.js +182 -0
- package/demos/gdaf_core_test.js +131 -0
- package/demos/gdaf_demo.js +237 -0
- package/demos/ltp_demo.js +361 -0
- package/demos/ltp_primitives_demo.js +403 -0
- package/demos/message_demo.js +209 -0
- package/demos/preimage_separation_demo.js +383 -0
- package/demos/script_helper_demo.js +289 -0
- package/demos/security_demo.js +287 -0
- package/demos/shamir_demo.js +121 -0
- package/demos/simple_demo.js +204 -0
- package/demos/simple_p2pkh_demo.js +169 -0
- package/demos/simple_utxo_preimage_demo.js +196 -0
- package/demos/smart_contract_demo.html +1347 -0
- package/demos/smart_contract_demo.js +910 -0
- package/demos/utxo_generator_demo.js +244 -0
- package/demos/validation_pipeline_demo.js +155 -0
- package/demos/web3keys.html +740 -0
- package/docs/BUNDLE_UPDATE_SUMMARY.md +40 -0
- package/docs/FIX_CREATEHMAC_ISSUE.md +91 -0
- package/docs/SMARTLEDGER_BSV_USAGE_ANSWERS.md +477 -0
- package/docs/SMARTLEDGER_BSV_USAGE_EXAMPLES.js +372 -0
- package/docs/SMARTLEDGER_BSV_USAGE_GUIDE.md +555 -0
- package/docs/SMART_CONTRACT_DEVELOPMENT_GUIDE.md +1459 -0
- package/examples/complete_workflow_demo.js +783 -0
- package/examples/definitive_working_demo.js +261 -0
- package/examples/final_working_contracts.js +338 -0
- package/examples/smart_contract_templates.js +718 -0
- package/examples/working_smart_contracts.js +348 -0
- package/lib/mnemonic/pbkdf2.browser.js +69 -0
- package/lib/mnemonic/pbkdf2.js +2 -68
- package/lib/mnemonic/pbkdf2.node.js +68 -0
- package/package.json +16 -5
- package/tests/browser-compatibility/README.md +35 -0
- package/tests/browser-compatibility/test-cdn-vs-local.html +186 -0
- package/tests/browser-compatibility/test-pbkdf2.html +51 -0
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete Smart Contract Workflow - End-to-End Guide
|
|
3
|
+
* ==================================================
|
|
4
|
+
*
|
|
5
|
+
* This file demonstrates the complete process of:
|
|
6
|
+
* 1. Creating smart contracts with preimage validation
|
|
7
|
+
* 2. Deploying contracts to addresses
|
|
8
|
+
* 3. Funding contract addresses
|
|
9
|
+
* 4. Creating transactions that satisfy contracts
|
|
10
|
+
* 5. Broadcasting and validation
|
|
11
|
+
*
|
|
12
|
+
* Usage: node examples/complete_workflow_demo.js
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const bsv = require('../index.js')
|
|
16
|
+
const fs = require('fs')
|
|
17
|
+
const path = require('path')
|
|
18
|
+
|
|
19
|
+
// Enable colored output if available
|
|
20
|
+
let chalk
|
|
21
|
+
try {
|
|
22
|
+
chalk = require('chalk')
|
|
23
|
+
} catch (e) {
|
|
24
|
+
chalk = {
|
|
25
|
+
green: (text) => `✅ ${text}`,
|
|
26
|
+
red: (text) => `❌ ${text}`,
|
|
27
|
+
yellow: (text) => `⚠️ ${text}`,
|
|
28
|
+
blue: (text) => `ℹ️ ${text}`,
|
|
29
|
+
magenta: (text) => `🔮 ${text}`,
|
|
30
|
+
cyan: (text) => `🌊 ${text}`,
|
|
31
|
+
bold: (text) => `**${text}**`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(chalk.bold.blue('\n🔄 Complete Smart Contract Workflow Demonstration\n'))
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// 1. PRODUCTION-READY SMART CONTRACT CLASS
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
class ProductionSmartContract {
|
|
42
|
+
constructor(contractType, params, options = {}) {
|
|
43
|
+
this.contractType = contractType
|
|
44
|
+
this.params = params
|
|
45
|
+
this.options = {
|
|
46
|
+
network: 'testnet',
|
|
47
|
+
storageDir: './.smart-contracts',
|
|
48
|
+
...options
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Generate contract-specific private key (deterministic)
|
|
52
|
+
this.contractSeed = this._generateContractSeed()
|
|
53
|
+
this.privateKey = new bsv.PrivateKey(this.contractSeed)
|
|
54
|
+
|
|
55
|
+
// Build contract script
|
|
56
|
+
this.script = this._buildContractScript()
|
|
57
|
+
this.address = this._createContractAddress()
|
|
58
|
+
|
|
59
|
+
// Initialize storage
|
|
60
|
+
this._initializeStorage()
|
|
61
|
+
|
|
62
|
+
console.log(chalk.green(`✅ ${contractType} contract created`))
|
|
63
|
+
console.log(chalk.blue(` Address: ${this.address.toString()}`))
|
|
64
|
+
console.log(chalk.blue(` Network: ${this.options.network}`))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_generateContractSeed() {
|
|
68
|
+
// Create deterministic seed from contract parameters
|
|
69
|
+
const seedData = JSON.stringify({
|
|
70
|
+
type: this.contractType,
|
|
71
|
+
params: this.params,
|
|
72
|
+
timestamp: Math.floor(Date.now() / 1000)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return bsv.crypto.Hash.sha256sha256(Buffer.from(seedData)).toString('hex')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_buildContractScript() {
|
|
79
|
+
const builder = new bsv.SmartContract.CovenantBuilder()
|
|
80
|
+
|
|
81
|
+
let builtScript
|
|
82
|
+
switch (this.contractType) {
|
|
83
|
+
case 'payment_validation':
|
|
84
|
+
builtScript = this._buildPaymentValidation(builder)
|
|
85
|
+
break
|
|
86
|
+
case 'escrow':
|
|
87
|
+
builtScript = this._buildEscrow(builder)
|
|
88
|
+
break
|
|
89
|
+
case 'subscription':
|
|
90
|
+
builtScript = this._buildSubscription(builder)
|
|
91
|
+
break
|
|
92
|
+
case 'atomic_swap':
|
|
93
|
+
builtScript = this._buildAtomicSwap(builder)
|
|
94
|
+
break
|
|
95
|
+
case 'multi_condition':
|
|
96
|
+
builtScript = this._buildMultiCondition(builder)
|
|
97
|
+
break
|
|
98
|
+
default:
|
|
99
|
+
throw new Error(`Unknown contract type: ${this.contractType}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Convert to BSV Script object
|
|
103
|
+
return new bsv.Script(builtScript.hex)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_buildPaymentValidation(builder) {
|
|
107
|
+
return builder
|
|
108
|
+
.comment(`Payment Validation: ${this.params.minAmount}-${this.params.maxAmount || 'unlimited'} sats`)
|
|
109
|
+
.extractField('value')
|
|
110
|
+
.push(this.params.minAmount)
|
|
111
|
+
.greaterThanOrEqual()
|
|
112
|
+
.verify()
|
|
113
|
+
.build()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_buildEscrow(builder) {
|
|
117
|
+
return builder
|
|
118
|
+
.comment(`Escrow: ${this.params.amount} sats, timeout: ${this.params.timeoutBlocks} blocks`)
|
|
119
|
+
.extractField('value')
|
|
120
|
+
.push(this.params.amount)
|
|
121
|
+
.greaterThanOrEqual()
|
|
122
|
+
.verify()
|
|
123
|
+
.extractField('nLocktime')
|
|
124
|
+
.push(this.params.timeoutBlocks)
|
|
125
|
+
.lessThan() // Must be spent before timeout
|
|
126
|
+
.verify()
|
|
127
|
+
.build()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
_buildSubscription(builder) {
|
|
131
|
+
return builder
|
|
132
|
+
.comment(`Subscription: ${this.params.monthlyAmount} sats/month`)
|
|
133
|
+
.extractField('value')
|
|
134
|
+
.push(this.params.monthlyAmount)
|
|
135
|
+
.numEqual()
|
|
136
|
+
.verify()
|
|
137
|
+
.build()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_buildAtomicSwap(builder) {
|
|
141
|
+
return builder
|
|
142
|
+
.comment(`Atomic Swap: ${this.params.amountA} <-> ${this.params.amountB}`)
|
|
143
|
+
.extractField('value')
|
|
144
|
+
.push(this.params.amountA + this.params.amountB)
|
|
145
|
+
.greaterThanOrEqual()
|
|
146
|
+
.verify()
|
|
147
|
+
.build()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
_buildMultiCondition(builder) {
|
|
151
|
+
builder.comment('Multi-condition contract')
|
|
152
|
+
|
|
153
|
+
this.params.conditions.forEach((condition, index) => {
|
|
154
|
+
builder.comment(`Condition ${index + 1}: ${condition.type}`)
|
|
155
|
+
|
|
156
|
+
switch (condition.type) {
|
|
157
|
+
case 'amount':
|
|
158
|
+
builder
|
|
159
|
+
.extractField('value')
|
|
160
|
+
.push(condition.value)
|
|
161
|
+
.greaterThanOrEqual()
|
|
162
|
+
.verify()
|
|
163
|
+
break
|
|
164
|
+
case 'locktime':
|
|
165
|
+
builder
|
|
166
|
+
.extractField('nLocktime')
|
|
167
|
+
.push(condition.value)
|
|
168
|
+
.greaterThan()
|
|
169
|
+
.verify()
|
|
170
|
+
break
|
|
171
|
+
case 'outputs':
|
|
172
|
+
builder
|
|
173
|
+
.extractField('hashOutputs')
|
|
174
|
+
.push(condition.value)
|
|
175
|
+
.equalVerify()
|
|
176
|
+
break
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return builder.build()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
_createContractAddress() {
|
|
184
|
+
return bsv.SmartContract.utils.createCovenantAddress(this.script)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_initializeStorage() {
|
|
188
|
+
// Create storage directory
|
|
189
|
+
if (!fs.existsSync(this.options.storageDir)) {
|
|
190
|
+
fs.mkdirSync(this.options.storageDir, { recursive: true })
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Save contract metadata
|
|
194
|
+
const contractData = {
|
|
195
|
+
type: this.contractType,
|
|
196
|
+
params: this.params,
|
|
197
|
+
address: this.address.toString(),
|
|
198
|
+
script: {
|
|
199
|
+
asm: this.script.toASM(),
|
|
200
|
+
hex: this.script.toHex()
|
|
201
|
+
},
|
|
202
|
+
createdAt: new Date().toISOString(),
|
|
203
|
+
network: this.options.network
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const contractFile = path.join(this.options.storageDir, `${this.address.toString()}.json`)
|
|
207
|
+
fs.writeFileSync(contractFile, JSON.stringify(contractData, null, 2))
|
|
208
|
+
|
|
209
|
+
console.log(chalk.blue(` Contract saved: ${contractFile}`))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// DEPLOYMENT METHODS
|
|
214
|
+
// ============================================================================
|
|
215
|
+
|
|
216
|
+
async deploy(fundingUtxo, fundingPrivateKey) {
|
|
217
|
+
console.log(chalk.cyan('\n📤 Deploying Contract'))
|
|
218
|
+
console.log(chalk.cyan('===================='))
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
// Step 1: Create funding transaction
|
|
222
|
+
console.log(chalk.yellow('Step 1: Creating funding transaction...'))
|
|
223
|
+
|
|
224
|
+
const fundingTx = new bsv.Transaction()
|
|
225
|
+
.from(fundingUtxo)
|
|
226
|
+
.to(this.address, fundingUtxo.satoshis - 1000) // 1000 sat fee
|
|
227
|
+
.sign(fundingPrivateKey)
|
|
228
|
+
|
|
229
|
+
console.log(chalk.blue(` Funding TX: ${fundingTx.id}`))
|
|
230
|
+
console.log(chalk.blue(` Contract funded with: ${fundingUtxo.satoshis - 1000} satoshis`))
|
|
231
|
+
|
|
232
|
+
// Step 2: Store contract UTXO
|
|
233
|
+
const contractUtxo = {
|
|
234
|
+
txid: fundingTx.id,
|
|
235
|
+
vout: 0,
|
|
236
|
+
satoshis: fundingUtxo.satoshis - 1000,
|
|
237
|
+
script: this.script.toHex(),
|
|
238
|
+
address: this.address.toString()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Save UTXO for later spending
|
|
242
|
+
this._saveContractUtxo(contractUtxo)
|
|
243
|
+
|
|
244
|
+
// Step 3: Return deployment result
|
|
245
|
+
const deployment = {
|
|
246
|
+
transaction: fundingTx,
|
|
247
|
+
utxo: contractUtxo,
|
|
248
|
+
address: this.address,
|
|
249
|
+
broadcastReady: true
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
console.log(chalk.green('✅ Contract deployment prepared'))
|
|
253
|
+
console.log(chalk.blue(' Ready for broadcast to network'))
|
|
254
|
+
|
|
255
|
+
return deployment
|
|
256
|
+
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error(chalk.red('❌ Deployment failed:'), error.message)
|
|
259
|
+
throw error
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
_saveContractUtxo(utxo) {
|
|
264
|
+
const utxoFile = path.join(this.options.storageDir, `${this.address.toString()}_utxos.json`)
|
|
265
|
+
|
|
266
|
+
let utxos = []
|
|
267
|
+
if (fs.existsSync(utxoFile)) {
|
|
268
|
+
utxos = JSON.parse(fs.readFileSync(utxoFile, 'utf8'))
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
utxos.push({
|
|
272
|
+
...utxo,
|
|
273
|
+
createdAt: new Date().toISOString(),
|
|
274
|
+
spent: false
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
fs.writeFileSync(utxoFile, JSON.stringify(utxos, null, 2))
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ============================================================================
|
|
281
|
+
// SPENDING METHODS
|
|
282
|
+
// ============================================================================
|
|
283
|
+
|
|
284
|
+
createSpendingTransaction(contractUtxo, outputAddress, outputAmount) {
|
|
285
|
+
console.log(chalk.cyan('\n💸 Creating Spending Transaction'))
|
|
286
|
+
console.log(chalk.cyan('================================'))
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
console.log(chalk.yellow('Step 1: Building spending transaction...'))
|
|
290
|
+
|
|
291
|
+
// Create spending transaction
|
|
292
|
+
const spendingTx = new bsv.Transaction()
|
|
293
|
+
.from({
|
|
294
|
+
txId: contractUtxo.txid,
|
|
295
|
+
outputIndex: contractUtxo.vout,
|
|
296
|
+
script: contractUtxo.script,
|
|
297
|
+
satoshis: contractUtxo.satoshis
|
|
298
|
+
})
|
|
299
|
+
.to(outputAddress, outputAmount)
|
|
300
|
+
|
|
301
|
+
console.log(chalk.blue(` Spending TX: ${spendingTx.id}`))
|
|
302
|
+
console.log(chalk.blue(` Output: ${outputAmount} sats to ${outputAddress}`))
|
|
303
|
+
|
|
304
|
+
// Generate preimage for contract validation
|
|
305
|
+
console.log(chalk.yellow('Step 2: Generating preimage for validation...'))
|
|
306
|
+
|
|
307
|
+
const preimage = bsv.Transaction.sighash.sighashPreimage(
|
|
308
|
+
spendingTx,
|
|
309
|
+
bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID,
|
|
310
|
+
0,
|
|
311
|
+
bsv.Script.fromHex(contractUtxo.script),
|
|
312
|
+
new bsv.crypto.BN(contractUtxo.satoshis)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
console.log(chalk.blue(` Preimage generated: ${preimage.toString('hex').substring(0, 32)}...`))
|
|
316
|
+
|
|
317
|
+
// Test contract validation
|
|
318
|
+
console.log(chalk.yellow('Step 3: Testing contract validation...'))
|
|
319
|
+
|
|
320
|
+
const validationResult = this.validateSpending(preimage.toString('hex'))
|
|
321
|
+
|
|
322
|
+
if (!validationResult.success) {
|
|
323
|
+
throw new Error(`Contract validation failed: ${validationResult.error}`)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
console.log(chalk.green('✅ Contract validation passed'))
|
|
327
|
+
|
|
328
|
+
// Create unlocking script
|
|
329
|
+
const unlockingScript = new bsv.Script()
|
|
330
|
+
.add(preimage)
|
|
331
|
+
|
|
332
|
+
spendingTx.inputs[0].setScript(unlockingScript)
|
|
333
|
+
|
|
334
|
+
console.log(chalk.green('✅ Spending transaction created'))
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
transaction: spendingTx,
|
|
338
|
+
preimage: preimage.toString('hex'),
|
|
339
|
+
validation: validationResult,
|
|
340
|
+
broadcastReady: true
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
} catch (error) {
|
|
344
|
+
console.error(chalk.red('❌ Spending transaction creation failed:'), error.message)
|
|
345
|
+
throw error
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
validateSpending(preimageHex) {
|
|
350
|
+
try {
|
|
351
|
+
const result = bsv.SmartContract.testScript(
|
|
352
|
+
preimageHex,
|
|
353
|
+
this.script.toHex(),
|
|
354
|
+
{ verbose: true }
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
success: result.valid,
|
|
359
|
+
error: result.error,
|
|
360
|
+
details: result
|
|
361
|
+
}
|
|
362
|
+
} catch (error) {
|
|
363
|
+
return {
|
|
364
|
+
success: false,
|
|
365
|
+
error: error.message
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ============================================================================
|
|
371
|
+
// UTILITY METHODS
|
|
372
|
+
// ============================================================================
|
|
373
|
+
|
|
374
|
+
getContractInfo() {
|
|
375
|
+
return {
|
|
376
|
+
type: this.contractType,
|
|
377
|
+
params: this.params,
|
|
378
|
+
address: this.address.toString(),
|
|
379
|
+
script: {
|
|
380
|
+
asm: this.script.toASM(),
|
|
381
|
+
hex: this.script.toHex(),
|
|
382
|
+
size: this.script.toBuffer().length
|
|
383
|
+
},
|
|
384
|
+
network: this.options.network
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
loadContractUtxos() {
|
|
389
|
+
const utxoFile = path.join(this.options.storageDir, `${this.address.toString()}_utxos.json`)
|
|
390
|
+
|
|
391
|
+
if (fs.existsSync(utxoFile)) {
|
|
392
|
+
const utxos = JSON.parse(fs.readFileSync(utxoFile, 'utf8'))
|
|
393
|
+
return utxos.filter(utxo => !utxo.spent)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return []
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
markUtxoSpent(txid, vout) {
|
|
400
|
+
const utxoFile = path.join(this.options.storageDir, `${this.address.toString()}_utxos.json`)
|
|
401
|
+
|
|
402
|
+
if (fs.existsSync(utxoFile)) {
|
|
403
|
+
const utxos = JSON.parse(fs.readFileSync(utxoFile, 'utf8'))
|
|
404
|
+
|
|
405
|
+
const utxo = utxos.find(u => u.txid === txid && u.vout === vout)
|
|
406
|
+
if (utxo) {
|
|
407
|
+
utxo.spent = true
|
|
408
|
+
utxo.spentAt = new Date().toISOString()
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
fs.writeFileSync(utxoFile, JSON.stringify(utxos, null, 2))
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ============================================================================
|
|
417
|
+
// 2. COMPLETE WORKFLOW ORCHESTRATOR
|
|
418
|
+
// ============================================================================
|
|
419
|
+
|
|
420
|
+
class SmartContractWorkflow {
|
|
421
|
+
constructor(options = {}) {
|
|
422
|
+
this.options = {
|
|
423
|
+
network: 'testnet',
|
|
424
|
+
storageDir: './.workflow-demo',
|
|
425
|
+
...options
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Create demo private keys
|
|
429
|
+
this.userPrivateKey = new bsv.PrivateKey()
|
|
430
|
+
this.recipientAddress = new bsv.PrivateKey().toAddress()
|
|
431
|
+
|
|
432
|
+
console.log(chalk.bold.magenta('\n🎬 Smart Contract Workflow Orchestrator\n'))
|
|
433
|
+
console.log(chalk.blue(`User Address: ${this.userPrivateKey.toAddress().toString()}`))
|
|
434
|
+
console.log(chalk.blue(`Recipient Address: ${this.recipientAddress.toString()}`))
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async demonstrateCompleteWorkflow() {
|
|
438
|
+
try {
|
|
439
|
+
console.log(chalk.bold.cyan('\n🚀 Complete Workflow Demonstration'))
|
|
440
|
+
console.log(chalk.cyan('===================================\n'))
|
|
441
|
+
|
|
442
|
+
// Step 1: Create various contract types
|
|
443
|
+
await this._demonstrateContractCreation()
|
|
444
|
+
|
|
445
|
+
// Step 2: Deploy contracts
|
|
446
|
+
await this._demonstrateContractDeployment()
|
|
447
|
+
|
|
448
|
+
// Step 3: Interact with contracts
|
|
449
|
+
await this._demonstrateContractInteraction()
|
|
450
|
+
|
|
451
|
+
// Step 4: Advanced scenarios
|
|
452
|
+
await this._demonstrateAdvancedScenarios()
|
|
453
|
+
|
|
454
|
+
console.log(chalk.bold.green('\n🎉 Complete workflow demonstration finished!'))
|
|
455
|
+
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error(chalk.red('Workflow error:'), error.message)
|
|
458
|
+
throw error
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async _demonstrateContractCreation() {
|
|
463
|
+
console.log(chalk.bold.yellow('Phase 1: Contract Creation'))
|
|
464
|
+
console.log(chalk.yellow('==========================\n'))
|
|
465
|
+
|
|
466
|
+
// Create payment validation contract
|
|
467
|
+
console.log(chalk.cyan('1.1 Payment Validation Contract'))
|
|
468
|
+
this.paymentContract = new ProductionSmartContract('payment_validation', {
|
|
469
|
+
minAmount: 100000,
|
|
470
|
+
maxAmount: 500000
|
|
471
|
+
}, this.options)
|
|
472
|
+
|
|
473
|
+
console.log()
|
|
474
|
+
|
|
475
|
+
// Create escrow contract
|
|
476
|
+
console.log(chalk.cyan('1.2 Escrow Contract'))
|
|
477
|
+
this.escrowContract = new ProductionSmartContract('escrow', {
|
|
478
|
+
amount: 1000000,
|
|
479
|
+
timeoutBlocks: 600000
|
|
480
|
+
}, this.options)
|
|
481
|
+
|
|
482
|
+
console.log()
|
|
483
|
+
|
|
484
|
+
// Create multi-condition contract
|
|
485
|
+
console.log(chalk.cyan('1.3 Multi-Condition Contract'))
|
|
486
|
+
this.multiContract = new ProductionSmartContract('multi_condition', {
|
|
487
|
+
conditions: [
|
|
488
|
+
{ type: 'amount', value: 50000 },
|
|
489
|
+
{ type: 'locktime', value: 600000 }
|
|
490
|
+
]
|
|
491
|
+
}, this.options)
|
|
492
|
+
|
|
493
|
+
console.log()
|
|
494
|
+
|
|
495
|
+
console.log(chalk.green('✅ All contracts created successfully'))
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
async _demonstrateContractDeployment() {
|
|
499
|
+
console.log(chalk.bold.yellow('\nPhase 2: Contract Deployment'))
|
|
500
|
+
console.log(chalk.yellow('============================\n'))
|
|
501
|
+
|
|
502
|
+
// Create mock funding UTXO
|
|
503
|
+
const fundingUtxo = this._createMockUtxo(2000000) // 2M sats
|
|
504
|
+
|
|
505
|
+
console.log(chalk.cyan('2.1 Deploying Payment Contract'))
|
|
506
|
+
this.paymentDeployment = await this.paymentContract.deploy(fundingUtxo, this.userPrivateKey)
|
|
507
|
+
|
|
508
|
+
console.log(chalk.cyan('\n2.2 Deploying Escrow Contract'))
|
|
509
|
+
const escrowFunding = this._createMockUtxo(1500000) // 1.5M sats
|
|
510
|
+
this.escrowDeployment = await this.escrowContract.deploy(escrowFunding, this.userPrivateKey)
|
|
511
|
+
|
|
512
|
+
console.log(chalk.cyan('\n2.3 Deploying Multi-Condition Contract'))
|
|
513
|
+
const multiFunding = this._createMockUtxo(1000000) // 1M sats
|
|
514
|
+
this.multiDeployment = await this.multiContract.deploy(multiFunding, this.userPrivateKey)
|
|
515
|
+
|
|
516
|
+
console.log(chalk.green('\n✅ All contracts deployed successfully'))
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
async _demonstrateContractInteraction() {
|
|
520
|
+
console.log(chalk.bold.yellow('\nPhase 3: Contract Interaction'))
|
|
521
|
+
console.log(chalk.yellow('=============================\n'))
|
|
522
|
+
|
|
523
|
+
// Interact with payment contract
|
|
524
|
+
console.log(chalk.cyan('3.1 Spending from Payment Contract'))
|
|
525
|
+
try {
|
|
526
|
+
const paymentSpending = this.paymentContract.createSpendingTransaction(
|
|
527
|
+
this.paymentDeployment.utxo,
|
|
528
|
+
this.recipientAddress,
|
|
529
|
+
150000 // Valid amount (>= 100000)
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
console.log(chalk.green('✅ Payment contract spending created'))
|
|
533
|
+
|
|
534
|
+
} catch (error) {
|
|
535
|
+
console.log(chalk.red('❌ Payment spending failed:'), error.message)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Interact with escrow contract
|
|
539
|
+
console.log(chalk.cyan('\n3.2 Spending from Escrow Contract'))
|
|
540
|
+
try {
|
|
541
|
+
const escrowSpending = this.escrowContract.createSpendingTransaction(
|
|
542
|
+
this.escrowDeployment.utxo,
|
|
543
|
+
this.recipientAddress,
|
|
544
|
+
1000000 // Exact escrow amount
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
console.log(chalk.green('✅ Escrow contract spending created'))
|
|
548
|
+
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.log(chalk.red('❌ Escrow spending failed:'), error.message)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Test validation failures
|
|
554
|
+
console.log(chalk.cyan('\n3.3 Testing Validation Failures'))
|
|
555
|
+
try {
|
|
556
|
+
const invalidSpending = this.paymentContract.createSpendingTransaction(
|
|
557
|
+
this.paymentDeployment.utxo,
|
|
558
|
+
this.recipientAddress,
|
|
559
|
+
50000 // Invalid amount (< 100000)
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
console.log(chalk.red('⚠️ This should have failed but didn\'t'))
|
|
563
|
+
|
|
564
|
+
} catch (error) {
|
|
565
|
+
console.log(chalk.green('✅ Validation correctly rejected invalid spending'))
|
|
566
|
+
console.log(chalk.blue(` Error: ${error.message}`))
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async _demonstrateAdvancedScenarios() {
|
|
571
|
+
console.log(chalk.bold.yellow('\nPhase 4: Advanced Scenarios'))
|
|
572
|
+
console.log(chalk.yellow('===========================\n'))
|
|
573
|
+
|
|
574
|
+
// Batch contract operations
|
|
575
|
+
console.log(chalk.cyan('4.1 Batch Contract Operations'))
|
|
576
|
+
|
|
577
|
+
const contracts = [this.paymentContract, this.escrowContract, this.multiContract]
|
|
578
|
+
|
|
579
|
+
contracts.forEach((contract, index) => {
|
|
580
|
+
const info = contract.getContractInfo()
|
|
581
|
+
console.log(chalk.blue(` Contract ${index + 1}: ${info.type}`))
|
|
582
|
+
console.log(chalk.blue(` Address: ${info.address}`))
|
|
583
|
+
console.log(chalk.blue(` Script size: ${info.script.size} bytes`))
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
// Contract portfolio management
|
|
587
|
+
console.log(chalk.cyan('\n4.2 Contract Portfolio'))
|
|
588
|
+
|
|
589
|
+
const portfolio = {
|
|
590
|
+
totalContracts: contracts.length,
|
|
591
|
+
totalValue: 0,
|
|
592
|
+
contractTypes: {}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
contracts.forEach(contract => {
|
|
596
|
+
const utxos = contract.loadContractUtxos()
|
|
597
|
+
const contractValue = utxos.reduce((sum, utxo) => sum + utxo.satoshis, 0)
|
|
598
|
+
|
|
599
|
+
portfolio.totalValue += contractValue
|
|
600
|
+
portfolio.contractTypes[contract.contractType] =
|
|
601
|
+
(portfolio.contractTypes[contract.contractType] || 0) + 1
|
|
602
|
+
})
|
|
603
|
+
|
|
604
|
+
console.log(chalk.blue(` Total Contracts: ${portfolio.totalContracts}`))
|
|
605
|
+
console.log(chalk.blue(` Total Value: ${portfolio.totalValue} satoshis`))
|
|
606
|
+
console.log(chalk.blue(` Contract Types:`, JSON.stringify(portfolio.contractTypes, null, 4)))
|
|
607
|
+
|
|
608
|
+
console.log(chalk.green('\n✅ Advanced scenarios completed'))
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
_createMockUtxo(satoshis) {
|
|
612
|
+
// Create a mock UTXO for demo purposes
|
|
613
|
+
return {
|
|
614
|
+
txid: 'a'.repeat(64),
|
|
615
|
+
vout: 0,
|
|
616
|
+
satoshis: satoshis,
|
|
617
|
+
script: bsv.Script.buildPublicKeyHashOut(this.userPrivateKey.toAddress()).toHex()
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ============================================================================
|
|
623
|
+
// 3. ADVANCED CONTRACT EXAMPLES
|
|
624
|
+
// ============================================================================
|
|
625
|
+
|
|
626
|
+
class AdvancedContractExamples {
|
|
627
|
+
constructor() {
|
|
628
|
+
console.log(chalk.bold.magenta('\n🎯 Advanced Smart Contract Examples\n'))
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
demonstrateAdvancedPatterns() {
|
|
632
|
+
console.log(chalk.bold.cyan('Advanced Contract Patterns'))
|
|
633
|
+
console.log(chalk.cyan('==========================\n'))
|
|
634
|
+
|
|
635
|
+
// Demonstrate each pattern
|
|
636
|
+
this._demonstrateTimeLockPattern()
|
|
637
|
+
this._demonstrateMultiSigConstraints()
|
|
638
|
+
this._demonstrateAtomicSwapPattern()
|
|
639
|
+
this._demonstrateSubscriptionPattern()
|
|
640
|
+
this._demonstrateComplexValidation()
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
_demonstrateTimeLockPattern() {
|
|
644
|
+
console.log(chalk.yellow('Pattern 1: Time Lock with Amount Validation'))
|
|
645
|
+
|
|
646
|
+
const timeLockContract = new ProductionSmartContract('multi_condition', {
|
|
647
|
+
conditions: [
|
|
648
|
+
{ type: 'amount', value: 100000 }, // Min 100k sats
|
|
649
|
+
{ type: 'locktime', value: 700000 } // After block 700k
|
|
650
|
+
]
|
|
651
|
+
})
|
|
652
|
+
|
|
653
|
+
console.log(chalk.blue(` Time Lock Address: ${timeLockContract.address.toString()}`))
|
|
654
|
+
console.log(chalk.blue(' Validates: Amount >= 100k AND locktime > 700k'))
|
|
655
|
+
console.log()
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
_demonstrateMultiSigConstraints() {
|
|
659
|
+
console.log(chalk.yellow('Pattern 2: Multi-Sig with Spending Constraints'))
|
|
660
|
+
|
|
661
|
+
// This would combine multi-sig with preimage validation
|
|
662
|
+
console.log(chalk.blue(' Concept: Require 2-of-3 signatures AND spending limits'))
|
|
663
|
+
console.log(chalk.blue(' Implementation: Custom script combining OP_CHECKMULTISIG with field validation'))
|
|
664
|
+
console.log()
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
_demonstrateAtomicSwapPattern() {
|
|
668
|
+
console.log(chalk.yellow('Pattern 3: Atomic Swap with Secret Reveal'))
|
|
669
|
+
|
|
670
|
+
const swapContract = new ProductionSmartContract('atomic_swap', {
|
|
671
|
+
amountA: 500000,
|
|
672
|
+
amountB: 1000000,
|
|
673
|
+
secretHash: 'abc123...'
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
console.log(chalk.blue(` Swap Address: ${swapContract.address.toString()}`))
|
|
677
|
+
console.log(chalk.blue(' Validates: Correct amounts AND secret reveal'))
|
|
678
|
+
console.log()
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
_demonstrateSubscriptionPattern() {
|
|
682
|
+
console.log(chalk.yellow('Pattern 4: Subscription with Payment Counting'))
|
|
683
|
+
|
|
684
|
+
const subscriptionContract = new ProductionSmartContract('subscription', {
|
|
685
|
+
monthlyAmount: 10000000, // 0.1 BSV
|
|
686
|
+
maxPayments: 12
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
console.log(chalk.blue(` Subscription Address: ${subscriptionContract.address.toString()}`))
|
|
690
|
+
console.log(chalk.blue(' Validates: Exact monthly amount'))
|
|
691
|
+
console.log()
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
_demonstrateComplexValidation() {
|
|
695
|
+
console.log(chalk.yellow('Pattern 5: Complex Multi-Field Validation'))
|
|
696
|
+
|
|
697
|
+
const builder = new bsv.SmartContract.CovenantBuilder()
|
|
698
|
+
|
|
699
|
+
const complexScript = builder
|
|
700
|
+
.comment('Complex validation: amount, outputs, version, sighash')
|
|
701
|
+
|
|
702
|
+
// Validate amount range
|
|
703
|
+
.extractField('value')
|
|
704
|
+
.dup()
|
|
705
|
+
.push(100000)
|
|
706
|
+
.greaterThanOrEqual()
|
|
707
|
+
.verify()
|
|
708
|
+
.push(1000000)
|
|
709
|
+
.lessThanOrEqual()
|
|
710
|
+
.verify()
|
|
711
|
+
|
|
712
|
+
// Validate version
|
|
713
|
+
.extractField('nVersion')
|
|
714
|
+
.push(2)
|
|
715
|
+
.numEqual()
|
|
716
|
+
.verify()
|
|
717
|
+
|
|
718
|
+
// Validate sighash type
|
|
719
|
+
.extractField('sighashType')
|
|
720
|
+
.push(bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID)
|
|
721
|
+
.numEqual()
|
|
722
|
+
.verify()
|
|
723
|
+
|
|
724
|
+
.build()
|
|
725
|
+
|
|
726
|
+
const complexBsvScript = new bsv.Script(complexScript.hex)
|
|
727
|
+
const complexAddress = bsv.SmartContract.utils.createCovenantAddress(complexBsvScript)
|
|
728
|
+
|
|
729
|
+
console.log(chalk.blue(` Complex Contract Address: ${complexAddress.toString()}`))
|
|
730
|
+
console.log(chalk.blue(' Validates: Amount range + version + sighash type'))
|
|
731
|
+
console.log(chalk.blue(` Script size: ${complexBsvScript.toBuffer().length} bytes`))
|
|
732
|
+
console.log()
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// ============================================================================
|
|
737
|
+
// 4. MAIN EXECUTION
|
|
738
|
+
// ============================================================================
|
|
739
|
+
|
|
740
|
+
async function main() {
|
|
741
|
+
try {
|
|
742
|
+
console.log(chalk.bold.blue('Complete Smart Contract Workflow Demo'))
|
|
743
|
+
console.log(chalk.blue('====================================\n'))
|
|
744
|
+
|
|
745
|
+
// Run complete workflow
|
|
746
|
+
const workflow = new SmartContractWorkflow({
|
|
747
|
+
network: 'testnet',
|
|
748
|
+
storageDir: './.workflow-demo'
|
|
749
|
+
})
|
|
750
|
+
|
|
751
|
+
await workflow.demonstrateCompleteWorkflow()
|
|
752
|
+
|
|
753
|
+
// Show advanced patterns
|
|
754
|
+
const advancedExamples = new AdvancedContractExamples()
|
|
755
|
+
advancedExamples.demonstrateAdvancedPatterns()
|
|
756
|
+
|
|
757
|
+
console.log(chalk.bold.green('\n🎯 All demonstrations completed successfully!'))
|
|
758
|
+
|
|
759
|
+
// Usage instructions
|
|
760
|
+
console.log(chalk.bold.yellow('\n📚 Next Steps:'))
|
|
761
|
+
console.log(chalk.yellow('1. Review the generated contract files in .workflow-demo/'))
|
|
762
|
+
console.log(chalk.yellow('2. Modify contract parameters for your use cases'))
|
|
763
|
+
console.log(chalk.yellow('3. Test with real UTXOs on testnet'))
|
|
764
|
+
console.log(chalk.yellow('4. Implement broadcast functionality for production'))
|
|
765
|
+
console.log(chalk.yellow('5. Add error handling and monitoring'))
|
|
766
|
+
|
|
767
|
+
} catch (error) {
|
|
768
|
+
console.error(chalk.bold.red('\nDemo Error:'), error.message)
|
|
769
|
+
console.error(chalk.red('Stack:'), error.stack)
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Export for use in other modules
|
|
774
|
+
module.exports = {
|
|
775
|
+
ProductionSmartContract,
|
|
776
|
+
SmartContractWorkflow,
|
|
777
|
+
AdvancedContractExamples
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Run demo if executed directly
|
|
781
|
+
if (require.main === module) {
|
|
782
|
+
main().catch(console.error)
|
|
783
|
+
}
|