@btc-vision/btc-runtime 1.0.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.
- package/LICENSE.md +62 -0
- package/README.md +34 -0
- package/package.json +46 -0
- package/runtime/buffer/BytesReader.ts +193 -0
- package/runtime/buffer/BytesWriter.ts +322 -0
- package/runtime/contracts/OP_20.ts +377 -0
- package/runtime/contracts/OP_NET.ts +77 -0
- package/runtime/contracts/interfaces/IOP_20.ts +25 -0
- package/runtime/env/BTCEnvironment.ts +372 -0
- package/runtime/env/global.ts +18 -0
- package/runtime/env/index.ts +3 -0
- package/runtime/events/NetEvent.ts +27 -0
- package/runtime/events/predefined/ApproveEvent.ts +16 -0
- package/runtime/events/predefined/BurnEvent.ts +13 -0
- package/runtime/events/predefined/ClaimEvent.ts +13 -0
- package/runtime/events/predefined/MintEvent.ts +15 -0
- package/runtime/events/predefined/StakeEvent.ts +13 -0
- package/runtime/events/predefined/TransferEvent.ts +16 -0
- package/runtime/events/predefined/UnstakeEvent.ts +13 -0
- package/runtime/events/predefined/index.ts +7 -0
- package/runtime/exports/index.ts +57 -0
- package/runtime/generic/Map.ts +55 -0
- package/runtime/index.ts +45 -0
- package/runtime/interfaces/IBTC.ts +6 -0
- package/runtime/lang/Definitions.ts +1 -0
- package/runtime/math/abi.ts +37 -0
- package/runtime/math/bytes.ts +34 -0
- package/runtime/math/cyrb53.ts +46 -0
- package/runtime/math/rnd.ts +51 -0
- package/runtime/math/sha256.ts +270 -0
- package/runtime/memory/AddressMemoryMap.ts +64 -0
- package/runtime/memory/KeyMerger.ts +72 -0
- package/runtime/memory/MemorySlot.ts +1 -0
- package/runtime/memory/MemorySlotPointer.ts +3 -0
- package/runtime/memory/MultiAddressMemoryMap.ts +76 -0
- package/runtime/storage/StoredU256.ts +320 -0
- package/runtime/types/Address.ts +5 -0
- package/runtime/types/Revert.ts +5 -0
- package/runtime/types/SafeMath.ts +137 -0
- package/runtime/types/index.ts +8 -0
- package/runtime/universal/ABIRegistry.ts +72 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Custom Software License Agreement
|
|
2
|
+
|
|
3
|
+
## 1. Definitions
|
|
4
|
+
|
|
5
|
+
- **"Licensor"** refers to the owner(s) and creator(s) of the software. The owner of the github organization "
|
|
6
|
+
btc-vision", "BlobMaster41".
|
|
7
|
+
- **"User"** refers to any person or entity that accesses or uses the software.
|
|
8
|
+
- **"Software"** refers to the source code, binaries, and documentation, whether in electronic or printed format, made
|
|
9
|
+
available by Licensor.
|
|
10
|
+
|
|
11
|
+
## 2. Grant of License
|
|
12
|
+
|
|
13
|
+
This License permits User to view the Software via the repository hosting the Software ("Hosting Service"). Except as
|
|
14
|
+
provided in this Section, no other use of the Software is permitted. The User may not modify, copy, reproduce,
|
|
15
|
+
republish, upload, post, transmit, or distribute the Software in any way.
|
|
16
|
+
|
|
17
|
+
## 3. Restrictions
|
|
18
|
+
|
|
19
|
+
- **Modification and Distribution**: User is prohibited from modifying, merging, distributing, sublicensing, and/or
|
|
20
|
+
selling copies of the Software.
|
|
21
|
+
- **Commercial Use**: User is prohibited from using the Software for any commercial purposes.
|
|
22
|
+
- **Reverse Engineering**: User is prohibited from reverse engineering, decompiling, or disassembling the Software.
|
|
23
|
+
|
|
24
|
+
## 4. Termination
|
|
25
|
+
|
|
26
|
+
This License is effective until terminated by the Licensor. It will terminate immediately without notice from the
|
|
27
|
+
Licensor if User fails to comply with any provision of this License. Upon termination, User must destroy all copies of
|
|
28
|
+
the Software.
|
|
29
|
+
|
|
30
|
+
## 5. Copyright Notice
|
|
31
|
+
|
|
32
|
+
The Software is © 2024 by the Licensor. All rights reserved.
|
|
33
|
+
|
|
34
|
+
## 6. Governing Law
|
|
35
|
+
|
|
36
|
+
This License shall be governed by and construed in accordance with the laws of [Toronto, Canada]. Any legal action or
|
|
37
|
+
proceeding arising under this License will be brought exclusively in the courts located in [Toronto], and the parties
|
|
38
|
+
hereby consent to personal jurisdiction and venue therein.
|
|
39
|
+
|
|
40
|
+
## 7. Limitation of Liability
|
|
41
|
+
|
|
42
|
+
In no event will the Licensor be liable for any damages, including, without limitation, indirect, incidental, special,
|
|
43
|
+
consequential, or punitive damages arising out of the use of or inability to use the Software.
|
|
44
|
+
|
|
45
|
+
## 8. Indemnification
|
|
46
|
+
|
|
47
|
+
User agrees to indemnify, defend, and hold harmless the Licensor and its affiliates, officers, agents, employees, and
|
|
48
|
+
partners from any claim or demand, including reasonable attorneys' fees, made by any third party due to or arising out
|
|
49
|
+
of User's use of the Software, User's violation of this License, or User's violation of any rights of another.
|
|
50
|
+
|
|
51
|
+
## 9. Breach of License
|
|
52
|
+
|
|
53
|
+
Any breach of this License will result in immediate termination of User's rights under this License. Additionally, the
|
|
54
|
+
Licensor reserves the right to pursue any legal action against the User in the event of a breach of this License.
|
|
55
|
+
|
|
56
|
+
## 10. Acknowledgment
|
|
57
|
+
|
|
58
|
+
User acknowledges that they have read this License, understand it, and agree to be bound by its terms and conditions.
|
|
59
|
+
User also agrees that this License is the complete and exclusive statement of the agreement between the Licensor and the
|
|
60
|
+
User and supersedes all proposals or prior agreements, oral or written, and any other communications between the
|
|
61
|
+
Licensor and the User relating to the subject matter of this License.
|
|
62
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# OPNet Smart Contract Runtime
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
[](https://github.com/prettier/prettier)
|
|
11
|
+
|
|
12
|
+
## Introduction
|
|
13
|
+
|
|
14
|
+
The OPNet Smart Contract Runtime is a WebAssembly runtime that is designed to help developers write smart contracts for the OPNet blockchain.
|
|
15
|
+
The runtime is written in AssemblyScript, a subset of TypeScript that compiles to WebAssembly.
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
1. Clone the repository:
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/btc-vision/btc-runtime.git
|
|
22
|
+
```
|
|
23
|
+
2. Navigate to the repository directory:
|
|
24
|
+
```bash
|
|
25
|
+
cd btc-runtime
|
|
26
|
+
```
|
|
27
|
+
3. Install the necessary dependencies:
|
|
28
|
+
```bash
|
|
29
|
+
npm i
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
View the license by clicking [here](https://github.com/btc-vision/wbtc/blob/main/LICENSE.md).
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@btc-vision/btc-runtime",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Bitcoin Smart Contract Runtime",
|
|
5
|
+
"main": "btc/index.ts",
|
|
6
|
+
"types": "btc/index.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "jest",
|
|
9
|
+
"build": "asc runtime/index.ts --target release --measure -Ospeed --noAssert --optimizeLevel 3 --shrinkLevel 2 --converge --disable mutable-globals,sign-extension,nontrapping-f2i,bulk-memory --runtime stub --memoryBase 0 --lowMemoryLimit --uncheckedBehavior never --initialMemory 16 --maximumMemory 16 --exportRuntime"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"bitcoin",
|
|
13
|
+
"smart",
|
|
14
|
+
"contract",
|
|
15
|
+
"runtime",
|
|
16
|
+
"opnet",
|
|
17
|
+
"OP_NET"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://opnet.org",
|
|
20
|
+
"author": "BlobMaster41",
|
|
21
|
+
"license": "LICENSE.MD",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^20.11.30",
|
|
24
|
+
"assemblyscript": "^0.27.25",
|
|
25
|
+
"prettier": "^3.2.5"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/BlobMaster41/btc-runtime.git"
|
|
30
|
+
},
|
|
31
|
+
"type": "module",
|
|
32
|
+
"files": [
|
|
33
|
+
"package.json",
|
|
34
|
+
"runtime",
|
|
35
|
+
"runtime/*.ts",
|
|
36
|
+
"runtime/**/*.ts",
|
|
37
|
+
"!**/*.js.map",
|
|
38
|
+
"!**/*.tsbuildinfo"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@assemblyscript/loader": "^0.27.25",
|
|
42
|
+
"as-bignum": "^0.3.0",
|
|
43
|
+
"gulplog": "^2.2.0",
|
|
44
|
+
"ts-node": "^10.9.2"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
2
|
+
import { Selector } from '../math/abi';
|
|
3
|
+
import { u256 } from 'as-bignum/assembly';
|
|
4
|
+
import { Revert } from '../types/Revert';
|
|
5
|
+
import { Map } from '../generic/Map';
|
|
6
|
+
|
|
7
|
+
@final
|
|
8
|
+
export class BytesReader {
|
|
9
|
+
private readonly buffer: DataView;
|
|
10
|
+
|
|
11
|
+
private currentOffset: i32 = 0;
|
|
12
|
+
|
|
13
|
+
constructor(bytes: Uint8Array) {
|
|
14
|
+
this.buffer = new DataView(bytes.buffer);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public readU8(): u8 {
|
|
18
|
+
this.verifyEnd(this.currentOffset + 1);
|
|
19
|
+
|
|
20
|
+
return this.buffer.getUint8(this.currentOffset++);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public readU16(): u16 {
|
|
24
|
+
this.verifyEnd(this.currentOffset + 2);
|
|
25
|
+
|
|
26
|
+
const value = this.buffer.getUint16(this.currentOffset, true);
|
|
27
|
+
this.currentOffset += 2;
|
|
28
|
+
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public readU32(le: boolean = true): u32 {
|
|
33
|
+
this.verifyEnd(this.currentOffset + 4);
|
|
34
|
+
|
|
35
|
+
const value = this.buffer.getUint32(this.currentOffset, le);
|
|
36
|
+
this.currentOffset += 4;
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public readU64(): u64 {
|
|
41
|
+
this.verifyEnd(this.currentOffset + 8);
|
|
42
|
+
|
|
43
|
+
const value = this.buffer.getUint64(this.currentOffset, true);
|
|
44
|
+
this.currentOffset += 8;
|
|
45
|
+
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public readU256(): u256 {
|
|
50
|
+
const next32Bytes: u8[] = [];
|
|
51
|
+
for (let i = 0; i < 32; i++) {
|
|
52
|
+
next32Bytes[i] = this.readU8();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return u256.fromBytesBE(next32Bytes);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public readBytes(length: u32, zeroStop: boolean = false): Uint8Array {
|
|
59
|
+
this.verifyEnd(this.currentOffset + length);
|
|
60
|
+
|
|
61
|
+
let bytes: Uint8Array = new Uint8Array(length);
|
|
62
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
63
|
+
const byte: u8 = this.readU8();
|
|
64
|
+
if (zeroStop && byte === 0) {
|
|
65
|
+
bytes = bytes.slice(0, i);
|
|
66
|
+
|
|
67
|
+
this.currentOffset += length - (i + 1);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
bytes[i] = byte;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return bytes;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public readMultiBytesAddressMap(): Map<Address, Uint8Array[]> {
|
|
78
|
+
const map: Map<Address, Uint8Array[]> = new Map<Address, Uint8Array[]>();
|
|
79
|
+
const size: u8 = this.readU8();
|
|
80
|
+
|
|
81
|
+
if (size > 8) throw new Revert('Too many contract called.');
|
|
82
|
+
|
|
83
|
+
for (let i: u8 = 0; i < size; i++) {
|
|
84
|
+
const address: Address = this.readAddress();
|
|
85
|
+
const responseSize: u8 = this.readU8();
|
|
86
|
+
|
|
87
|
+
if (responseSize > 10) throw new Revert('Too many calls.');
|
|
88
|
+
|
|
89
|
+
const calls: Uint8Array[] = [];
|
|
90
|
+
for (let j: u8 = 0; j < responseSize; j++) {
|
|
91
|
+
const response: Uint8Array = this.readBytesWithLength();
|
|
92
|
+
calls.push(response);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
map.set(address, calls);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return map;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public readBytesWithLength(): Uint8Array {
|
|
102
|
+
const length = this.readU32();
|
|
103
|
+
|
|
104
|
+
return this.readBytes(length);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public readString(length: u16): string {
|
|
108
|
+
const bytes = this.readBytes(length, true);
|
|
109
|
+
|
|
110
|
+
return String.UTF8.decode(bytes.buffer);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public readTuple(): u256[] {
|
|
114
|
+
const length = this.readU32();
|
|
115
|
+
const result: u256[] = new Array<u256>(length);
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < length; i++) {
|
|
118
|
+
result[i] = this.readU256();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public readAddressValueTuple(): Map<Address, u256> {
|
|
125
|
+
const length: u16 = this.readU16();
|
|
126
|
+
const result = new Map<Address, u256>();
|
|
127
|
+
|
|
128
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
129
|
+
const address = this.readAddress();
|
|
130
|
+
const value = this.readU256();
|
|
131
|
+
|
|
132
|
+
if (result.has(address)) throw new Revert('Duplicate address found in map');
|
|
133
|
+
|
|
134
|
+
result.set(address, value);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public readSelector(): Selector {
|
|
141
|
+
return this.readU32(false);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public readStringWithLength(): string {
|
|
145
|
+
const length = this.readU16();
|
|
146
|
+
|
|
147
|
+
return this.readString(length);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public readBoolean(): boolean {
|
|
151
|
+
return this.readU8() !== 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public readFloat(): f32 {
|
|
155
|
+
const value = this.buffer.getFloat32(this.currentOffset, true);
|
|
156
|
+
this.currentOffset += 4;
|
|
157
|
+
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public readAddress(): Address {
|
|
162
|
+
return this.readString(ADDRESS_BYTE_LENGTH);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public getOffset(): i32 {
|
|
166
|
+
return this.currentOffset;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public setOffset(offset: i32): void {
|
|
170
|
+
this.currentOffset = offset;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public verifyEnd(size: i32): void {
|
|
174
|
+
if (this.currentOffset > this.buffer.byteLength) {
|
|
175
|
+
throw new Error(`Expected to read ${size} bytes but read ${this.currentOffset} bytes`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private verifyChecksum(): void {
|
|
180
|
+
const writtenChecksum = this.readU32();
|
|
181
|
+
|
|
182
|
+
let checksum: u32 = 0;
|
|
183
|
+
for (let i = 0; i < this.buffer.byteLength; i++) {
|
|
184
|
+
checksum += this.buffer.getUint8(i);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
checksum = checksum % 2 ** 32;
|
|
188
|
+
|
|
189
|
+
if (checksum !== writtenChecksum) {
|
|
190
|
+
throw new Error('Invalid checksum for buffer');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
3
|
+
import { Selector } from '../math/abi';
|
|
4
|
+
import { BytesReader } from './BytesReader';
|
|
5
|
+
import { SelectorsMap } from '../universal/ABIRegistry';
|
|
6
|
+
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
7
|
+
import { MemorySlotData } from '../memory/MemorySlot';
|
|
8
|
+
import { cyrb53a } from '../math/cyrb53';
|
|
9
|
+
import { Revert } from '../types/Revert';
|
|
10
|
+
import { Map } from '../generic/Map';
|
|
11
|
+
import { BlockchainStorage, PointerStorage } from '../types';
|
|
12
|
+
|
|
13
|
+
export enum BufferDataType {
|
|
14
|
+
U8 = 0,
|
|
15
|
+
U16 = 1,
|
|
16
|
+
U32 = 2,
|
|
17
|
+
U64 = 3,
|
|
18
|
+
U256 = 4,
|
|
19
|
+
ADDRESS = 5,
|
|
20
|
+
STRING = 6,
|
|
21
|
+
BOOLEAN = 7,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@final
|
|
25
|
+
export class BytesWriter {
|
|
26
|
+
private currentOffset: u32 = 0;
|
|
27
|
+
private buffer: DataView;
|
|
28
|
+
|
|
29
|
+
private selectorDatatype: u8[] = [];
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
length: i32 = 1,
|
|
33
|
+
private readonly trackDataTypes: boolean = false,
|
|
34
|
+
) {
|
|
35
|
+
this.buffer = new DataView(new ArrayBuffer(length));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public bufferLength(): u32 {
|
|
39
|
+
return this.buffer.byteLength;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public writeU8(value: u8): void {
|
|
43
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.U8));
|
|
44
|
+
|
|
45
|
+
this.allocSafe(1);
|
|
46
|
+
this.buffer.setUint8(this.currentOffset++, value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public writeU16(value: u16): void {
|
|
50
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.U16));
|
|
51
|
+
|
|
52
|
+
this.allocSafe(2);
|
|
53
|
+
this.buffer.setUint16(this.currentOffset, value, true);
|
|
54
|
+
this.currentOffset += 2;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public writeU32(value: u32, le: boolean = true): void {
|
|
58
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.U32));
|
|
59
|
+
|
|
60
|
+
this.allocSafe(4);
|
|
61
|
+
this.buffer.setUint32(this.currentOffset, value, le);
|
|
62
|
+
this.currentOffset += 4;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public writeU64(value: u64): void {
|
|
66
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.U64));
|
|
67
|
+
|
|
68
|
+
this.allocSafe(8);
|
|
69
|
+
this.buffer.setUint64(this.currentOffset, value || 0, true);
|
|
70
|
+
this.currentOffset += 8;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public writeStorage(storage: BlockchainStorage): void {
|
|
74
|
+
this.writeU32(storage.size);
|
|
75
|
+
|
|
76
|
+
const keys: Address[] = storage.keys();
|
|
77
|
+
const values: PointerStorage[] = storage.values();
|
|
78
|
+
|
|
79
|
+
for (let i: i32 = 0; i < keys.length; i++) {
|
|
80
|
+
const address: Address = keys[i];
|
|
81
|
+
const storage: PointerStorage = values[i];
|
|
82
|
+
|
|
83
|
+
this.writeAddress(address);
|
|
84
|
+
|
|
85
|
+
const subKeys: MemorySlotPointer[] = storage.keys();
|
|
86
|
+
const subValues: MemorySlotData<u256>[] = storage.values();
|
|
87
|
+
|
|
88
|
+
this.writeU32(subKeys.length);
|
|
89
|
+
|
|
90
|
+
for (let j: i32 = 0; j < subKeys.length; j++) {
|
|
91
|
+
const pointer: MemorySlotPointer = subKeys[j];
|
|
92
|
+
const value: MemorySlotData<u256> = subValues[j];
|
|
93
|
+
|
|
94
|
+
this.writeU256(pointer);
|
|
95
|
+
this.writeU256(value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public writeSelector(value: Selector): void {
|
|
101
|
+
this.writeU32(value, false);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public writeBoolean(value: boolean): void {
|
|
105
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.BOOLEAN));
|
|
106
|
+
|
|
107
|
+
this.writeU8(value ? 1 : 0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public writeU256(value: u256): void {
|
|
111
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.U256));
|
|
112
|
+
this.allocSafe(32);
|
|
113
|
+
|
|
114
|
+
const bytes = value.toUint8Array(true);
|
|
115
|
+
for (let i: i32 = 0; i < 32; i++) {
|
|
116
|
+
this.writeU8(bytes[i] || 0);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public writeTuple(value: u256[]): void {
|
|
121
|
+
this.allocSafe(4 + value.length * 32);
|
|
122
|
+
this.writeU32(u32(value.length));
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < value.length; i++) {
|
|
125
|
+
this.writeU256(value[i]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public writeBytes(value: Uint8Array): void {
|
|
130
|
+
this.allocSafe(value.length);
|
|
131
|
+
|
|
132
|
+
for (let i = 0; i < value.length; i++) {
|
|
133
|
+
this.writeU8(value[i]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public writeBytesWithLength(value: Uint8Array): void {
|
|
138
|
+
const length: u32 = u32(value.byteLength);
|
|
139
|
+
this.allocSafe(length + 4);
|
|
140
|
+
this.writeU32(length);
|
|
141
|
+
|
|
142
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
143
|
+
this.writeU8(value[i]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public writeString(value: string): void {
|
|
148
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.STRING));
|
|
149
|
+
|
|
150
|
+
for (let i: i32 = 0; i < value.length; i++) {
|
|
151
|
+
this.writeU8(u8(value.charCodeAt(i)));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public writeAddress(value: Address): void {
|
|
156
|
+
if (this.trackDataTypes) this.selectorDatatype.push(u8(BufferDataType.ADDRESS));
|
|
157
|
+
|
|
158
|
+
const bytes = this.fromAddress(value);
|
|
159
|
+
this.writeBytes(bytes);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public writeStringWithLength(value: string): void {
|
|
163
|
+
this.writeU16(u16(value.length));
|
|
164
|
+
|
|
165
|
+
this.writeString(value);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public writeViewSelectorMap(map: SelectorsMap): void {
|
|
169
|
+
this.writeU16(u16(map.size));
|
|
170
|
+
|
|
171
|
+
const keys = map.keys();
|
|
172
|
+
for (let i = 0; i < keys.length; i++) {
|
|
173
|
+
const key: u32 = keys[i] as u32;
|
|
174
|
+
const value = map.get(key);
|
|
175
|
+
|
|
176
|
+
this.writeBytes(value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public writeAddressValueTupleMap(map: Map<Address, u256>): void {
|
|
181
|
+
if (map.size > 65535) throw new Revert('Map size is too large');
|
|
182
|
+
this.writeU16(u16(map.size));
|
|
183
|
+
|
|
184
|
+
const keys = map.keys();
|
|
185
|
+
for (let i = 0; i < keys.length; i++) {
|
|
186
|
+
const key: Address = keys[i];
|
|
187
|
+
const value: u256 = map.get(key) || u256.Zero;
|
|
188
|
+
|
|
189
|
+
this.writeAddress(key);
|
|
190
|
+
this.writeU256(value);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public writeLimitedAddressBytesMap(map: Map<Address, Uint8Array[]>): void {
|
|
195
|
+
if (map.size > 8) throw new Revert('Too many contract called.'); // no more than 8 different contracts.
|
|
196
|
+
|
|
197
|
+
this.writeU8(u8(map.size));
|
|
198
|
+
|
|
199
|
+
const keys: Address[] = map.keys();
|
|
200
|
+
for (let i: i32 = 0; i < keys.length; i++) {
|
|
201
|
+
const address: Address = keys[i];
|
|
202
|
+
const calls: Uint8Array[] = map.get(address) || [];
|
|
203
|
+
|
|
204
|
+
if (calls.length > 10) throw new Revert('Too many calls.'); // no more than 16 different calls.
|
|
205
|
+
|
|
206
|
+
this.writeAddress(address);
|
|
207
|
+
this.writeU8(u8(calls.length));
|
|
208
|
+
|
|
209
|
+
for (let j: i32 = 0; j < calls.length; j++) {
|
|
210
|
+
this.writeBytesWithLength(calls[j]);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public writeMethodSelectorsMap(map: Selector[]): void {
|
|
216
|
+
this.writeU16(u16(map.length));
|
|
217
|
+
|
|
218
|
+
for (let i = 0; i < map.length; i++) {
|
|
219
|
+
this.writeSelector(map[i]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public getBuffer(clear: boolean = true): Uint8Array {
|
|
224
|
+
const buf = new Uint8Array(this.buffer.byteLength);
|
|
225
|
+
for (let i: u32 = 0; i < u32(this.buffer.byteLength); i++) {
|
|
226
|
+
buf[i] = this.buffer.getUint8(i);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (clear) this.clear();
|
|
230
|
+
|
|
231
|
+
return buf;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
public toBytesReader(): BytesReader {
|
|
235
|
+
return new BytesReader(this.getBuffer());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public getOffset(): u32 {
|
|
239
|
+
return this.currentOffset;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public setOffset(offset: u32): void {
|
|
243
|
+
this.currentOffset = offset;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public clear(): void {
|
|
247
|
+
this.currentOffset = 0;
|
|
248
|
+
this.buffer = this.getDefaultBuffer();
|
|
249
|
+
this.selectorDatatype = [];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public allocSafe(size: u32): void {
|
|
253
|
+
if (this.currentOffset + size > u32(this.buffer.byteLength)) {
|
|
254
|
+
const sizeDiff: u32 = size - (u32(this.buffer.byteLength) - this.currentOffset);
|
|
255
|
+
|
|
256
|
+
this.resize(sizeDiff);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public writeABISelector(name: string, selector: Selector): void {
|
|
261
|
+
this.writeStringWithLength(name);
|
|
262
|
+
this.writeSelector(selector);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public getSelectorDataType(): u64 {
|
|
266
|
+
let hash: u64 = 0;
|
|
267
|
+
if (this.selectorDatatype.length === 0) return hash;
|
|
268
|
+
|
|
269
|
+
return cyrb53a(this.selectorDatatype);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private getChecksum(): u32 {
|
|
273
|
+
let checksum: u32 = 0;
|
|
274
|
+
for (let i = 0; i < this.buffer.byteLength; i++) {
|
|
275
|
+
checksum += this.buffer.getUint8(i);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return checksum % 2 ** 32;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private writeMethodSelectorMap(value: Set<Selector>): void {
|
|
282
|
+
this.writeU16(u16(value.size));
|
|
283
|
+
|
|
284
|
+
const keys = value.values();
|
|
285
|
+
for (let i = 0; i < keys.length; i++) {
|
|
286
|
+
const key = keys[i];
|
|
287
|
+
|
|
288
|
+
this.writeSelector(key);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private fromAddress(value: Address): Uint8Array {
|
|
293
|
+
if (value.length > i32(ADDRESS_BYTE_LENGTH)) {
|
|
294
|
+
throw new Revert('Address is too long');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const bytes: Uint8Array = new Uint8Array(ADDRESS_BYTE_LENGTH);
|
|
298
|
+
for (let i: i32 = 0; i < value.length; i++) {
|
|
299
|
+
bytes[i] = value.charCodeAt(i);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (let i: u8 = u8(value.length); i < ADDRESS_BYTE_LENGTH; i++) {
|
|
303
|
+
bytes[i] = 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return bytes;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private resize(size: u32): void {
|
|
310
|
+
const buf: Uint8Array = new Uint8Array(u32(this.buffer.byteLength) + size);
|
|
311
|
+
|
|
312
|
+
for (let i: i32 = 0; i < this.buffer.byteLength; i++) {
|
|
313
|
+
buf[i] = this.buffer.getUint8(i);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this.buffer = new DataView(buf.buffer);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private getDefaultBuffer(length: i32 = 1): DataView {
|
|
320
|
+
return new DataView(new ArrayBuffer(length));
|
|
321
|
+
}
|
|
322
|
+
}
|