@btc-vision/btc-runtime 1.1.11 → 1.2.1
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/package.json +12 -6
- package/runtime/buffer/BytesReader.ts +32 -0
- package/runtime/buffer/BytesWriter.ts +9 -16
- package/runtime/contracts/DeployableOP_20.ts +27 -33
- package/runtime/contracts/OP_NET.ts +4 -25
- package/runtime/env/{BTCEnvironment.ts → BlockchainEnvironment.ts} +41 -75
- package/runtime/env/classes/Block.ts +18 -0
- package/runtime/env/classes/Transaction.ts +47 -0
- package/runtime/env/classes/UTXO.ts +17 -0
- package/runtime/env/global.ts +16 -1
- package/runtime/env/index.ts +1 -1
- package/runtime/events/NetEvent.ts +0 -1
- package/runtime/events/predefined/MintEvent.ts +1 -0
- package/runtime/exports/index.ts +8 -14
- package/runtime/index.ts +10 -3
- package/runtime/tests/assert.ts +8 -0
- package/runtime/tests/env.ts +7 -0
- package/runtime/tests/tests.ts +25 -0
- package/runtime/types/SafeMath.ts +12 -12
- package/runtime/types/index.ts +2 -2
- package/runtime/utils/box.ts +115 -0
- package/runtime/utils/hex.ts +60 -0
- package/runtime/utils/index.ts +2 -0
- package/runtime/universal/ABIRegistry.ts +0 -27
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/btc-runtime",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Bitcoin Smart Contract Runtime",
|
|
5
5
|
"main": "btc/index.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "cross-env node scripts/asc tests/tests.ts"
|
|
8
|
+
},
|
|
6
9
|
"types": "btc/index.ts",
|
|
7
|
-
"scripts": {},
|
|
8
10
|
"keywords": [
|
|
9
11
|
"bitcoin",
|
|
10
12
|
"smart",
|
|
@@ -17,9 +19,12 @@
|
|
|
17
19
|
"author": "BlobMaster41",
|
|
18
20
|
"license": "MIT",
|
|
19
21
|
"devDependencies": {
|
|
22
|
+
"@types/mocha": "^10.0.8",
|
|
20
23
|
"@types/node": "^22.5.5",
|
|
21
|
-
"assemblyscript": "^0.27.
|
|
22
|
-
"
|
|
24
|
+
"assemblyscript": "^0.27.30",
|
|
25
|
+
"cross-env": "^7.0.3",
|
|
26
|
+
"ts-mocha": "^10.0.0",
|
|
27
|
+
"fs-extra": "^11.2.0"
|
|
23
28
|
},
|
|
24
29
|
"repository": {
|
|
25
30
|
"type": "git",
|
|
@@ -32,10 +37,11 @@
|
|
|
32
37
|
"runtime/*.ts",
|
|
33
38
|
"runtime/**/*.ts",
|
|
34
39
|
"!**/*.js.map",
|
|
35
|
-
"!**/*.tsbuildinfo"
|
|
40
|
+
"!**/*.tsbuildinfo",
|
|
41
|
+
"test/*.ts"
|
|
36
42
|
],
|
|
37
43
|
"dependencies": {
|
|
38
|
-
"@assemblyscript/loader": "^0.27.
|
|
44
|
+
"@assemblyscript/loader": "^0.27.30",
|
|
39
45
|
"@eslint/js": "^9.10.0",
|
|
40
46
|
"as-bignum": "^0.3.0",
|
|
41
47
|
"gulplog": "^2.2.0",
|
|
@@ -3,6 +3,8 @@ import { Selector } from '../math/abi';
|
|
|
3
3
|
import { u256 } from 'as-bignum/assembly';
|
|
4
4
|
import { Revert } from '../types/Revert';
|
|
5
5
|
import { Map } from '../generic/Map';
|
|
6
|
+
import { TransactionInput, TransactionOutput } from '../env/classes/UTXO';
|
|
7
|
+
import { StaticArray } from 'staticarray';
|
|
6
8
|
|
|
7
9
|
@final
|
|
8
10
|
export class BytesReader {
|
|
@@ -106,6 +108,36 @@ export class BytesReader {
|
|
|
106
108
|
return String.UTF8.decode(bytes.buffer);
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
public readTransactionInputs(): StaticArray<TransactionInput> {
|
|
112
|
+
const length = this.readU8();
|
|
113
|
+
const result = new StaticArray<TransactionInput>(length);
|
|
114
|
+
|
|
115
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
116
|
+
const txId = this.readBytes(32);
|
|
117
|
+
const outputIndex = this.readU8();
|
|
118
|
+
const scriptSig = this.readBytesWithLength();
|
|
119
|
+
|
|
120
|
+
result[i] = new TransactionInput(txId, outputIndex, scriptSig);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public readTransactionOutputs(): StaticArray<TransactionOutput> {
|
|
127
|
+
const length = this.readU8();
|
|
128
|
+
const result = new StaticArray<TransactionOutput>(length);
|
|
129
|
+
|
|
130
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
131
|
+
const index = this.readU8();
|
|
132
|
+
const scriptPubKey = this.readBytesWithLength();
|
|
133
|
+
const value = this.readU64();
|
|
134
|
+
|
|
135
|
+
result[i] = new TransactionOutput(index, scriptPubKey, value);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
109
141
|
public readTuple(): u256[] {
|
|
110
142
|
const length = this.readU32();
|
|
111
143
|
const result: u256[] = new Array<u256>(length);
|
|
@@ -11,10 +11,11 @@ export class BytesWriter {
|
|
|
11
11
|
private currentOffset: u32 = 0;
|
|
12
12
|
private buffer: DataView;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
const arrayBuffer = new ArrayBuffer(length);
|
|
14
|
+
private readonly typedArray: Uint8Array;
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
constructor(length: i32) {
|
|
17
|
+
const typedArray = (this.typedArray = new Uint8Array(length));
|
|
18
|
+
this.buffer = new DataView(typedArray.buffer);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
public bufferLength(): u32 {
|
|
@@ -63,12 +64,7 @@ export class BytesWriter {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
public writeU256(value: u256): void {
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
const bytes = value.toUint8Array(true);
|
|
69
|
-
for (let i: i32 = 0; i < 32; i++) {
|
|
70
|
-
this.writeU8(bytes[i] || 0);
|
|
71
|
-
}
|
|
67
|
+
this.writeBytesU8Array(value.toUint8Array());
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
public writeTuple(value: u256[]): void {
|
|
@@ -81,14 +77,11 @@ export class BytesWriter {
|
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
public writeBytes(value: Uint8Array): void {
|
|
84
|
-
this.
|
|
85
|
-
|
|
86
|
-
for (let i = 0; i < value.length; i++) {
|
|
87
|
-
this.writeU8(value[i]);
|
|
88
|
-
}
|
|
80
|
+
this.writeBytesU8Array(value);
|
|
89
81
|
}
|
|
90
82
|
|
|
91
|
-
|
|
83
|
+
@inline
|
|
84
|
+
public writeBytesU8Array(value: Uint8Array): void {
|
|
92
85
|
this.allocSafe(value.length);
|
|
93
86
|
|
|
94
87
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -196,7 +189,7 @@ export class BytesWriter {
|
|
|
196
189
|
}
|
|
197
190
|
|
|
198
191
|
public getBuffer(): Uint8Array {
|
|
199
|
-
return
|
|
192
|
+
return this.typedArray;
|
|
200
193
|
}
|
|
201
194
|
|
|
202
195
|
public toBytesReader(): BytesReader {
|
|
@@ -11,10 +11,11 @@ import { StoredU256 } from '../storage/StoredU256';
|
|
|
11
11
|
import { Address } from '../types/Address';
|
|
12
12
|
import { Revert } from '../types/Revert';
|
|
13
13
|
import { SafeMath } from '../types/SafeMath';
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
import { IOP_20 } from './interfaces/IOP_20';
|
|
16
16
|
import { OP20InitParameters } from './interfaces/OP20InitParameters';
|
|
17
17
|
import { OP_NET } from './OP_NET';
|
|
18
|
+
import { Calldata } from '../types';
|
|
18
19
|
|
|
19
20
|
const maxSupplyPointer: u16 = Blockchain.nextPointer;
|
|
20
21
|
const decimalsPointer: u16 = Blockchain.nextPointer;
|
|
@@ -94,7 +95,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
94
95
|
throw new Revert('Already initialized');
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
if (!skipOwnerVerification) this.onlyOwner(Blockchain.
|
|
98
|
+
if (!skipOwnerVerification) this.onlyOwner(Blockchain.tx.sender);
|
|
98
99
|
|
|
99
100
|
if (params.decimals > 32) {
|
|
100
101
|
throw new Revert('Decimals can not be more than 32');
|
|
@@ -118,7 +119,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
118
119
|
|
|
119
120
|
public approve(callData: Calldata): BytesWriter {
|
|
120
121
|
// Define the owner and spender
|
|
121
|
-
const owner = Blockchain.
|
|
122
|
+
const owner = Blockchain.tx.sender;
|
|
122
123
|
const spender: Address = callData.readAddress();
|
|
123
124
|
const value = callData.readU256();
|
|
124
125
|
|
|
@@ -180,28 +181,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
180
181
|
return response;
|
|
181
182
|
}
|
|
182
183
|
|
|
183
|
-
public
|
|
184
|
-
switch (method) {
|
|
185
|
-
case encodeSelector('allowance'):
|
|
186
|
-
return this.allowance(calldata);
|
|
187
|
-
case encodeSelector('approve'):
|
|
188
|
-
return this.approve(calldata);
|
|
189
|
-
case encodeSelector('balanceOf'):
|
|
190
|
-
return this.balanceOf(calldata);
|
|
191
|
-
case encodeSelector('burn'):
|
|
192
|
-
return this.burn(calldata);
|
|
193
|
-
case encodeSelector('mint'):
|
|
194
|
-
return this.mint(calldata);
|
|
195
|
-
case encodeSelector('transfer'):
|
|
196
|
-
return this.transfer(calldata);
|
|
197
|
-
case encodeSelector('transferFrom'):
|
|
198
|
-
return this.transferFrom(calldata);
|
|
199
|
-
default:
|
|
200
|
-
return super.callMethod(method, calldata);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
public callView(method: Selector): BytesWriter {
|
|
184
|
+
public execute(method: Selector, calldata: Calldata): BytesWriter {
|
|
205
185
|
let response: BytesWriter;
|
|
206
186
|
|
|
207
187
|
switch (method) {
|
|
@@ -225,8 +205,22 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
225
205
|
response = new BytesWriter(32);
|
|
226
206
|
response.writeU256(this.maxSupply);
|
|
227
207
|
break;
|
|
208
|
+
case encodeSelector('allowance'):
|
|
209
|
+
return this.allowance(calldata);
|
|
210
|
+
case encodeSelector('approve'):
|
|
211
|
+
return this.approve(calldata);
|
|
212
|
+
case encodeSelector('balanceOf'):
|
|
213
|
+
return this.balanceOf(calldata);
|
|
214
|
+
case encodeSelector('burn'):
|
|
215
|
+
return this.burn(calldata);
|
|
216
|
+
case encodeSelector('mint'):
|
|
217
|
+
return this.mint(calldata);
|
|
218
|
+
case encodeSelector('transfer'):
|
|
219
|
+
return this.transfer(calldata);
|
|
220
|
+
case encodeSelector('transferFrom'):
|
|
221
|
+
return this.transferFrom(calldata);
|
|
228
222
|
default:
|
|
229
|
-
return super.
|
|
223
|
+
return super.execute(method, calldata);
|
|
230
224
|
}
|
|
231
225
|
|
|
232
226
|
return response;
|
|
@@ -264,16 +258,16 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
264
258
|
throw new Revert(`No tokens`);
|
|
265
259
|
}
|
|
266
260
|
|
|
267
|
-
if (onlyOwner) this.onlyOwner(Blockchain.
|
|
261
|
+
if (onlyOwner) this.onlyOwner(Blockchain.tx.sender);
|
|
268
262
|
|
|
269
263
|
if (this._totalSupply.value < value) throw new Revert(`Insufficient total supply.`);
|
|
270
|
-
if (!this.balanceOfMap.has(Blockchain.
|
|
264
|
+
if (!this.balanceOfMap.has(Blockchain.tx.sender)) throw new Revert('No balance');
|
|
271
265
|
|
|
272
|
-
const balance: u256 = this.balanceOfMap.get(Blockchain.
|
|
266
|
+
const balance: u256 = this.balanceOfMap.get(Blockchain.tx.sender);
|
|
273
267
|
if (balance < value) throw new Revert(`Insufficient balance`);
|
|
274
268
|
|
|
275
269
|
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
276
|
-
this.balanceOfMap.set(Blockchain.
|
|
270
|
+
this.balanceOfMap.set(Blockchain.tx.sender, newBalance);
|
|
277
271
|
|
|
278
272
|
// @ts-expect-error TODO: Fix the typing because this is valid assembly-script syntax
|
|
279
273
|
this._totalSupply -= value;
|
|
@@ -283,7 +277,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
283
277
|
}
|
|
284
278
|
|
|
285
279
|
protected _mint(to: Address, value: u256, onlyOwner: boolean = true): boolean {
|
|
286
|
-
if (onlyOwner) this.onlyOwner(Blockchain.
|
|
280
|
+
if (onlyOwner) this.onlyOwner(Blockchain.tx.sender);
|
|
287
281
|
|
|
288
282
|
if (!this.balanceOfMap.has(to)) {
|
|
289
283
|
this.balanceOfMap.set(to, value);
|
|
@@ -304,7 +298,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
304
298
|
}
|
|
305
299
|
|
|
306
300
|
protected _transfer(to: string, value: u256): boolean {
|
|
307
|
-
const sender = Blockchain.
|
|
301
|
+
const sender = Blockchain.tx.sender;
|
|
308
302
|
|
|
309
303
|
if (!this.balanceOfMap.has(sender)) throw new Revert();
|
|
310
304
|
if (this.isSelf(sender)) throw new Revert('Can not transfer from self account');
|
|
@@ -359,7 +353,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
359
353
|
throw new Revert('Cannot transfer to or from dead address');
|
|
360
354
|
}
|
|
361
355
|
|
|
362
|
-
this._spendAllowance(from, Blockchain.
|
|
356
|
+
this._spendAllowance(from, Blockchain.tx.sender, value);
|
|
363
357
|
this._unsafeTransferFrom(from, to, value);
|
|
364
358
|
|
|
365
359
|
return true;
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { IBTC } from '../interfaces/IBTC';
|
|
2
2
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
3
3
|
import { Blockchain } from '../env';
|
|
4
|
-
import { Calldata } from '../universal/ABIRegistry';
|
|
5
4
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
6
5
|
import { encodeSelector, Selector } from '../math/abi';
|
|
7
6
|
import { Revert } from '../types/Revert';
|
|
8
7
|
import { MAX_EVENT_DATA_SIZE, NetEvent } from '../events/NetEvent';
|
|
9
|
-
import {
|
|
8
|
+
import { Calldata } from '../types';
|
|
10
9
|
|
|
11
10
|
export class OP_NET implements IBTC {
|
|
12
|
-
protected readonly instantiated: StoredBoolean = new StoredBoolean(
|
|
13
|
-
Blockchain.nextPointer,
|
|
14
|
-
false,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
11
|
public get address(): string {
|
|
18
12
|
return Blockchain.contractAddress;
|
|
19
13
|
}
|
|
@@ -22,24 +16,9 @@ export class OP_NET implements IBTC {
|
|
|
22
16
|
return Blockchain.owner;
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
public
|
|
26
|
-
return this.instantiated.value;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public onInstantiated(): void {
|
|
30
|
-
if (!this.isInstantiated) {
|
|
31
|
-
this.instantiated.value = true;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public callMethod(method: Selector, _calldata: Calldata): BytesWriter {
|
|
36
|
-
switch (method) {
|
|
37
|
-
default:
|
|
38
|
-
throw new Revert('Method not found');
|
|
39
|
-
}
|
|
40
|
-
}
|
|
19
|
+
public onDeployment(_calldata: Calldata): void {}
|
|
41
20
|
|
|
42
|
-
public
|
|
21
|
+
public execute(method: Selector, _calldata: Calldata): BytesWriter {
|
|
43
22
|
let response: BytesWriter;
|
|
44
23
|
|
|
45
24
|
switch (method) {
|
|
@@ -63,7 +42,7 @@ export class OP_NET implements IBTC {
|
|
|
63
42
|
throw new Error('Event data length exceeds maximum length.');
|
|
64
43
|
}
|
|
65
44
|
|
|
66
|
-
Blockchain.
|
|
45
|
+
Blockchain.emit(event);
|
|
67
46
|
}
|
|
68
47
|
|
|
69
48
|
protected isSelf(address: Address): boolean {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { Address, ADDRESS_BYTE_LENGTH
|
|
1
|
+
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
2
2
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
3
|
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
4
|
import { u256 } from 'as-bignum/assembly';
|
|
5
|
-
import { ABIRegistry } from '../universal/ABIRegistry';
|
|
6
5
|
import { BytesReader } from '../buffer/BytesReader';
|
|
7
6
|
import { encodePointerHash } from '../math/abi';
|
|
8
7
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
9
|
-
import {
|
|
8
|
+
import { NetEvent } from '../events/NetEvent';
|
|
10
9
|
import { Potential } from '../lang/Definitions';
|
|
11
10
|
import { OP_NET } from '../contracts/OP_NET';
|
|
12
11
|
import { PointerStorage } from '../types';
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
callContract,
|
|
15
14
|
deploy,
|
|
16
15
|
deployFromAddress,
|
|
16
|
+
emit,
|
|
17
17
|
encodeAddress,
|
|
18
18
|
loadPointer,
|
|
19
19
|
log,
|
|
@@ -21,44 +21,44 @@ import {
|
|
|
21
21
|
} from './global';
|
|
22
22
|
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
23
23
|
import { MapU256 } from '../generic/MapU256';
|
|
24
|
+
import { Block } from './classes/Block';
|
|
25
|
+
import { Transaction } from './classes/Transaction';
|
|
24
26
|
|
|
25
27
|
export * from '../env/global';
|
|
26
28
|
|
|
29
|
+
export function runtimeError(msg: string): Error {
|
|
30
|
+
return new Error(`RuntimeException: ${msg}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
@final
|
|
28
34
|
export class BlockchainEnvironment {
|
|
29
35
|
private static readonly MAX_U16: u16 = 65535;
|
|
30
|
-
|
|
36
|
+
|
|
31
37
|
public readonly DEAD_ADDRESS: Address = 'bc1dead';
|
|
32
|
-
private storage: PointerStorage = new MapU256();
|
|
33
|
-
private events: NetEvent[] = [];
|
|
34
|
-
private currentBlock: u256 = u256.Zero;
|
|
35
38
|
|
|
39
|
+
private storage: PointerStorage = new MapU256();
|
|
36
40
|
private _selfContract: Potential<OP_NET> = null;
|
|
37
41
|
|
|
38
|
-
private
|
|
42
|
+
private _block: Potential<Block> = null;
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
@inline
|
|
45
|
+
public get block(): Block {
|
|
46
|
+
if (!this._block) {
|
|
47
|
+
throw this.error('Block is required');
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
return this.
|
|
50
|
+
return this._block as Block;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
private
|
|
53
|
+
private _tx: Potential<Transaction> = null;
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
@inline
|
|
56
|
+
public get tx(): Transaction {
|
|
57
|
+
if (!this._tx) {
|
|
58
|
+
throw this.error('Transaction is required');
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
return this.
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private _timestamp: u64 = 0;
|
|
59
|
-
|
|
60
|
-
public get timestamp(): u64 {
|
|
61
|
-
return this._timestamp;
|
|
61
|
+
return this._tx as Transaction;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
private _contract: Potential<() => OP_NET> = null;
|
|
@@ -105,25 +105,24 @@ export class BlockchainEnvironment {
|
|
|
105
105
|
return this._contractAddress as Address;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
public get blockNumber(): u256 {
|
|
109
|
-
return this.currentBlock;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
public get blockNumberU64(): u64 {
|
|
113
|
-
return this.currentBlock.toU64();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
108
|
public setEnvironment(data: Uint8Array): void {
|
|
117
109
|
const reader: BytesReader = new BytesReader(data);
|
|
118
110
|
|
|
119
|
-
this.
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
this._tx = new Transaction(
|
|
112
|
+
reader.readAddress(),
|
|
113
|
+
reader.readAddress(),
|
|
114
|
+
reader.readBytes(32),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const currentBlock = reader.readU256();
|
|
122
118
|
|
|
123
119
|
this._owner = reader.readAddress();
|
|
124
120
|
this._contractAddress = reader.readAddress();
|
|
125
121
|
|
|
126
|
-
|
|
122
|
+
const medianTimestamp = reader.readU64();
|
|
123
|
+
const safeRnd64 = reader.readU64();
|
|
124
|
+
|
|
125
|
+
this._block = new Block(currentBlock, medianTimestamp, safeRnd64);
|
|
127
126
|
|
|
128
127
|
this.createContractIfNotExists();
|
|
129
128
|
}
|
|
@@ -154,32 +153,14 @@ export class BlockchainEnvironment {
|
|
|
154
153
|
log(buffer);
|
|
155
154
|
}
|
|
156
155
|
|
|
157
|
-
public
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
156
|
+
public emit(event: NetEvent): void {
|
|
157
|
+
const data = event.getEventData();
|
|
158
|
+
const buffer = new BytesWriter(event.eventType.length + 6 + data.byteLength);
|
|
161
159
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
public getEvents(): Uint8Array {
|
|
166
|
-
const eventLength: u16 = u16(this.events.length);
|
|
167
|
-
if (eventLength > MAX_EVENTS) {
|
|
168
|
-
throw this.error('Too many events');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const buffer: BytesWriter = new BytesWriter(this.getEventSize());
|
|
172
|
-
buffer.writeU16(eventLength);
|
|
173
|
-
|
|
174
|
-
for (let i: u8 = 0; i < eventLength; i++) {
|
|
175
|
-
const event: NetEvent = this.events[i];
|
|
176
|
-
|
|
177
|
-
buffer.writeStringWithLength(event.eventType);
|
|
178
|
-
buffer.writeU64(0); //event.getEventDataSelector()
|
|
179
|
-
buffer.writeBytesWithLength(event.getEventData());
|
|
180
|
-
}
|
|
160
|
+
buffer.writeStringWithLength(event.eventType);
|
|
161
|
+
buffer.writeBytesWithLength(data);
|
|
181
162
|
|
|
182
|
-
|
|
163
|
+
emit(buffer.getBuffer());
|
|
183
164
|
}
|
|
184
165
|
|
|
185
166
|
public encodeVirtualAddress(virtualAddress: Uint8Array): Address {
|
|
@@ -260,21 +241,6 @@ export class BlockchainEnvironment {
|
|
|
260
241
|
this._internalSetStorageAt(pointerHash, value);
|
|
261
242
|
}
|
|
262
243
|
|
|
263
|
-
public getMethodSelectors(): Uint8Array {
|
|
264
|
-
return ABIRegistry.getMethodSelectors();
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private getEventSize(): u32 {
|
|
268
|
-
let size: u32 = 2;
|
|
269
|
-
|
|
270
|
-
for (let i: u32 = 0; i < <u32>this.events.length; i++) {
|
|
271
|
-
const event: NetEvent = this.events[i];
|
|
272
|
-
size += 2 + event.eventType.length + 8 + event.length + 4;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return size;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
244
|
private createContractIfNotExists(): void {
|
|
279
245
|
if (!this._contract) {
|
|
280
246
|
throw this.error('Contract is required');
|
|
@@ -286,7 +252,7 @@ export class BlockchainEnvironment {
|
|
|
286
252
|
}
|
|
287
253
|
|
|
288
254
|
private error(msg: string): Error {
|
|
289
|
-
return
|
|
255
|
+
return runtimeError(msg);
|
|
290
256
|
}
|
|
291
257
|
|
|
292
258
|
private _internalSetStorageAt(pointerHash: u256, value: MemorySlotData<u256>): void {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
|
|
3
|
+
@final
|
|
4
|
+
export class Block {
|
|
5
|
+
private readonly u64BlockNumber: u64;
|
|
6
|
+
|
|
7
|
+
public constructor(
|
|
8
|
+
public readonly number: u256,
|
|
9
|
+
public readonly medianTimestamp: u64,
|
|
10
|
+
public readonly safeRnd64: u64,
|
|
11
|
+
) {
|
|
12
|
+
this.u64BlockNumber = number.toU64();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public get numberU64(): u64 {
|
|
16
|
+
return this.u64BlockNumber;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Address } from '../../types/Address';
|
|
2
|
+
import { TransactionInput, TransactionOutput } from './UTXO';
|
|
3
|
+
import { Potential } from '../../lang/Definitions';
|
|
4
|
+
import { StaticArray } from 'staticarray';
|
|
5
|
+
import { BytesReader } from '../../buffer/BytesReader';
|
|
6
|
+
import { inputs, outputs } from '../global';
|
|
7
|
+
|
|
8
|
+
@final
|
|
9
|
+
export class Transaction {
|
|
10
|
+
public constructor(
|
|
11
|
+
public readonly sender: Address, // "immediate caller"
|
|
12
|
+
public readonly origin: Address, // "leftmost thing in the call chain"
|
|
13
|
+
public readonly id: Uint8Array,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
private _inputs: Potential<StaticArray<TransactionInput>> = null;
|
|
17
|
+
|
|
18
|
+
public get inputs(): StaticArray<TransactionInput> {
|
|
19
|
+
if (!this._inputs) {
|
|
20
|
+
this._inputs = this.loadInputs();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return this._inputs;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private _outputs: Potential<StaticArray<TransactionOutput>> = null;
|
|
27
|
+
|
|
28
|
+
public get outputs(): StaticArray<TransactionOutput> {
|
|
29
|
+
if (!this._outputs) {
|
|
30
|
+
this._outputs = this.loadOutputs();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return this._outputs;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private loadInputs(): StaticArray<TransactionInput> {
|
|
37
|
+
const buffer = new BytesReader(inputs());
|
|
38
|
+
|
|
39
|
+
return buffer.readTransactionInputs();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private loadOutputs(): StaticArray<TransactionOutput> {
|
|
43
|
+
const buffer = new BytesReader(outputs());
|
|
44
|
+
|
|
45
|
+
return buffer.readTransactionOutputs();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@final
|
|
2
|
+
export class TransactionInput {
|
|
3
|
+
public constructor(
|
|
4
|
+
public readonly txId: Uint8Array,
|
|
5
|
+
public readonly outputIndex: u8,
|
|
6
|
+
public readonly scriptSig: Uint8Array,
|
|
7
|
+
) {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@final
|
|
11
|
+
export class TransactionOutput {
|
|
12
|
+
public constructor(
|
|
13
|
+
public readonly index: u8,
|
|
14
|
+
public readonly scriptPubKey: Uint8Array,
|
|
15
|
+
public readonly value: u64,
|
|
16
|
+
) {}
|
|
17
|
+
}
|
package/runtime/env/global.ts
CHANGED
|
@@ -22,11 +22,26 @@ export declare function callContract(data: Uint8Array): Uint8Array;
|
|
|
22
22
|
@external('env', 'log')
|
|
23
23
|
export declare function log(data: Uint8Array): void;
|
|
24
24
|
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
@external('env', 'emit')
|
|
27
|
+
export declare function emit(data: Uint8Array): void;
|
|
28
|
+
|
|
25
29
|
// @ts-ignore
|
|
26
30
|
@external('env', 'encodeAddress')
|
|
27
31
|
export declare function encodeAddress(data: Uint8Array): Uint8Array;
|
|
28
32
|
|
|
29
|
-
|
|
30
33
|
// @ts-ignore
|
|
31
34
|
@external('env', 'sha256')
|
|
32
35
|
export declare function sha256(data: Uint8Array): Uint8Array;
|
|
36
|
+
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
@external('env', 'ripemd160')
|
|
39
|
+
export declare function ripemd160(data: Uint8Array): Uint8Array;
|
|
40
|
+
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
@external('env', 'inputs')
|
|
43
|
+
export declare function inputs(): Uint8Array;
|
|
44
|
+
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
@external('env', 'outputs')
|
|
47
|
+
export declare function outputs(): Uint8Array;
|
package/runtime/env/index.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { BytesWriter } from '../buffer/BytesWriter';
|
|
|
2
2
|
import { Revert } from '../types/Revert';
|
|
3
3
|
|
|
4
4
|
export const MAX_EVENT_DATA_SIZE: u32 = 352; // 352 bytes max per event.
|
|
5
|
-
export const MAX_EVENTS: u16 = 1000; // 1000 events max per transactions.
|
|
6
5
|
|
|
7
6
|
export abstract class NetEvent {
|
|
8
7
|
private readonly buffer: Uint8Array;
|
|
@@ -7,6 +7,7 @@ import { Address, ADDRESS_BYTE_LENGTH } from '../../types/Address';
|
|
|
7
7
|
export class MintEvent extends NetEvent {
|
|
8
8
|
constructor(address: Address, amount: u256) {
|
|
9
9
|
const data: BytesWriter = new BytesWriter(32 + ADDRESS_BYTE_LENGTH);
|
|
10
|
+
|
|
10
11
|
data.writeAddress(address);
|
|
11
12
|
data.writeU256(amount);
|
|
12
13
|
|
package/runtime/exports/index.ts
CHANGED
|
@@ -1,27 +1,21 @@
|
|
|
1
|
-
import { Calldata } from '../universal/ABIRegistry';
|
|
2
1
|
import { Blockchain } from '../env';
|
|
3
|
-
import { Selector } from '../math/abi';
|
|
4
2
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
5
3
|
import { BytesReader } from '../buffer/BytesReader';
|
|
4
|
+
import { Selector } from '../math/abi';
|
|
5
|
+
import { Calldata } from '../types';
|
|
6
6
|
|
|
7
|
-
export function
|
|
7
|
+
export function execute(data: Uint8Array): Uint8Array {
|
|
8
8
|
const calldata: Calldata = new BytesReader(data);
|
|
9
|
-
const
|
|
9
|
+
const selector: Selector = calldata.readSelector();
|
|
10
|
+
const result: BytesWriter = Blockchain.contract.execute(selector, calldata);
|
|
10
11
|
|
|
11
12
|
return result.getBuffer();
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export function
|
|
15
|
-
const
|
|
16
|
-
return result.getBuffer();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function getEvents(): Uint8Array {
|
|
20
|
-
return Blockchain.getEvents();
|
|
21
|
-
}
|
|
15
|
+
export function onDeploy(data: Uint8Array): void {
|
|
16
|
+
const calldata: Calldata = new BytesReader(data);
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
return Blockchain.getMethodSelectors();
|
|
18
|
+
Blockchain.contract.onDeployment(calldata);
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
export function setEnvironment(data: Uint8Array): void {
|
package/runtime/index.ts
CHANGED
|
@@ -19,9 +19,15 @@ export * from './interfaces/DeployContractResponse';
|
|
|
19
19
|
export * from './events/NetEvent';
|
|
20
20
|
export * from './events/predefined';
|
|
21
21
|
|
|
22
|
+
/** Env */
|
|
23
|
+
export * from './env/classes/UTXO';
|
|
24
|
+
export * from './env/classes/Transaction';
|
|
25
|
+
export * from './env/classes/Block';
|
|
26
|
+
|
|
22
27
|
/** Types */
|
|
23
28
|
export * from './generic/Map';
|
|
24
29
|
export * from './interfaces/IBTC';
|
|
30
|
+
export * from './types';
|
|
25
31
|
|
|
26
32
|
/** Definitions */
|
|
27
33
|
export * from './lang/Definitions';
|
|
@@ -49,9 +55,10 @@ export * from './storage/StoredString';
|
|
|
49
55
|
export * from './storage/StoredBoolean';
|
|
50
56
|
export * from './storage/Serializable';
|
|
51
57
|
|
|
52
|
-
/** Universal */
|
|
53
|
-
export * from './universal/ABIRegistry';
|
|
54
|
-
|
|
55
58
|
/** Shared libraries */
|
|
56
59
|
export * from './shared-libraries/TransferHelper';
|
|
57
60
|
export * from './shared-libraries/OP20Utils';
|
|
61
|
+
|
|
62
|
+
/** Utils */
|
|
63
|
+
export * from './utils/hex';
|
|
64
|
+
export * from './utils/box';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BytesWriter } from "../buffer/BytesWriter";
|
|
2
|
+
import { u256 } from "as-bignum/assembly";
|
|
3
|
+
import { Blockchain } from "../env";
|
|
4
|
+
import { Box } from "../utils/box";
|
|
5
|
+
import { log } from "./env";
|
|
6
|
+
import { assertEq } from "./assert";
|
|
7
|
+
|
|
8
|
+
export function test_encode(): void {
|
|
9
|
+
const writer = new BytesWriter(64);
|
|
10
|
+
writer.writeU256(u256.from(10));
|
|
11
|
+
writer.writeU256(u256.from(20));
|
|
12
|
+
const buffer = writer.getBuffer().buffer;
|
|
13
|
+
assertEq(Box.from(buffer).toHexString(), "0x0a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function test_log(): void {
|
|
17
|
+
Blockchain.log("test logging test: OK!");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function test_writeStringWithLength(): void {
|
|
21
|
+
const s = 'test write';
|
|
22
|
+
const writer = new BytesWriter(s.length + 2);
|
|
23
|
+
writer.writeStringWithLength(s);
|
|
24
|
+
assertEq(Box.from(writer.getBuffer().buffer).toHexString(), "0x0a0074657374207772697465");
|
|
25
|
+
}
|
|
@@ -35,8 +35,8 @@ export class SafeMath {
|
|
|
35
35
|
throw new Error('SafeMath: modulo by zero');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const divResult = SafeMath.div(a, b);
|
|
39
|
+
const product = SafeMath.mul(divResult, b);
|
|
40
40
|
return SafeMath.sub(a, product);
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -121,16 +121,16 @@ export class SafeMath {
|
|
|
121
121
|
if (u256.gt(y, u256.fromU32(3))) {
|
|
122
122
|
let z = y;
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
const u246_2 = u256.fromU32(2);
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
const d = SafeMath.div(y, u246_2);
|
|
127
127
|
let x = SafeMath.add(d, u256.One);
|
|
128
128
|
|
|
129
129
|
while (u256.lt(x, z)) {
|
|
130
130
|
z = x;
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
const u = SafeMath.div(y, x);
|
|
133
|
+
const y2 = u256.add(u, x);
|
|
134
134
|
|
|
135
135
|
x = SafeMath.div(y2, u246_2);
|
|
136
136
|
}
|
|
@@ -150,8 +150,8 @@ export class SafeMath {
|
|
|
150
150
|
return value.clone();
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
const totalBits = 256;
|
|
154
|
+
const bitsPerSegment = 64;
|
|
155
155
|
|
|
156
156
|
// Normalize shift to be within 0-255 range
|
|
157
157
|
shift &= 255;
|
|
@@ -161,12 +161,12 @@ export class SafeMath {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// Determine how many full 64-bit segments we are shifting
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
const segmentShift = (shift / bitsPerSegment) | 0;
|
|
165
|
+
const bitShift = shift % bitsPerSegment;
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
const segments = [value.lo1, value.lo2, value.hi1, value.hi2];
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
const result = new Array<u64>(4).fill(0);
|
|
170
170
|
|
|
171
171
|
for (let i = 0; i < segments.length; i++) {
|
|
172
172
|
if (i + segmentShift < segments.length) {
|
package/runtime/types/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Map } from '../generic/Map';
|
|
|
2
2
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
3
|
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
4
|
import { u256 } from 'as-bignum/assembly';
|
|
5
|
-
import {
|
|
5
|
+
import { BytesReader } from '../buffer/BytesReader';
|
|
6
6
|
|
|
7
7
|
export type PointerStorage = Map<MemorySlotPointer, MemorySlotData<u256>>;
|
|
8
|
-
export type
|
|
8
|
+
export type Calldata = NonNullable<BytesReader>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { encodeHex, encodeHexUTF8 } from "./hex";
|
|
2
|
+
|
|
3
|
+
export function nullptr<T>(): T {
|
|
4
|
+
return changetype<T>(0);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class Box {
|
|
8
|
+
public start: usize;
|
|
9
|
+
public len: usize;
|
|
10
|
+
constructor(start: usize, len: usize) {
|
|
11
|
+
this.start = start;
|
|
12
|
+
this.len = len;
|
|
13
|
+
}
|
|
14
|
+
toHexString(): string {
|
|
15
|
+
return encodeHex(this.start, this.len);
|
|
16
|
+
}
|
|
17
|
+
toHexUTF8(): ArrayBuffer {
|
|
18
|
+
return encodeHexUTF8(this.start, this.len);
|
|
19
|
+
}
|
|
20
|
+
static concat(data: Array<Box>): ArrayBuffer {
|
|
21
|
+
const result = new ArrayBuffer(
|
|
22
|
+
data.reduce<i32>((r: i32, v: Box, i: i32, ary: Array<Box>) => {
|
|
23
|
+
return r + <i32>v.len;
|
|
24
|
+
}, 0),
|
|
25
|
+
);
|
|
26
|
+
data.reduce<usize>((r: usize, v: Box, i: i32, ary: Array<Box>) => {
|
|
27
|
+
memory.copy(r, v.start, v.len);
|
|
28
|
+
return r + v.len;
|
|
29
|
+
}, changetype<usize>(result));
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
shift(): Box {
|
|
34
|
+
if (this.len == 0) {
|
|
35
|
+
return nullptr<Box>();
|
|
36
|
+
}
|
|
37
|
+
this.start = this.start + 1;
|
|
38
|
+
this.len = this.len - 1;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
sliceFrom(start: usize): Box {
|
|
43
|
+
return new Box(this.start + start, this.len - start);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
sliceTo(ptr: usize): Box {
|
|
47
|
+
if (ptr > this.start + this.len) {
|
|
48
|
+
throw new Error("ptr is out of bounds");
|
|
49
|
+
}
|
|
50
|
+
return new Box(this.start, ptr - this.start);
|
|
51
|
+
}
|
|
52
|
+
shrinkFront(distance: usize): Box {
|
|
53
|
+
this.start = this.start + distance;
|
|
54
|
+
this.len = this.len - distance;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
growFront(distance: usize): Box {
|
|
58
|
+
this.start = this.start - distance;
|
|
59
|
+
this.len = this.len + distance;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
shrinkBack(distance: usize): Box {
|
|
63
|
+
this.len = this.len - distance;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
growBack(distance: usize): Box {
|
|
67
|
+
this.len = this.len + distance;
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
setLength(len: usize): Box {
|
|
71
|
+
this.len = len;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
toArrayBuffer(): ArrayBuffer {
|
|
75
|
+
const result = new ArrayBuffer(<i32>this.len);
|
|
76
|
+
memory.copy(changetype<usize>(result), this.start, this.len);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
isEmpty(): boolean {
|
|
80
|
+
return this.len == 0;
|
|
81
|
+
}
|
|
82
|
+
static from(data: ArrayBuffer): Box {
|
|
83
|
+
return new Box(changetype<usize>(data), data.byteLength);
|
|
84
|
+
}
|
|
85
|
+
static copy(data: ArrayBuffer): Box {
|
|
86
|
+
const ptr = heap.alloc(data.byteLength);
|
|
87
|
+
memory.copy(ptr, changetype<usize>(data), <usize>data.byteLength);
|
|
88
|
+
return new Box(ptr, <usize>data.byteLength);
|
|
89
|
+
}
|
|
90
|
+
static freeCopy(v: Box): void {
|
|
91
|
+
heap.free(v.start);
|
|
92
|
+
}
|
|
93
|
+
static fromTyped<T>(v: T): Box {
|
|
94
|
+
// const buffer = new ArrayBuffer(sizeof<T>(v));
|
|
95
|
+
const buffer = new ArrayBuffer(offsetof<T>());
|
|
96
|
+
store<T>(changetype<usize>(buffer), v);
|
|
97
|
+
return Box.copy(buffer);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export class RCBox extends Box {
|
|
101
|
+
public buffer: ArrayBuffer;
|
|
102
|
+
constructor(v: ArrayBuffer) {
|
|
103
|
+
super(changetype<usize>(v), <usize>v.byteLength);
|
|
104
|
+
this.buffer = v;
|
|
105
|
+
}
|
|
106
|
+
static from(v: ArrayBuffer): RCBox {
|
|
107
|
+
return new RCBox(v);
|
|
108
|
+
}
|
|
109
|
+
static fromTyped<T>(v: T): RCBox {
|
|
110
|
+
// const buffer = new ArrayBuffer(sizeof<T>(v));
|
|
111
|
+
const buffer = new ArrayBuffer(offsetof<T>());
|
|
112
|
+
store<T>(changetype<usize>(buffer), v);
|
|
113
|
+
return RCBox.from(buffer);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const hexLookupTable: StaticArray<u8> = [
|
|
2
|
+
48, 48, 48, 49, 48, 50, 48, 51, 48, 52, 48, 53, 48, 54, 48, 55, 48, 56, 48,
|
|
3
|
+
57, 48, 97, 48, 98, 48, 99, 48, 100, 48, 101, 48, 102, 49, 48, 49, 49, 49, 50,
|
|
4
|
+
49, 51, 49, 52, 49, 53, 49, 54, 49, 55, 49, 56, 49, 57, 49, 97, 49, 98, 49,
|
|
5
|
+
99, 49, 100, 49, 101, 49, 102, 50, 48, 50, 49, 50, 50, 50, 51, 50, 52, 50, 53,
|
|
6
|
+
50, 54, 50, 55, 50, 56, 50, 57, 50, 97, 50, 98, 50, 99, 50, 100, 50, 101, 50,
|
|
7
|
+
102, 51, 48, 51, 49, 51, 50, 51, 51, 51, 52, 51, 53, 51, 54, 51, 55, 51, 56,
|
|
8
|
+
51, 57, 51, 97, 51, 98, 51, 99, 51, 100, 51, 101, 51, 102, 52, 48, 52, 49, 52,
|
|
9
|
+
50, 52, 51, 52, 52, 52, 53, 52, 54, 52, 55, 52, 56, 52, 57, 52, 97, 52, 98,
|
|
10
|
+
52, 99, 52, 100, 52, 101, 52, 102, 53, 48, 53, 49, 53, 50, 53, 51, 53, 52, 53,
|
|
11
|
+
53, 53, 54, 53, 55, 53, 56, 53, 57, 53, 97, 53, 98, 53, 99, 53, 100, 53, 101,
|
|
12
|
+
53, 102, 54, 48, 54, 49, 54, 50, 54, 51, 54, 52, 54, 53, 54, 54, 54, 55, 54,
|
|
13
|
+
56, 54, 57, 54, 97, 54, 98, 54, 99, 54, 100, 54, 101, 54, 102, 55, 48, 55, 49,
|
|
14
|
+
55, 50, 55, 51, 55, 52, 55, 53, 55, 54, 55, 55, 55, 56, 55, 57, 55, 97, 55,
|
|
15
|
+
98, 55, 99, 55, 100, 55, 101, 55, 102, 56, 48, 56, 49, 56, 50, 56, 51, 56, 52,
|
|
16
|
+
56, 53, 56, 54, 56, 55, 56, 56, 56, 57, 56, 97, 56, 98, 56, 99, 56, 100, 56,
|
|
17
|
+
101, 56, 102, 57, 48, 57, 49, 57, 50, 57, 51, 57, 52, 57, 53, 57, 54, 57, 55,
|
|
18
|
+
57, 56, 57, 57, 57, 97, 57, 98, 57, 99, 57, 100, 57, 101, 57, 102, 97, 48, 97,
|
|
19
|
+
49, 97, 50, 97, 51, 97, 52, 97, 53, 97, 54, 97, 55, 97, 56, 97, 57, 97, 97,
|
|
20
|
+
97, 98, 97, 99, 97, 100, 97, 101, 97, 102, 98, 48, 98, 49, 98, 50, 98, 51, 98,
|
|
21
|
+
52, 98, 53, 98, 54, 98, 55, 98, 56, 98, 57, 98, 97, 98, 98, 98, 99, 98, 100,
|
|
22
|
+
98, 101, 98, 102, 99, 48, 99, 49, 99, 50, 99, 51, 99, 52, 99, 53, 99, 54, 99,
|
|
23
|
+
55, 99, 56, 99, 57, 99, 97, 99, 98, 99, 99, 99, 100, 99, 101, 99, 102, 100,
|
|
24
|
+
48, 100, 49, 100, 50, 100, 51, 100, 52, 100, 53, 100, 54, 100, 55, 100, 56,
|
|
25
|
+
100, 57, 100, 97, 100, 98, 100, 99, 100, 100, 100, 101, 100, 102, 101, 48,
|
|
26
|
+
101, 49, 101, 50, 101, 51, 101, 52, 101, 53, 101, 54, 101, 55, 101, 56, 101,
|
|
27
|
+
57, 101, 97, 101, 98, 101, 99, 101, 100, 101, 101, 101, 102, 102, 48, 102, 49,
|
|
28
|
+
102, 50, 102, 51, 102, 52, 102, 53, 102, 54, 102, 55, 102, 56, 102, 57, 102,
|
|
29
|
+
97, 102, 98, 102, 99, 102, 100, 102, 101, 102, 102,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export function encodeHexUTF8(start: usize, len: usize): ArrayBuffer {
|
|
33
|
+
let result = new ArrayBuffer(2 + <i32>len * 2);
|
|
34
|
+
store<u16>(changetype<usize>(result), <u16>0x7830);
|
|
35
|
+
for (let i: usize = 0; i < len; i++) {
|
|
36
|
+
store<u16>(
|
|
37
|
+
2 + changetype<usize>(result) + i * 2,
|
|
38
|
+
load<u16>(changetype<usize>(hexLookupTable) + 2 * load<u8>(start + i)),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
export function encodeHex(start: usize, len: usize): string {
|
|
44
|
+
return String.UTF8.decode(encodeHexUTF8(start, len));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function encodeHexFromBuffer(data: ArrayBuffer): string {
|
|
48
|
+
return encodeHex(changetype<usize>(data), data.byteLength);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function decodeHex(hex: string): ArrayBuffer {
|
|
52
|
+
const result = new ArrayBuffer(hex.length / 2);
|
|
53
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
54
|
+
store<u8>(
|
|
55
|
+
changetype<usize>(result) + i / 2,
|
|
56
|
+
<u8>parseInt(hex.substring(i, i + 2), 16),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { encodeSelector, Selector } from '../math/abi';
|
|
2
|
-
import { BytesReader } from '../buffer/BytesReader';
|
|
3
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
|
-
|
|
5
|
-
export type Calldata = NonNullable<BytesReader>;
|
|
6
|
-
|
|
7
|
-
class ABIRegistryBase {
|
|
8
|
-
private methodMap: Selector[] = [];
|
|
9
|
-
|
|
10
|
-
public getMethodSelectors(): Uint8Array {
|
|
11
|
-
const writer: BytesWriter = new BytesWriter(2 + this.methodMap.length * 4);
|
|
12
|
-
writer.writeMethodSelectorsMap(this.methodMap);
|
|
13
|
-
|
|
14
|
-
return writer.getBuffer();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Register methods with their selectors and handlers
|
|
18
|
-
public defineMethodSelector(name: string): void {
|
|
19
|
-
const selector: u32 = encodeSelector(name);
|
|
20
|
-
|
|
21
|
-
if (!this.methodMap.includes(selector)) {
|
|
22
|
-
this.methodMap.push(selector);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const ABIRegistry = new ABIRegistryBase();
|