-
Notifications
You must be signed in to change notification settings - Fork 2
/
helper.js
147 lines (119 loc) · 3.83 KB
/
helper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const { existsSync, readFileSync, writeFileSync } = require('fs');
const path = require('path');
const { randomBytes } = require('crypto');
const { compileContract: compileContractImpl, bsv } = require('scryptlib');
const inputSatoshis = 100000
const dummyTxId = randomBytes(32).toString('hex');
const axios = require('axios')
const API_PREFIX = 'https://api.whatsonchain.com/v1/bsv/test'
function compileContract(fileName, options) {
const filePath = path.join(__dirname, 'contracts', fileName)
const out = path.join(__dirname, 'out')
const result = compileContractImpl(filePath, options ? options : {
out: out
});
if (result.errors.length > 0) {
console.log(`Compile contract ${filePath} failed: `, result.errors)
throw result.errors;
}
return result;
}
function loadDesc(fileName) {
let filePath = '';
if (!fileName.endsWith(".json")) {
filePath = path.join(__dirname, `out/${fileName}_desc.json`);
if (!existsSync(filePath)) {
filePath = path.join(__dirname, `out/${fileName}_debug_desc.json`);
if (!existsSync(filePath)) {
filePath = path.join(__dirname, `out/${fileName}_release_desc.json`);
}
}
} else {
filePath = path.join(__dirname, `out/${fileName}`);
}
if (!existsSync(filePath)) {
throw new Error(`Description file ${filePath} not exist!\nIf You already run 'npm run watch', maybe fix the compile error first!`)
}
return JSON.parse(readFileSync(filePath).toString());
}
function newTx() {
const utxo = {
txId: dummyTxId,
outputIndex: 0,
script: '', // placeholder
satoshis: inputSatoshis
};
return new bsv.Transaction().from(utxo);
}
async function sendTx(tx) {
const txhex = tx.toString();
const size = Math.max(1, txhex.length / 2 / 1024); //KB
const time = Math.max(100000, 1000 * size);
const {
data
} = await axios({
method: 'post',
url: `https://testnet-mapi.gorillapool.io/mapi/tx`,
data: Buffer.from(txhex, 'hex'),
headers: {
'Accept': 'text/plain',
'Content-Type': 'application/octet-stream'
},
timeout: time,
maxBodyLength: Infinity
});
const payload = JSON.parse(data.payload)
if(payload.returnResult === 'success') {
return payload.txid;
} else if(payload.returnResult === 'failure') {
console.error('sendTx error:', txhex)
throw new Error(payload.resultDescription)
}
throw new Error('sendTx error')
}
async function fetchUtxos(address) {
// step 1: fetch utxos
let {
data: utxos
} = await axios.get(`${API_PREFIX}/address/${address}/unspent`)
return utxos.map((utxo) => ({
txId: utxo.tx_hash,
outputIndex: utxo.tx_pos,
satoshis: utxo.value,
script: bsv.Script.buildPublicKeyHashOut(address).toHex(),
}))
}
async function deployContract(contract, amount) {
const { privateKey } = require('./privateKey');
const address = privateKey.toAddress()
const tx = new bsv.Transaction()
tx.from(await fetchUtxos(address))
.addOutput(new bsv.Transaction.Output({
script: contract.lockingScript,
satoshis: amount,
}))
.change(address)
.sign(privateKey)
await sendTx(tx)
return tx
}
//create an input spending from prevTx's output, with empty script
function createInputFromPrevTx(tx, outputIndex) {
const outputIdx = outputIndex || 0
return new bsv.Transaction.Input({
prevTxId: tx.id,
outputIndex: outputIdx,
script: new bsv.Script(), // placeholder
output: tx.outputs[outputIdx]
})
}
module.exports = {
compileContract,
loadDesc,
newTx,
inputSatoshis,
deployContract,
fetchUtxos,
sendTx,
createInputFromPrevTx
}