@alephium/web3 0.0.3 → 0.1.0-rc.2
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/.editorconfig +13 -0
- package/.eslintignore +2 -0
- package/.eslintrc.json +21 -0
- package/README.md +2 -2
- package/contracts/add.ral +7 -3
- package/contracts/greeter.ral +3 -1
- package/contracts/greeter_interface.ral +3 -0
- package/contracts/greeter_main.ral +9 -0
- package/contracts/main.ral +3 -5
- package/dev/user.conf +8 -4
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/scripts/check-versions.d.ts +1 -0
- package/dist/scripts/check-versions.js +39 -0
- package/dist/{cli → scripts}/create-project.d.ts +0 -0
- package/dist/scripts/create-project.js +124 -0
- package/dist/scripts/header.d.ts +0 -0
- package/dist/scripts/header.js +18 -0
- package/dist/scripts/rename-gitignore.d.ts +1 -0
- package/dist/scripts/rename-gitignore.js +24 -0
- package/dist/scripts/start-devnet.d.ts +1 -0
- package/dist/scripts/start-devnet.js +131 -0
- package/dist/scripts/stop-devnet.d.ts +1 -0
- package/dist/scripts/stop-devnet.js +32 -0
- package/dist/{api → src/api}/api-alephium.d.ts +287 -168
- package/dist/{api → src/api}/api-alephium.js +497 -115
- package/dist/{api → src/api}/api-explorer.d.ts +117 -19
- package/dist/{api → src/api}/api-explorer.js +206 -46
- package/dist/src/api/index.d.ts +10 -0
- package/dist/src/api/index.js +55 -0
- package/dist/{lib → src}/constants.d.ts +0 -0
- package/dist/{lib → src}/constants.js +0 -0
- package/dist/src/contract/contract.d.ts +182 -0
- package/dist/src/contract/contract.js +760 -0
- package/dist/src/contract/events.d.ts +29 -0
- package/dist/src/contract/events.js +77 -0
- package/dist/src/contract/index.d.ts +3 -0
- package/dist/src/contract/index.js +32 -0
- package/dist/src/contract/ralph.d.ts +12 -0
- package/dist/src/contract/ralph.js +362 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +34 -0
- package/dist/src/signer/index.d.ts +2 -0
- package/dist/src/signer/index.js +31 -0
- package/dist/src/signer/node-wallet.d.ts +13 -0
- package/dist/src/signer/node-wallet.js +60 -0
- package/dist/src/signer/signer.d.ts +143 -0
- package/dist/src/signer/signer.js +184 -0
- package/dist/src/test/index.d.ts +7 -0
- package/dist/src/test/index.js +41 -0
- package/dist/src/test/privatekey-wallet.d.ts +12 -0
- package/dist/src/test/privatekey-wallet.js +68 -0
- package/dist/{lib → src/utils}/address.d.ts +0 -0
- package/dist/{lib → src/utils}/address.js +1 -1
- package/dist/{lib → src/utils}/bs58.d.ts +2 -2
- package/dist/{lib → src/utils}/bs58.js +3 -1
- package/dist/{lib → src/utils}/djb2.d.ts +0 -0
- package/dist/{lib → src/utils}/djb2.js +1 -1
- package/dist/src/utils/index.d.ts +6 -0
- package/dist/src/utils/index.js +35 -0
- package/dist/{lib → src/utils}/password-crypto.d.ts +0 -0
- package/dist/{lib → src/utils}/password-crypto.js +8 -7
- package/dist/src/utils/transaction.d.ts +2 -0
- package/dist/src/utils/transaction.js +58 -0
- package/dist/src/utils/utils.d.ts +30 -0
- package/dist/{lib → src/utils}/utils.js +83 -19
- package/gitignore +5 -4
- package/package.json +55 -41
- package/scripts/create-project.ts +136 -0
- package/scripts/header.js +17 -0
- package/scripts/start-devnet.js +3 -3
- package/src/api/api-alephium.ts +2323 -0
- package/src/api/api-explorer.ts +808 -0
- package/src/api/index.ts +35 -0
- package/src/constants.ts +20 -0
- package/src/contract/contract.ts +1014 -0
- package/src/contract/events.ts +102 -0
- package/src/contract/index.ts +21 -0
- package/src/contract/ralph.test.ts +178 -0
- package/src/contract/ralph.ts +362 -0
- package/src/fixtures/address.json +36 -0
- package/src/fixtures/balance.json +9 -0
- package/src/fixtures/self-clique.json +19 -0
- package/src/fixtures/transaction.json +13 -0
- package/src/fixtures/transactions.json +179 -0
- package/src/index.ts +24 -0
- package/src/signer/fixtures/genesis.json +26 -0
- package/src/signer/fixtures/wallets.json +26 -0
- package/src/signer/index.ts +20 -0
- package/src/signer/node-wallet.ts +74 -0
- package/src/signer/signer.ts +313 -0
- package/src/test/index.ts +32 -0
- package/src/test/privatekey-wallet.ts +58 -0
- package/src/utils/address.test.ts +47 -0
- package/src/utils/address.ts +39 -0
- package/src/utils/bs58.ts +26 -0
- package/src/utils/djb2.test.ts +35 -0
- package/src/utils/djb2.ts +25 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/password-crypto.test.ts +27 -0
- package/src/utils/password-crypto.ts +77 -0
- package/src/utils/transaction.test.ts +50 -0
- package/src/utils/transaction.ts +39 -0
- package/src/utils/utils.test.ts +160 -0
- package/src/utils/utils.ts +209 -0
- package/templates/{README.md → base/README.md} +4 -4
- package/templates/base/package.json +35 -0
- package/templates/base/src/greeter.ts +41 -0
- package/templates/base/tsconfig.json +19 -0
- package/templates/react/README.md +34 -0
- package/templates/react/config-overrides.js +18 -0
- package/templates/react/package.json +66 -0
- package/templates/react/src/App.tsx +42 -0
- package/templates/react/src/artifacts/greeter.ral.json +26 -0
- package/templates/react/src/artifacts/greeter_main.ral.json +22 -0
- package/templates/shared/.eslintrc.json +12 -0
- package/templates/shared/scripts/header.js +0 -0
- package/test/contract.test.ts +161 -0
- package/test/events.test.ts +139 -0
- package/webpack.config.js +1 -1
- package/contracts/greeter-main.ral +0 -8
- package/dist/cli/create-project.js +0 -87
- package/dist/lib/clique.d.ts +0 -23
- package/dist/lib/clique.js +0 -149
- package/dist/lib/contract.d.ts +0 -152
- package/dist/lib/contract.js +0 -711
- package/dist/lib/explorer.d.ts +0 -8
- package/dist/lib/explorer.js +0 -46
- package/dist/lib/index.d.ts +0 -12
- package/dist/lib/index.js +0 -60
- package/dist/lib/node.d.ts +0 -10
- package/dist/lib/node.js +0 -64
- package/dist/lib/numbers.d.ts +0 -7
- package/dist/lib/numbers.js +0 -128
- package/dist/lib/signer.d.ts +0 -17
- package/dist/lib/signer.js +0 -70
- package/dist/lib/storage-browser.d.ts +0 -9
- package/dist/lib/storage-browser.js +0 -52
- package/dist/lib/storage-node.d.ts +0 -9
- package/dist/lib/storage-node.js +0 -65
- package/dist/lib/utils.d.ts +0 -11
- package/dist/lib/wallet.d.ts +0 -30
- package/dist/lib/wallet.js +0 -142
- 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
|
+
}
|