@alephium/web3 0.0.3 → 0.1.0-rc.0

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.
Files changed (144) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +21 -0
  4. package/README.md +2 -2
  5. package/contracts/add.ral +7 -3
  6. package/contracts/greeter.ral +3 -1
  7. package/contracts/greeter_interface.ral +3 -0
  8. package/contracts/greeter_main.ral +9 -0
  9. package/contracts/main.ral +3 -5
  10. package/dev/user.conf +8 -4
  11. package/dist/alephium-web3.min.js +1 -1
  12. package/dist/alephium-web3.min.js.map +1 -1
  13. package/dist/scripts/check-versions.d.ts +1 -0
  14. package/dist/scripts/check-versions.js +39 -0
  15. package/dist/{cli → scripts}/create-project.d.ts +0 -0
  16. package/dist/scripts/create-project.js +124 -0
  17. package/dist/scripts/header.d.ts +0 -0
  18. package/dist/scripts/header.js +18 -0
  19. package/dist/scripts/rename-gitignore.d.ts +1 -0
  20. package/dist/scripts/rename-gitignore.js +24 -0
  21. package/dist/scripts/start-devnet.d.ts +1 -0
  22. package/dist/scripts/start-devnet.js +131 -0
  23. package/dist/scripts/stop-devnet.d.ts +1 -0
  24. package/dist/scripts/stop-devnet.js +32 -0
  25. package/dist/{api → src/api}/api-alephium.d.ts +287 -168
  26. package/dist/{api → src/api}/api-alephium.js +497 -115
  27. package/dist/{api → src/api}/api-explorer.d.ts +117 -19
  28. package/dist/{api → src/api}/api-explorer.js +206 -46
  29. package/dist/src/api/index.d.ts +10 -0
  30. package/dist/src/api/index.js +55 -0
  31. package/dist/{lib → src}/constants.d.ts +0 -0
  32. package/dist/{lib → src}/constants.js +0 -0
  33. package/dist/src/contract/contract.d.ts +182 -0
  34. package/dist/src/contract/contract.js +760 -0
  35. package/dist/src/contract/events.d.ts +29 -0
  36. package/dist/src/contract/events.js +77 -0
  37. package/dist/src/contract/index.d.ts +3 -0
  38. package/dist/src/contract/index.js +32 -0
  39. package/dist/src/contract/ralph.d.ts +12 -0
  40. package/dist/src/contract/ralph.js +362 -0
  41. package/dist/src/index.d.ts +5 -0
  42. package/dist/src/index.js +34 -0
  43. package/dist/src/signer/index.d.ts +2 -0
  44. package/dist/src/signer/index.js +31 -0
  45. package/dist/src/signer/node-wallet.d.ts +13 -0
  46. package/dist/src/signer/node-wallet.js +60 -0
  47. package/dist/src/signer/signer.d.ts +143 -0
  48. package/dist/src/signer/signer.js +184 -0
  49. package/dist/src/test/index.d.ts +7 -0
  50. package/dist/src/test/index.js +41 -0
  51. package/dist/src/test/privatekey-wallet.d.ts +12 -0
  52. package/dist/src/test/privatekey-wallet.js +68 -0
  53. package/dist/{lib → src/utils}/address.d.ts +0 -0
  54. package/dist/{lib → src/utils}/address.js +1 -1
  55. package/dist/{lib → src/utils}/bs58.d.ts +2 -2
  56. package/dist/{lib → src/utils}/bs58.js +3 -1
  57. package/dist/{lib → src/utils}/djb2.d.ts +0 -0
  58. package/dist/{lib → src/utils}/djb2.js +1 -1
  59. package/dist/src/utils/index.d.ts +6 -0
  60. package/dist/src/utils/index.js +35 -0
  61. package/dist/{lib → src/utils}/password-crypto.d.ts +0 -0
  62. package/dist/{lib → src/utils}/password-crypto.js +8 -7
  63. package/dist/src/utils/transaction.d.ts +2 -0
  64. package/dist/src/utils/transaction.js +58 -0
  65. package/dist/src/utils/utils.d.ts +30 -0
  66. package/dist/{lib → src/utils}/utils.js +83 -19
  67. package/gitignore +5 -4
  68. package/package.json +56 -40
  69. package/scripts/create-project.ts +136 -0
  70. package/scripts/header.js +17 -0
  71. package/scripts/start-devnet.js +3 -3
  72. package/src/api/api-alephium.ts +2323 -0
  73. package/src/api/api-explorer.ts +808 -0
  74. package/src/api/index.ts +35 -0
  75. package/src/constants.ts +20 -0
  76. package/src/contract/contract.ts +1014 -0
  77. package/src/contract/events.ts +102 -0
  78. package/src/contract/index.ts +21 -0
  79. package/src/contract/ralph.test.ts +178 -0
  80. package/src/contract/ralph.ts +362 -0
  81. package/src/fixtures/address.json +36 -0
  82. package/src/fixtures/balance.json +9 -0
  83. package/src/fixtures/self-clique.json +19 -0
  84. package/src/fixtures/transaction.json +13 -0
  85. package/src/fixtures/transactions.json +179 -0
  86. package/src/index.ts +24 -0
  87. package/src/signer/fixtures/genesis.json +26 -0
  88. package/src/signer/fixtures/wallets.json +26 -0
  89. package/src/signer/index.ts +20 -0
  90. package/src/signer/node-wallet.ts +74 -0
  91. package/src/signer/signer.ts +313 -0
  92. package/src/test/index.ts +32 -0
  93. package/src/test/privatekey-wallet.ts +58 -0
  94. package/src/utils/address.test.ts +47 -0
  95. package/src/utils/address.ts +39 -0
  96. package/src/utils/bs58.ts +26 -0
  97. package/src/utils/djb2.test.ts +35 -0
  98. package/src/utils/djb2.ts +25 -0
  99. package/src/utils/index.ts +24 -0
  100. package/src/utils/password-crypto.test.ts +27 -0
  101. package/src/utils/password-crypto.ts +77 -0
  102. package/src/utils/transaction.test.ts +50 -0
  103. package/src/utils/transaction.ts +39 -0
  104. package/src/utils/utils.test.ts +160 -0
  105. package/src/utils/utils.ts +209 -0
  106. package/templates/{README.md → base/README.md} +4 -4
  107. package/templates/base/package.json +35 -0
  108. package/templates/base/src/greeter.ts +41 -0
  109. package/templates/base/tsconfig.json +19 -0
  110. package/templates/react/README.md +34 -0
  111. package/templates/react/config-overrides.js +18 -0
  112. package/templates/react/package.json +66 -0
  113. package/templates/react/src/App.tsx +42 -0
  114. package/templates/react/src/artifacts/greeter.ral.json +26 -0
  115. package/templates/react/src/artifacts/greeter_main.ral.json +22 -0
  116. package/templates/shared/.eslintrc.json +12 -0
  117. package/templates/shared/scripts/header.js +0 -0
  118. package/test/contract.test.ts +161 -0
  119. package/test/events.test.ts +139 -0
  120. package/webpack.config.js +1 -1
  121. package/contracts/greeter-main.ral +0 -8
  122. package/dist/cli/create-project.js +0 -87
  123. package/dist/lib/clique.d.ts +0 -23
  124. package/dist/lib/clique.js +0 -149
  125. package/dist/lib/contract.d.ts +0 -152
  126. package/dist/lib/contract.js +0 -711
  127. package/dist/lib/explorer.d.ts +0 -8
  128. package/dist/lib/explorer.js +0 -46
  129. package/dist/lib/index.d.ts +0 -12
  130. package/dist/lib/index.js +0 -60
  131. package/dist/lib/node.d.ts +0 -10
  132. package/dist/lib/node.js +0 -64
  133. package/dist/lib/numbers.d.ts +0 -7
  134. package/dist/lib/numbers.js +0 -128
  135. package/dist/lib/signer.d.ts +0 -17
  136. package/dist/lib/signer.js +0 -70
  137. package/dist/lib/storage-browser.d.ts +0 -9
  138. package/dist/lib/storage-browser.js +0 -52
  139. package/dist/lib/storage-node.d.ts +0 -9
  140. package/dist/lib/storage-node.js +0 -65
  141. package/dist/lib/utils.d.ts +0 -11
  142. package/dist/lib/wallet.d.ts +0 -30
  143. package/dist/lib/wallet.js +0 -142
  144. package/templates/package.json +0 -29
@@ -0,0 +1,102 @@
1
+ /*
2
+ Copyright 2018 - 2022 The Alephium Authors
3
+ This file is part of the alephium project.
4
+
5
+ The library is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ The library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ import EventEmitter from 'eventemitter3'
20
+ import { node } from '../api'
21
+ import { NodeProvider } from '../api'
22
+
23
+ type EventCallback = (event: node.ContractEvent) => Promise<void>
24
+ type ErrorCallback = (error: any, subscription: Subscription) => Promise<void>
25
+
26
+ export interface SubscribeOptions {
27
+ provider: NodeProvider
28
+ contractAddress: string
29
+ fromCount?: number
30
+ pollingInterval: number
31
+ eventCallback: EventCallback
32
+ errorCallback: ErrorCallback
33
+ }
34
+
35
+ export class Subscription {
36
+ provider: NodeProvider
37
+ readonly contractAddress: string
38
+ pollingInterval: number
39
+
40
+ private fromCount: number
41
+ private eventCallback: EventCallback
42
+ private errorCallback: ErrorCallback
43
+ private task: ReturnType<typeof setTimeout> | undefined
44
+ private cancelled: boolean
45
+ private eventEmitter: EventEmitter
46
+
47
+ constructor(options: SubscribeOptions) {
48
+ this.provider = options.provider
49
+ this.contractAddress = options.contractAddress
50
+ this.fromCount = typeof options.fromCount === 'undefined' ? 0 : options.fromCount
51
+ this.pollingInterval = options.pollingInterval
52
+ this.eventCallback = options.eventCallback
53
+ this.errorCallback = options.errorCallback
54
+ this.task = undefined
55
+ this.cancelled = false
56
+
57
+ this.eventEmitter = new EventEmitter()
58
+ this.eventEmitter.on('tick', async () => {
59
+ await this.fetchEvents()
60
+ })
61
+ this.eventEmitter.emit('tick')
62
+ }
63
+
64
+ unsubscribe(): void {
65
+ this.eventEmitter.removeAllListeners()
66
+ this.cancelled = true
67
+ if (typeof this.task !== 'undefined') {
68
+ clearTimeout(this.task)
69
+ }
70
+ }
71
+
72
+ currentEventCount(): number {
73
+ return this.fromCount
74
+ }
75
+
76
+ private async fetchEvents() {
77
+ try {
78
+ const events = await this.provider.events.getEventsContractContractaddress(this.contractAddress, {
79
+ start: this.fromCount
80
+ })
81
+ if (this.cancelled) {
82
+ return
83
+ }
84
+
85
+ if (this.fromCount === events.nextStart) {
86
+ this.task = setTimeout(() => this.eventEmitter.emit('tick'), this.pollingInterval)
87
+ return
88
+ }
89
+
90
+ const promises = events.events.map((event) => this.eventCallback(event))
91
+ await Promise.all(promises)
92
+ this.fromCount = events.nextStart
93
+ await this.fetchEvents()
94
+ } catch (err) {
95
+ await this.errorCallback(err, this)
96
+ }
97
+ }
98
+ }
99
+
100
+ export function subscribe(options: SubscribeOptions): Subscription {
101
+ return new Subscription(options)
102
+ }
@@ -0,0 +1,21 @@
1
+ /*
2
+ Copyright 2018 - 2022 The Alephium Authors
3
+ This file is part of the alephium project.
4
+
5
+ The library is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ The library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ export * from './ralph'
20
+ export * from './contract'
21
+ export * from './events'
@@ -0,0 +1,178 @@
1
+ /*
2
+ Copyright 2018 - 2022 The Alephium Authors
3
+ This file is part of the alephium project.
4
+
5
+ The library is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ The library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ import { node } from '../api'
20
+ import * as ralph from './ralph'
21
+ import * as utils from '../utils'
22
+ import { Fields } from './contract'
23
+
24
+ describe('contract', function () {
25
+ it('should encode I256', async () => {
26
+ function test(i256: bigint, expected: string) {
27
+ expect(utils.binToHex(ralph.encodeI256(i256))).toEqual(expected)
28
+ }
29
+ test(BigInt('0'), '00')
30
+ test(BigInt('1'), '01')
31
+ test(BigInt('2'), '02')
32
+ test(BigInt('-1'), '3f')
33
+ test(BigInt('-2'), '3e')
34
+ test(BigInt('32'), '4020')
35
+ test(BigInt('33'), '4021')
36
+ test(BigInt('34'), '4022')
37
+ test(BigInt('31'), '1f')
38
+ test(BigInt('30'), '1e')
39
+ test(BigInt('8192'), '80002000')
40
+ test(BigInt('8193'), '80002001')
41
+ test(BigInt('8194'), '80002002')
42
+ test(BigInt('8191'), '5fff')
43
+ test(BigInt('8190'), '5ffe')
44
+ test(BigInt('536870912'), 'c020000000')
45
+ test(BigInt('536870913'), 'c020000001')
46
+ test(BigInt('536870914'), 'c020000002')
47
+ test(BigInt('536870911'), '9fffffff')
48
+ test(BigInt('536870910'), '9ffffffe')
49
+ test(
50
+ BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819967'),
51
+ 'dc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
52
+ )
53
+ test(
54
+ BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819966'),
55
+ 'dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'
56
+ )
57
+ test(
58
+ BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819965'),
59
+ 'dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
60
+ )
61
+ test(
62
+ BigInt('-57896044618658097711785492504343953926634992332820282019728792003956564819968'),
63
+ 'dc8000000000000000000000000000000000000000000000000000000000000000'
64
+ )
65
+ test(
66
+ BigInt('-57896044618658097711785492504343953926634992332820282019728792003956564819967'),
67
+ 'dc8000000000000000000000000000000000000000000000000000000000000001'
68
+ )
69
+ test(
70
+ BigInt('-57896044618658097711785492504343953926634992332820282019728792003956564819966'),
71
+ 'dc8000000000000000000000000000000000000000000000000000000000000002'
72
+ )
73
+
74
+ function fail(n: bigint) {
75
+ expect(() => ralph.encodeI256(n)).toThrow()
76
+ }
77
+ fail(BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819968'))
78
+ fail(BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819969'))
79
+ fail(BigInt('-57896044618658097711785492504343953926634992332820282019728792003956564819969'))
80
+ fail(BigInt('-57896044618658097711785492504343953926634992332820282019728792003956564819970'))
81
+ })
82
+
83
+ it('should encode U256', async () => {
84
+ function test(u256: bigint, expected: string) {
85
+ expect(utils.binToHex(ralph.encodeU256(u256))).toEqual(expected)
86
+ }
87
+ test(BigInt('0'), '00')
88
+ test(BigInt('1'), '01')
89
+ test(BigInt('2'), '02')
90
+ fail(BigInt('-1'))
91
+ fail(BigInt('-2'))
92
+ test(BigInt('64'), '4040')
93
+ test(BigInt('65'), '4041')
94
+ test(BigInt('66'), '4042')
95
+ test(BigInt('63'), '3f')
96
+ test(BigInt('62'), '3e')
97
+ test(BigInt('16384'), '80004000')
98
+ test(BigInt('16385'), '80004001')
99
+ test(BigInt('16386'), '80004002')
100
+ test(BigInt('16383'), '7fff')
101
+ test(BigInt('16382'), '7ffe')
102
+ test(BigInt('1073741824'), 'c040000000')
103
+ test(BigInt('1073741825'), 'c040000001')
104
+ test(BigInt('1073741826'), 'c040000002')
105
+ test(BigInt('1073741823'), 'bfffffff')
106
+ test(BigInt('1073741822'), 'bffffffe')
107
+ test(
108
+ BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639935'),
109
+ 'dcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
110
+ )
111
+ test(
112
+ BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639934'),
113
+ 'dcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'
114
+ )
115
+ test(
116
+ BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639933'),
117
+ 'dcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
118
+ )
119
+
120
+ function fail(n: bigint) {
121
+ expect(() => ralph.encodeU256(n)).toThrow()
122
+ }
123
+ fail(BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639936'))
124
+ fail(BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639937'))
125
+ })
126
+
127
+ it('should encode ByteVec', async () => {
128
+ const bytes = 'b382fc88aa31d63f4c2f3f8a03715ba2a629552e85431fb1c1d909bab46d1aae'
129
+ const bytecode = ralph.encodeScriptFieldAsString('ByteVec', bytes)
130
+ expect(bytecode).toEqual('144020b382fc88aa31d63f4c2f3f8a03715ba2a629552e85431fb1c1d909bab46d1aae')
131
+ })
132
+
133
+ it('should test buildScriptByteCode', async () => {
134
+ const variables = { x: true, y: 0x05, z: 'ff', a: '1C2RAVWSuaXw8xtUxqVERR7ChKBE1XgscNFw73NSHE1v3' }
135
+ const fieldsSig: node.FieldsSig = {
136
+ signature: 'Not really',
137
+ names: ['x', 'y', 'z', 'a'],
138
+ types: ['Bool', 'U256', 'ByteVec', 'Address']
139
+ }
140
+ const bytecode = ralph.buildScriptByteCode('-{0}-{1}-{2}-{3}-', variables, fieldsSig)
141
+ expect(bytecode).toEqual('-03-1305-1401ff-1500a3cd757be03c7dac8d48bf79e2a7d6e735e018a9c054b99138c7b29738c437ec-')
142
+ })
143
+
144
+ it('should test buildContractByteCode', async () => {
145
+ const fields: Fields = {
146
+ a: -1,
147
+ b: 1,
148
+ c: '23',
149
+ d: '1C2RAVWSuaXw8xtUxqVERR7ChKBE1XgscNFw73NSHE1v3',
150
+ e: [false, true]
151
+ }
152
+ const fieldsSig: node.FieldsSig = {
153
+ signature: 'Not really',
154
+ names: ['a', 'b', 'c', 'd', 'e'],
155
+ types: ['I256', 'U256', 'ByteVec', 'Address', '[Bool;2]']
156
+ }
157
+ const encoded = ralph.buildContractByteCode('ff', fields, fieldsSig)
158
+ expect(encoded).toEqual(
159
+ 'ff06013f02010301230400a3cd757be03c7dac8d48bf79e2a7d6e735e018a9c054b99138c7b29738c437ec00000001'
160
+ )
161
+ })
162
+
163
+ // it('should test buildByteCode', async () => {
164
+ // const compiled = {
165
+ // type: 'TemplateContractByteCode',
166
+ // filedLength: 1,
167
+ // methodsByteCode: [
168
+ // '01000203021205160016015f{subContractId:ByteVec}1702a00016002a16012aa100a000160016011602010002',
169
+ // '00000202020416001601000002'
170
+ // ]
171
+ // }
172
+ // const variables = { subContractId: '55834baf25f40fe5a8d6ac83c5f2b76a1677ed3ddbd6a79c4dea274992982e2b' }
173
+ // const bytecode = ralph.buildContractByteCode(compiled, variables)
174
+ // expect(bytecode).toEqual(
175
+ // '01024046405301000203021205160016015f14402055834baf25f40fe5a8d6ac83c5f2b76a1677ed3ddbd6a79c4dea274992982e2b1702a00016002a16012aa100a00016001601160201000200000202020416001601000002'
176
+ // )
177
+ // })
178
+ })
@@ -0,0 +1,362 @@
1
+ /*
2
+ Copyright 2018 - 2022 The Alephium Authors
3
+ This file is part of the alephium project.
4
+
5
+ The library is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ The library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ import { Buffer } from 'buffer/'
20
+ import { bs58, isHexString } from '../utils'
21
+ import { node } from '../api'
22
+ import { Fields, Val } from './contract'
23
+
24
+ const bigIntZero = BigInt(0)
25
+
26
+ class UnSigned {
27
+ static readonly oneByteBound = BigInt(0x40)
28
+ static readonly twoByteBound = UnSigned.oneByteBound << BigInt(8)
29
+ static readonly fourByteBound = UnSigned.oneByteBound << BigInt(8 * 3)
30
+ static readonly u256UpperBound = BigInt(1) << BigInt(256)
31
+ }
32
+
33
+ class Signed {
34
+ static readonly oneByteBound = BigInt(0x20)
35
+ static readonly twoByteBound = Signed.oneByteBound << BigInt(8)
36
+ static readonly fourByteBound = Signed.oneByteBound << BigInt(8 * 3)
37
+ static readonly i256UpperBound = BigInt(1) << BigInt(255)
38
+ static readonly i256LowerBound = -this.i256UpperBound
39
+ }
40
+
41
+ class CompactInt {
42
+ static readonly oneBytePrefix = 0x00
43
+ static readonly oneByteNegPrefix = 0xc0
44
+ static readonly twoBytePrefix = 0x40
45
+ static readonly twoByteNegPrefix = 0x80
46
+ static readonly fourBytePrefix = 0x80
47
+ static readonly fourByteNegPrefix = 0x40
48
+ static readonly multiBytePrefix = 0xc0
49
+ }
50
+
51
+ export function encodeBool(bool: boolean): Uint8Array {
52
+ return bool ? Uint8Array.from([1]) : Uint8Array.from([0])
53
+ }
54
+
55
+ export function encodeI256(i256: bigint): Uint8Array {
56
+ if (i256 >= bigIntZero) {
57
+ return encodeI256Positive(i256)
58
+ } else {
59
+ return encodeI256Negative(i256)
60
+ }
61
+ }
62
+
63
+ // n should be positive
64
+ function toByteArray(n: bigint, signed: boolean, notBit: boolean): Uint8Array {
65
+ let hex = n.toString(16)
66
+ if (hex.length % 2 === 1) {
67
+ hex = '0' + hex
68
+ } else if (signed && hex[0] >= '8') {
69
+ hex = '00' + hex // add the byte for sign
70
+ }
71
+
72
+ const byteLength = hex.length / 2
73
+ const bytes = new Uint8Array(byteLength + 1)
74
+ for (let index = 0; index < byteLength; index++) {
75
+ const offset = index * 2
76
+ const byte = parseInt(hex.slice(offset, offset + 2), 16)
77
+ bytes[`${index + 1}`] = notBit ? ~byte : byte
78
+ }
79
+
80
+ const header = byteLength - 4 + CompactInt.multiBytePrefix
81
+ bytes[0] = header
82
+ return bytes
83
+ }
84
+
85
+ function encodeI256Positive(i256: bigint): Uint8Array {
86
+ if (i256 < Signed.oneByteBound) {
87
+ return new Uint8Array([Number(i256) + CompactInt.oneBytePrefix])
88
+ } else if (i256 < Signed.twoByteBound) {
89
+ const num = Number(i256)
90
+ return new Uint8Array([(num >> 8) + CompactInt.twoBytePrefix, num & 0xff])
91
+ } else if (i256 < Signed.fourByteBound) {
92
+ const num = Number(i256)
93
+ return new Uint8Array([(num >> 24) + CompactInt.fourBytePrefix, (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff])
94
+ } else if (i256 < Signed.i256UpperBound) {
95
+ return toByteArray(i256, true, false)
96
+ } else {
97
+ throw Error(`Too large number for i256: ${i256}`)
98
+ }
99
+ }
100
+
101
+ function encodeI256Negative(i256: bigint): Uint8Array {
102
+ if (i256 >= -Signed.oneByteBound) {
103
+ const num = Number(i256)
104
+ return new Uint8Array([(num ^ CompactInt.oneByteNegPrefix) & 0xff])
105
+ } else if (i256 >= -Signed.twoByteBound) {
106
+ const num = Number(i256)
107
+ return new Uint8Array([((num >> 8) ^ CompactInt.twoByteNegPrefix) & 0xff, num & 0xff])
108
+ } else if (i256 >= -Signed.fourByteBound) {
109
+ const num = Number(i256)
110
+ return new Uint8Array([
111
+ ((num >> 24) ^ CompactInt.fourByteNegPrefix) & 0xff,
112
+ (num >> 16) & 0xff,
113
+ (num >> 8) & 0xff,
114
+ num & 0xff
115
+ ])
116
+ } else if (i256 >= Signed.i256LowerBound) {
117
+ return toByteArray(~i256, true, true)
118
+ } else {
119
+ throw Error(`Too small number for i256: ${i256}`)
120
+ }
121
+ }
122
+
123
+ export function encodeU256(u256: bigint): Uint8Array {
124
+ if (u256 < bigIntZero) {
125
+ throw Error(`Negative number for U256: ${u256}`)
126
+ } else if (u256 < UnSigned.oneByteBound) {
127
+ return new Uint8Array([Number(u256) + CompactInt.oneBytePrefix])
128
+ } else if (u256 < UnSigned.twoByteBound) {
129
+ const num = Number(u256)
130
+ return new Uint8Array([((num >> 8) & 0xff) + CompactInt.twoBytePrefix, num & 0xff])
131
+ } else if (u256 < UnSigned.fourByteBound) {
132
+ const num = Number(u256)
133
+ return new Uint8Array([
134
+ ((num >> 24) & 0xff) + CompactInt.fourBytePrefix,
135
+ (num >> 16) & 0xff,
136
+ (num >> 8) & 0xff,
137
+ num & 0xff
138
+ ])
139
+ } else if (u256 < UnSigned.u256UpperBound) {
140
+ return toByteArray(u256, false, false)
141
+ } else {
142
+ throw Error(`Too large number for U256: ${u256}`)
143
+ }
144
+ }
145
+
146
+ export function encodeByteVec(bytes: string): Uint8Array {
147
+ if (!isHexString(bytes)) {
148
+ throw Error(`Given value ${bytes} is not a valid hex string`)
149
+ }
150
+
151
+ const buffer0 = Buffer.from(bytes, 'hex')
152
+ const buffer1 = Buffer.from(encodeI256(BigInt(buffer0.length)))
153
+ return Buffer.concat([buffer1, buffer0])
154
+ }
155
+
156
+ export function encodeAddress(address: string): Uint8Array {
157
+ return bs58.decode(address)
158
+ }
159
+
160
+ function invalidScriptField(tpe: string, value: Val): Error {
161
+ return Error(`Invalid script field ${value} for type ${tpe}`)
162
+ }
163
+
164
+ enum Instruction {
165
+ trueConst = 3,
166
+ falseConst = 4,
167
+ i256Const0 = 5,
168
+ i256Const1 = 6,
169
+ i256Const2 = 7,
170
+ i256Const3 = 8,
171
+ i256Const4 = 9,
172
+ i256Const5 = 10,
173
+ i256ConstN1 = 11,
174
+ u256Const0 = 12,
175
+ u256Const1 = 13,
176
+ u256Const2 = 14,
177
+ u256Const3 = 15,
178
+ u256Const4 = 16,
179
+ u256Const5 = 17,
180
+ i256Const = 18,
181
+ u256Const = 19,
182
+ bytesConst = 20,
183
+ addressConst = 21
184
+ }
185
+
186
+ // TODO: optimize
187
+ function encodeScriptFieldI256(value: bigint): Uint8Array {
188
+ return new Uint8Array([Instruction.i256Const, ...encodeI256(value)])
189
+ }
190
+
191
+ // TODO: optimize
192
+ function encodeScriptFieldU256(value: bigint): Uint8Array {
193
+ return new Uint8Array([Instruction.u256Const, ...encodeU256(value)])
194
+ }
195
+
196
+ export function encodeScriptFieldAsString(tpe: string, value: Val): string {
197
+ return Buffer.from(encodeScriptField(tpe, value)).toString('hex')
198
+ }
199
+
200
+ export function encodeScriptField(tpe: string, value: Val): Uint8Array {
201
+ switch (tpe) {
202
+ case 'Bool':
203
+ if (typeof value === 'boolean') {
204
+ const byte = value ? Instruction.trueConst : Instruction.falseConst
205
+ return new Uint8Array([byte])
206
+ }
207
+ break
208
+ case 'I256':
209
+ if (typeof value === 'number' && Number.isInteger(value)) {
210
+ return encodeScriptFieldI256(BigInt(value))
211
+ } else if (typeof value === 'bigint') {
212
+ return encodeScriptFieldI256(value)
213
+ }
214
+ break
215
+ case 'U256':
216
+ if (typeof value === 'number' && Number.isInteger(value)) {
217
+ return encodeScriptFieldU256(BigInt(value))
218
+ } else if (typeof value === 'bigint') {
219
+ return encodeScriptFieldU256(value)
220
+ }
221
+ break
222
+ case 'ByteVec':
223
+ if (typeof value === 'string') {
224
+ return new Uint8Array([Instruction.bytesConst, ...encodeByteVec(value)])
225
+ }
226
+ break
227
+ case 'Address':
228
+ if (typeof value === 'string') {
229
+ return new Uint8Array([Instruction.addressConst, ...encodeAddress(value)])
230
+ }
231
+ break
232
+ }
233
+
234
+ throw invalidScriptField(tpe, value)
235
+ }
236
+
237
+ const scriptFieldRegex = /\{([0-9]*)\}/g
238
+
239
+ export function buildScriptByteCode(bytecodeTemplate: string, fields: Fields, fieldsSig: node.FieldsSig): string {
240
+ return bytecodeTemplate.replace(scriptFieldRegex, (_, fieldIndex: string) => {
241
+ const fieldName = fieldsSig.names[`${fieldIndex}`]
242
+ const fieldType = fieldsSig.types[`${fieldIndex}`]
243
+ if (fieldName in fields) {
244
+ const fieldValue = fields[`${fieldName}`]
245
+ return encodeScriptFieldAsString(fieldType, fieldValue)
246
+ } else {
247
+ throw new Error(`The value of field ${fieldName} is not provided`)
248
+ }
249
+ })
250
+ }
251
+
252
+ export function buildContractByteCode(bytecode: string, fields: Fields, fieldsSig: node.FieldsSig): string {
253
+ const fieldsEncoded = fieldsSig.names.flatMap((fieldName, fieldIndex) => {
254
+ const fieldType = fieldsSig.types[`${fieldIndex}`]
255
+ if (fieldName in fields) {
256
+ const fieldValue = fields[`${fieldName}`]
257
+ return encodeContractField(fieldType, fieldValue)
258
+ } else {
259
+ throw new Error(`The value of field ${fieldName} is not provided`)
260
+ }
261
+ })
262
+ const fieldsLength = Buffer.from(encodeI256(BigInt(fieldsEncoded.length))).toString('hex')
263
+ return bytecode + fieldsLength + fieldsEncoded.map((f) => Buffer.from(f).toString('hex')).join('')
264
+ }
265
+
266
+ enum ApiValType {
267
+ Bool = 0,
268
+ I256 = 1,
269
+ U256 = 2,
270
+ ByteVec = 3,
271
+ Address = 4
272
+ }
273
+
274
+ function encodeContractFieldI256(value: bigint): Uint8Array {
275
+ return new Uint8Array([ApiValType.I256, ...encodeI256(value)])
276
+ }
277
+
278
+ function encodeContractFieldU256(value: bigint): Uint8Array {
279
+ return new Uint8Array([ApiValType.U256, ...encodeU256(value)])
280
+ }
281
+
282
+ function encodeContractFieldArray(tpe: string, val: Val): Uint8Array[] {
283
+ if (!Array.isArray(val)) {
284
+ throw new Error(`Expected array, got ${val}`)
285
+ }
286
+
287
+ const semiColonIndex = tpe.lastIndexOf(';')
288
+ if (semiColonIndex == -1) {
289
+ throw new Error(`Invalid Array type: ${tpe}`)
290
+ }
291
+
292
+ const subType = tpe.slice(1, semiColonIndex)
293
+ const dim = parseInt(tpe.slice(semiColonIndex + 1, -1))
294
+ if ((val as Val[]).length != dim) {
295
+ throw new Error(`Invalid val dimension: ${val}`)
296
+ } else {
297
+ return (val as Val[]).flatMap((v) => encodeContractField(subType, v))
298
+ }
299
+ }
300
+
301
+ export function encodeContractField(tpe: string, value: Val): Uint8Array[] {
302
+ switch (tpe) {
303
+ case 'Bool':
304
+ if (typeof value === 'boolean') {
305
+ const byte = value ? 1 : 0
306
+ return [new Uint8Array([ApiValType.Bool, byte])]
307
+ }
308
+ break
309
+ case 'I256':
310
+ if (typeof value === 'number' && Number.isInteger(value)) {
311
+ return [encodeContractFieldI256(BigInt(value))]
312
+ } else if (typeof value === 'bigint') {
313
+ return [encodeContractFieldI256(value)]
314
+ }
315
+ break
316
+ case 'U256':
317
+ if (typeof value === 'number' && Number.isInteger(value)) {
318
+ return [encodeContractFieldU256(BigInt(value))]
319
+ } else if (typeof value === 'bigint') {
320
+ return [encodeContractFieldU256(value)]
321
+ }
322
+ break
323
+ case 'ByteVec':
324
+ if (typeof value === 'string') {
325
+ return [new Uint8Array([ApiValType.ByteVec, ...encodeByteVec(value)])]
326
+ }
327
+ break
328
+ case 'Address':
329
+ if (typeof value === 'string') {
330
+ return [new Uint8Array([ApiValType.Address, ...encodeAddress(value)])]
331
+ }
332
+ break
333
+
334
+ default:
335
+ // Array type
336
+ return encodeContractFieldArray(tpe, value)
337
+ }
338
+
339
+ throw invalidVal(tpe, value)
340
+ }
341
+
342
+ function invalidVal(tpe: string, value: Val): Error {
343
+ return Error(`Invalid API value ${value} for type ${tpe}`)
344
+ }
345
+
346
+ // export function buildContractByteCode(
347
+ // compiled: node.TemplateContractByteCode,
348
+ // templateVariables: TemplateVariables
349
+ // ): string {
350
+ // const methodsBuilt = compiled.methodsByteCode.map((template) => buildByteCode(template, templateVariables))
351
+ // let count = 0
352
+ // const methodIndexes = methodsBuilt.map((hex) => {
353
+ // count += hex.length / 2
354
+ // return count
355
+ // })
356
+ // return (
357
+ // binToHex(encodeI256(BigInt(compiled.filedLength))) +
358
+ // binToHex(encodeI256(BigInt(methodIndexes.length))) +
359
+ // methodIndexes.map((index) => binToHex(encodeI256(BigInt(index)))).join('') +
360
+ // methodsBuilt.join('')
361
+ // )
362
+ // }
@@ -0,0 +1,36 @@
1
+ {
2
+ "hash": "16sR3EMn2BdFgENRhz6N2TJ78nfaADdv3prKXUQMaB6m3",
3
+ "details": {
4
+ "balance": "string",
5
+ "txNumber": 0
6
+ },
7
+ "transactions": [
8
+ {
9
+ "hash": "string",
10
+ "blockHash": "string",
11
+ "timestamp": 0,
12
+ "inputs": [
13
+ {
14
+ "outputRef": {
15
+ "hint": 0,
16
+ "key": "string"
17
+ },
18
+ "unlockScript": "string",
19
+ "txHashRef": "string",
20
+ "address": "string",
21
+ "amount": "string"
22
+ }
23
+ ],
24
+ "outputs": [
25
+ {
26
+ "amount": "string",
27
+ "address": "string",
28
+ "lockTime": 0,
29
+ "spent": "string"
30
+ }
31
+ ],
32
+ "gasAmount": 0,
33
+ "gasPrice": "string"
34
+ }
35
+ ]
36
+ }