forked from Colored-Coins/Transfer-Encoder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
transferEncoder.js
119 lines (108 loc) · 5.13 KB
/
transferEncoder.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
var TYPE_MASK = 0xf0
var TRANSFER_MASK = 0x10
var BURN_MASK = 0x20
var TRANSFER_OP_CODES = [
new Buffer([0x10]), // All Hashes in OP_RETURN
new Buffer([0x11]), // SHA2 in Pay-to-Script-Hash multi-sig output (1 out of 2)
new Buffer([0x12]), // All Hashes in Pay-to-Script-Hash multi-sig outputs (1 out of 3)
new Buffer([0x13]), // Low security transaction no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case.
new Buffer([0x14]), // Low security transaction no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case. also no rules inside the metadata (if there are any they will be in ignored)
new Buffer([0x15]) // No metadata or rules (no SHA1 or SHA2)
]
var BURN_OP_CODES = [
new Buffer([0x20]), // All Hashes in OP_RETURN
new Buffer([0x21]), // SHA2 in Pay-to-Script-Hash multi-sig output (1 out of 2)
new Buffer([0x22]), // All Hashes in Pay-to-Script-Hash multi-sig outputs (1 out of 3)
new Buffer([0x23]), // Low security transaction no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case.
new Buffer([0x24]), // Low security transaction no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case. also no rules inside the metadata (if there are any they will be in ignored)
new Buffer([0x25]) // No metadata or rules (no SHA1 or SHA2)
]
var transferPaymentEncoder = require('cc-payment-encoder')
var burnPaymentEncoder = require('cc-burn-payment-encoder')
var consumer = function (buff) {
var curr = 0
return function consume (len) {
return buff.slice(curr, curr += len)
}
}
var padLeadingZeros = function (hex, byteSize) {
return (hex.length === byteSize * 2) ? hex : padLeadingZeros('0' + hex, byteSize)
}
module.exports = {
encode: function (data, byteSize) {
if (!data
|| typeof data.payments === 'undefined'
) {
throw new Error('Missing Data')
}
var opcode
var OP_CODES = data.type === 'burn' ? BURN_OP_CODES : TRANSFER_OP_CODES
var paymentEncoder = data.type === 'burn' ? burnPaymentEncoder : transferPaymentEncoder
var hash = new Buffer(0)
var protocol = new Buffer(padLeadingZeros(data.protocol.toString(16), 2), 'hex')
var version = new Buffer([data.version])
var transferHeader = Buffer.concat([protocol, version])
var payments = paymentEncoder.encodeBulk(data.payments)
var issueByteSize = transferHeader.length + payments.length + 1
if (issueByteSize > byteSize) throw new Error('Data code is bigger then the allowed byte size')
if (!data.sha2) {
if (data.torrentHash) {
opcode = data.noRules ? OP_CODES[4] : OP_CODES[3]
if (issueByteSize + data.torrentHash.length > byteSize) throw new Error('Can\'t fit Torrent Hash in byte size')
return {codeBuffer: Buffer.concat([transferHeader, opcode, data.torrentHash, payments]), leftover: []}
}
return {codeBuffer: Buffer.concat([transferHeader, OP_CODES[5], hash, payments]), leftover: []}
}
if (!data.torrentHash) throw new Error('Torrent Hash is missing')
var leftover = [data.torrentHash, data.sha2]
opcode = OP_CODES[2]
issueByteSize = issueByteSize + data.torrentHash.length
if (issueByteSize <= byteSize) {
hash = Buffer.concat([hash, leftover.shift()])
opcode = OP_CODES[1]
issueByteSize = issueByteSize + data.sha2.length
}
if (issueByteSize <= byteSize) {
hash = Buffer.concat([hash, leftover.shift()])
opcode = OP_CODES[0]
}
return {codeBuffer: Buffer.concat([transferHeader, opcode, hash, payments]), leftover: leftover}
},
decode: function (op_code_buffer) {
var data = {}
var consume = consumer(op_code_buffer)
data.protocol = parseInt(consume(2).toString('hex'), 16)
data.version = parseInt(consume(1).toString('hex'), 16)
data.multiSig = []
var opcode = consume(1)
var paymentEncoder
if ((opcode[0] & TYPE_MASK) === TRANSFER_MASK) {
paymentEncoder = transferPaymentEncoder
} else if ((opcode[0] & TYPE_MASK) === BURN_MASK) {
paymentEncoder = burnPaymentEncoder
} else {
throw new Error('Unrecognized Code')
}
if (opcode[0] === TRANSFER_OP_CODES[0][0] || opcode[0] === BURN_OP_CODES[0][0]) {
data.torrentHash = consume(20)
data.sha2 = consume(32)
} else if (opcode[0] === TRANSFER_OP_CODES[1][0] || opcode[0] === BURN_OP_CODES[1][0]) {
data.torrentHash = consume(20)
data.multiSig.push({'index': 1, 'hashType': 'sha2'})
} else if (opcode[0] === TRANSFER_OP_CODES[2][0] || opcode[0] === BURN_OP_CODES[2][0]) {
data.multiSig.push({'index': 1, 'hashType': 'sha2'})
data.multiSig.push({'index': 2, 'hashType': 'torrentHash'})
} else if (opcode[0] === TRANSFER_OP_CODES[3][0] || opcode[0] === BURN_OP_CODES[3][0]) {
data.torrentHash = consume(20)
data.noRules = false
} else if (opcode[0] === TRANSFER_OP_CODES[4][0] || opcode[0] === BURN_OP_CODES[4][0]) {
data.torrentHash = consume(20)
data.noRules = true
} else if (opcode[0] === TRANSFER_OP_CODES[5][0] || opcode[0] === BURN_OP_CODES[5][0]) {
} else {
throw new Error('Unrecognized Code')
}
data.payments = paymentEncoder.decodeBulk(consume)
return data
}
}