-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathassetIdEncoder.js
146 lines (135 loc) · 6.12 KB
/
assetIdEncoder.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
var bitcoin = require('bitcoinjs-lib')
var bs58check = require('bs58check')
var hash = require('crypto-hashing')
var debug = require('debug')('assetIdEncoder')
var UNLOCKEPADDING = {
aggregatable: 0x2e37,
hybrid: 0x2e6b,
dispersed: 0x2e4e
}
var LOCKEPADDING = {
aggregatable: 0x20ce,
hybrid: 0x2102,
dispersed: 0x20e4
}
var BTC_P2PKH = 0x00
var BTC_TESTNET_P2PKH = 0x6f
var BTC_P2SH = 0x05
var BTC_TESTNET_P2SH = 0xc4
var NETWORKVERSIONS = [BTC_P2PKH, BTC_TESTNET_P2PKH, BTC_P2SH, BTC_TESTNET_P2SH]
var POSTFIXBYTELENGTH = 2
var padLeadingZeros = function (hex, byteSize) {
if (!byteSize) {
byteSize = Math.ceil(hex.length / 2)
}
return (hex.length === byteSize * 2) ? hex : padLeadingZeros('0' + hex, byteSize)
}
var createIdFromTxidIndex = function (txid, index, padding, divisibility) {
debug('createIdFromTxidIndex')
debug('txid = ', txid, ', index = ', index)
var str = txid + ':' + index
return hashAndBase58CheckEncode(str, padding, divisibility)
}
var createIdFromPreviousOutputScriptPubKey = function (previousOutputHex, padding, divisibility) {
var buffer = new Buffer(previousOutputHex, 'hex')
debug('buffer = ', buffer)
return hashAndBase58CheckEncode(buffer, padding, divisibility)
}
var createIdFromPubKeyHashInput = function (scriptSig, padding, divisibility) {
debug('createIdFromPubKeyHashInput')
if (!scriptSig.asm) {
var buffer = new Buffer(scriptSig.hex, 'hex')
scriptSig.asm = bitcoin.script.toASM(buffer)
}
var publicKey = scriptSig.asm.split(' ')[1]
debug('publicKey = ', publicKey)
publicKey = new Buffer(publicKey, 'hex')
var hash256 = hash.sha256(publicKey)
var pubKeyHash = hash.ripemd160(hash256)
debug('pubKeyHash = ', pubKeyHash)
var pubKeyHashOutput = bitcoin.script.pubKeyHashOutput(pubKeyHash)
debug('pubKeyHashOutput = ', pubKeyHashOutput)
return hashAndBase58CheckEncode(pubKeyHashOutput, padding, divisibility)
}
var createIdFromScriptHashInput = function (scriptSig, padding, divisibility) {
debug('createIdFromScriptHashInput')
var buffer = scriptSig.hex ? new Buffer(scriptSig.hex, 'hex') : bitcoin.script.fromASM(scriptSig.asm)
debug('buffer = ', buffer)
var chunks = bitcoin.script.decompile(buffer)
var lastChunk = chunks[chunks.length - 1]
debug('lastChunk = ', lastChunk)
var redeemScriptChunks = bitcoin.script.decompile(lastChunk)
redeemScriptChunks = redeemScriptChunks.map(function (chunk) { return Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk.toString(16), 'hex') })
var redeemScript = Buffer.concat(redeemScriptChunks)
debug('redeemScript = ', redeemScript)
var hash256 = hash.sha256(redeemScript)
var scriptHash = hash.ripemd160(hash256)
var scriptHashOutput = bitcoin.script.scriptHashOutput(scriptHash)
return hashAndBase58CheckEncode(scriptHashOutput, padding, divisibility)
}
var createIdFromAddress = function (address, padding, divisibility) {
debug('createIdFromAddress')
var addressBuffer = bs58check.decode(address)
var versionBuffer = addressBuffer.slice(0, 1)
var version = parseInt(versionBuffer.toString('hex'), 16)
debug('version = ', version)
if (NETWORKVERSIONS.indexOf(version) === -1) throw new Error('Unrecognized address network')
if (version === BTC_P2SH || version === BTC_TESTNET_P2SH) {
var scriptHash = addressBuffer.slice(versionBuffer.length, 21)
var scriptHashOutput = bitcoin.script.scriptHashOutput(scriptHash)
debug('scriptHashOutput = ', scriptHashOutput)
return hashAndBase58CheckEncode(scriptHashOutput, padding, divisibility)
}
if (version === BTC_P2PKH || version === BTC_TESTNET_P2PKH) {
var pubKeyHash = addressBuffer.slice(versionBuffer.length, 21)
var pubKeyHashOutput = bitcoin.script.pubKeyHashOutput(pubKeyHash)
debug('pubKeyHashOutput = ', pubKeyHashOutput)
return hashAndBase58CheckEncode(pubKeyHashOutput, padding, divisibility)
}
}
var hashAndBase58CheckEncode = function (payloadToHash, padding, divisibility) {
debug('hashAndBase58CheckEncode')
debug('padding and divisibility = ' + padding.toString(16) + ', ' + divisibility)
var hash256 = hash.sha256(payloadToHash)
var hash160 = hash.ripemd160(hash256)
debug('hash160 = ', hash160)
padding = new Buffer(padLeadingZeros(padding.toString(16)), 'hex')
divisibility = new Buffer(padLeadingZeros(divisibility.toString(16), POSTFIXBYTELENGTH), 'hex')
var concatenation = Buffer.concat([padding, hash160, divisibility])
return bs58check.encode(concatenation)
}
module.exports = function (bitcoinTransaction) {
debug('bitcoinTransaction.txid = ', bitcoinTransaction.txid)
if (!bitcoinTransaction.ccdata) throw new Error('Missing Colored Coin Metadata')
if (bitcoinTransaction.ccdata[0].type !== 'issuance') throw new Error('Not An issuance transaction')
if (typeof bitcoinTransaction.ccdata[0].lockStatus === 'undefined') throw new Error('Missing Lock Status data')
var lockStatus = bitcoinTransaction.ccdata[0].lockStatus
var aggregationPolicy = bitcoinTransaction.ccdata[0].aggregationPolicy || 'aggregatable'
var divisibility = bitcoinTransaction.ccdata[0].divisibility || 0
var firstInput = bitcoinTransaction.vin[0]
var padding
if (lockStatus) {
padding = LOCKEPADDING[aggregationPolicy]
return createIdFromTxidIndex(firstInput.txid, firstInput.vout, padding, divisibility)
}
padding = UNLOCKEPADDING[aggregationPolicy]
if (firstInput.previousOutput && firstInput.previousOutput.hex) {
return createIdFromPreviousOutputScriptPubKey(firstInput.previousOutput.hex, padding, divisibility)
}
if (firstInput.scriptSig && (firstInput.scriptSig.hex || firstInput.scriptSig.asm)) {
var scriptSig = firstInput.scriptSig
scriptSig.hex = scriptSig.hex || bitcoin.script.fromASM(scriptSig.asm).toString('hex')
debug('scriptSig.hex = ', scriptSig.hex)
var buffer = new Buffer(scriptSig.hex, 'hex')
var type = bitcoin.script.classifyInput(buffer)
if (type === 'pubkeyhash') {
return createIdFromPubKeyHashInput(scriptSig, padding, divisibility)
}
if (type === 'scripthash') {
return createIdFromScriptHashInput(scriptSig, padding, divisibility)
}
}
if (firstInput.address) {
return createIdFromAddress(firstInput.address, padding, divisibility)
}
}