@btc-vision/btc-runtime 1.8.1 → 1.9.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/README.md +57 -79
- package/package.json +8 -8
- package/runtime/buffer/BytesReader.ts +36 -45
- package/runtime/buffer/BytesWriter.ts +60 -20
- package/runtime/contracts/OP20.ts +643 -0
- package/runtime/contracts/OP_NET.ts +3 -3
- package/runtime/contracts/interfaces/IOP20.ts +15 -0
- package/runtime/contracts/interfaces/OP20InitParameters.ts +3 -1
- package/runtime/env/BlockchainEnvironment.ts +28 -7
- package/runtime/env/classes/Transaction.ts +1 -2
- package/runtime/env/global.ts +171 -23
- package/runtime/events/NetEvent.ts +1 -1
- package/runtime/events/predefined/{ApproveEvent.ts → ApprovedEvent.ts} +3 -3
- package/runtime/events/predefined/{MintEvent.ts → BurnedEvent.ts} +5 -6
- package/runtime/events/predefined/{TransferEvent.ts → MintedEvent.ts} +5 -6
- package/runtime/events/predefined/TransferredEvent.ts +18 -0
- package/runtime/events/predefined/index.ts +4 -4
- package/runtime/exports/index.ts +4 -4
- package/runtime/index.ts +13 -3
- package/runtime/math/abi.ts +10 -6
- package/runtime/math/bytes.ts +5 -17
- package/runtime/memory/AddressMemoryMap.ts +4 -5
- package/runtime/memory/KeyMerger.ts +7 -7
- package/runtime/memory/MapOfMap.ts +2 -7
- package/runtime/memory/Nested.ts +6 -8
- package/runtime/nested/PointerManager.ts +1 -1
- package/runtime/nested/codecs/AddressCodec.ts +1 -1
- package/runtime/nested/codecs/BooleanCodec.ts +1 -1
- package/runtime/nested/codecs/Ids.ts +1 -1
- package/runtime/nested/codecs/NumericCodec.ts +1 -1
- package/runtime/nested/codecs/StringCodec.ts +1 -1
- package/runtime/nested/codecs/VariableBytesCodec.ts +3 -3
- package/runtime/nested/storage/StorageMap.ts +3 -3
- package/runtime/nested/storage/StorageSet.ts +2 -2
- package/runtime/plugins/Plugin.ts +5 -7
- package/runtime/script/Bech32.ts +369 -0
- package/runtime/script/BitcoinAddresses.ts +208 -0
- package/runtime/script/BitcoinCodec.ts +395 -0
- package/runtime/script/Networks.ts +94 -0
- package/runtime/script/Opcodes.ts +155 -0
- package/runtime/script/Script.ts +463 -0
- package/runtime/script/ScriptUtils.ts +101 -0
- package/runtime/script/Segwit.ts +185 -0
- package/runtime/script/reader/ScriptReader.ts +247 -0
- package/runtime/secp256k1/ECPoint.ts +6 -12
- package/runtime/shared-libraries/TransferHelper.ts +72 -31
- package/runtime/storage/AdvancedStoredString.ts +1 -1
- package/runtime/storage/StoredAddress.ts +1 -1
- package/runtime/storage/StoredBoolean.ts +2 -4
- package/runtime/storage/StoredString.ts +6 -3
- package/runtime/storage/StoredU256.ts +1 -3
- package/runtime/storage/StoredU32.ts +1 -6
- package/runtime/storage/StoredU64.ts +1 -4
- package/runtime/storage/arrays/StoredBooleanArray.ts +7 -12
- package/runtime/storage/arrays/StoredPackedArray.ts +2 -7
- package/runtime/storage/maps/StoredMapU256.ts +5 -5
- package/runtime/types/Address.ts +49 -39
- package/runtime/types/SafeMath.ts +19 -18
- package/runtime/types/SafeMathI128.ts +14 -13
- package/runtime/utils/hex.ts +41 -19
- package/runtime/utils/index.ts +0 -2
- package/runtime/contracts/DeployableOP_20.ts +0 -415
- package/runtime/contracts/OP_20.ts +0 -9
- package/runtime/contracts/interfaces/IOP_20.ts +0 -19
- package/runtime/events/predefined/BurnEvent.ts +0 -14
- package/runtime/utils/b32.ts +0 -243
- package/runtime/utils/box.ts +0 -134
- package/runtime/utils/encodings.ts +0 -45
- /package/{LICENSE → LICENSE.md} +0 -0
package/README.md
CHANGED
|
@@ -31,13 +31,13 @@ execution while integrating deeply with Bitcoin's decentralized architecture.
|
|
|
31
31
|
|
|
32
32
|
### Features
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
34
|
+
- **AssemblyScript and WebAssembly:** Efficient and high-performance contract execution using WebAssembly.
|
|
35
|
+
- **Bitcoin Integration:** Direct interaction with Bitcoin L1, enabling the creation of decentralized applications that
|
|
36
|
+
operate on the Bitcoin network.
|
|
37
|
+
- **Comprehensive Storage Management:** Flexible and secure storage management using primary pointers and sub-pointers,
|
|
38
|
+
ensuring data integrity through cryptographic proofs.
|
|
39
|
+
- **Event Handling:** Sophisticated event system for contract state changes, allowing easy tracking and logging of
|
|
40
|
+
contract activities.
|
|
41
41
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
@@ -95,22 +95,20 @@ Here is a real-world example of how to create a basic token contract using the O
|
|
|
95
95
|
contract follows the OP20 standard.
|
|
96
96
|
|
|
97
97
|
```typescript
|
|
98
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
98
99
|
import {
|
|
99
100
|
Address,
|
|
101
|
+
AddressMap,
|
|
100
102
|
Blockchain,
|
|
101
103
|
BytesWriter,
|
|
102
104
|
Calldata,
|
|
103
|
-
|
|
104
|
-
encodeSelector,
|
|
105
|
-
Map,
|
|
105
|
+
OP20,
|
|
106
106
|
OP20InitParameters,
|
|
107
|
-
|
|
108
|
-
AddressMap,
|
|
107
|
+
SafeMath,
|
|
109
108
|
} from '@btc-vision/btc-runtime/runtime';
|
|
110
|
-
import { u128, u256 } from 'as-bignum/assembly';
|
|
111
109
|
|
|
112
110
|
@final
|
|
113
|
-
export class MyToken extends
|
|
111
|
+
export class MyToken extends OP20 {
|
|
114
112
|
public constructor() {
|
|
115
113
|
super();
|
|
116
114
|
|
|
@@ -119,71 +117,72 @@ export class MyToken extends DeployableOP_20 {
|
|
|
119
117
|
|
|
120
118
|
// "solidityLikeConstructor" This is a solidity-like constructor. This method will only run once when the contract is deployed.
|
|
121
119
|
public override onDeployment(_calldata: Calldata): void {
|
|
122
|
-
const maxSupply: u256 =
|
|
120
|
+
const maxSupply: u256 = u256.fromString('1000000000000000000000000000'); // Your max supply. (Here, 1 billion tokens)
|
|
123
121
|
const decimals: u8 = 18; // Your decimals.
|
|
124
|
-
const name: string = '
|
|
125
|
-
const symbol: string = '
|
|
122
|
+
const name: string = 'Test'; // Your token name.
|
|
123
|
+
const symbol: string = 'TEST'; // Your token symbol.
|
|
126
124
|
|
|
127
125
|
this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
|
|
128
126
|
|
|
129
127
|
// Add your logic here. Eg, minting the initial supply:
|
|
130
|
-
this._mint(Blockchain.tx.origin, maxSupply);
|
|
128
|
+
// this._mint(Blockchain.tx.origin, maxSupply);
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
131
|
+
@method(
|
|
132
|
+
{
|
|
133
|
+
name: 'address',
|
|
134
|
+
type: ABIDataTypes.ADDRESS,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'amount',
|
|
138
|
+
type: ABIDataTypes.UINT256,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
@emit('Minted')
|
|
142
|
+
public mint(calldata: Calldata): BytesWriter {
|
|
143
|
+
this.onlyDeployer(Blockchain.tx.sender);
|
|
144
|
+
this._mint(calldata.readAddress(), calldata.readU256());
|
|
145
|
+
return new BytesWriter(0);
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Mints tokens to the specified addresses.
|
|
150
|
+
*
|
|
151
|
+
* @param calldata Calldata containing an `AddressMap<Address, u256>` to mint to.
|
|
152
|
+
*/
|
|
153
|
+
@method({
|
|
154
|
+
name: 'addressAndAmount',
|
|
155
|
+
type: ABIDataTypes.ADDRESS_UINT256_TUPLE,
|
|
156
|
+
})
|
|
157
|
+
@emit('Minted')
|
|
158
|
+
public airdrop(calldata: Calldata): BytesWriter {
|
|
145
159
|
this.onlyDeployer(Blockchain.tx.sender);
|
|
146
160
|
|
|
147
|
-
const
|
|
161
|
+
const addressAndAmount: AddressMap<u256> = calldata.readAddressMapU256();
|
|
162
|
+
const addresses: Address[] = addressAndAmount.keys();
|
|
163
|
+
|
|
164
|
+
let totalAirdropped: u256 = u256.Zero;
|
|
148
165
|
|
|
149
|
-
const addresses: Address[] = drops.keys();
|
|
150
166
|
for (let i: i32 = 0; i < addresses.length; i++) {
|
|
151
167
|
const address = addresses[i];
|
|
152
|
-
const amount =
|
|
168
|
+
const amount = addressAndAmount.get(address);
|
|
153
169
|
|
|
154
|
-
this.
|
|
155
|
-
}
|
|
170
|
+
const currentBalance: u256 = this.balanceOfMap.get(address);
|
|
156
171
|
|
|
157
|
-
|
|
158
|
-
|
|
172
|
+
if (currentBalance) {
|
|
173
|
+
this.balanceOfMap.set(address, SafeMath.add(currentBalance, amount));
|
|
174
|
+
} else {
|
|
175
|
+
this.balanceOfMap.set(address, amount);
|
|
176
|
+
}
|
|
159
177
|
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private _optimizedMint(address: Address, amount: u256): void {
|
|
164
|
-
this.balanceOfMap.set(address, amount);
|
|
165
|
-
|
|
166
|
-
this._totalSupply.addNoCommit(amount);
|
|
167
|
-
|
|
168
|
-
this.createMintEvent(address, amount);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
private airdropWithAmount(calldata: Calldata): BytesWriter {
|
|
172
|
-
this.onlyDeployer(Blockchain.tx.sender);
|
|
178
|
+
totalAirdropped = SafeMath.add(totalAirdropped, amount);
|
|
173
179
|
|
|
174
|
-
|
|
175
|
-
const addresses: Address[] = calldata.readAddressArray();
|
|
176
|
-
|
|
177
|
-
for (let i: i32 = 0; i < addresses.length; i++) {
|
|
178
|
-
this._optimizedMint(addresses[i], amount);
|
|
180
|
+
this.createMintedEvent(address, amount);
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
this._totalSupply.
|
|
182
|
-
|
|
183
|
-
const writer: BytesWriter = new BytesWriter(1);
|
|
184
|
-
writer.writeBoolean(true);
|
|
183
|
+
this._totalSupply.set(SafeMath.add(this._totalSupply.value, totalAirdropped));
|
|
185
184
|
|
|
186
|
-
return
|
|
185
|
+
return new BytesWriter(0);
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
188
|
```
|
|
@@ -196,27 +195,6 @@ Storage pointers and sub-pointers are encoded and hashed to create unique and se
|
|
|
196
195
|
locations are managed using the `Blockchain` class's `setStorageAt` and `getStorageAt` methods, ensuring data integrity
|
|
197
196
|
and preventing tampering.
|
|
198
197
|
|
|
199
|
-
### Using Serializable Data Structures
|
|
200
|
-
|
|
201
|
-
For complex data types, the `Serializable` class allows you to manage and persist data structures across multiple
|
|
202
|
-
storage slots.
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
class ComplexData extends Serializable {
|
|
206
|
-
// Implementation
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Additional Documentation
|
|
211
|
-
|
|
212
|
-
For more detailed explanations on specific topics, refer to the individual documentation files:
|
|
213
|
-
|
|
214
|
-
- [Blockchain.md](docs/Blockchain.md)
|
|
215
|
-
- [Contract.md](docs/Contract.md)
|
|
216
|
-
- [Events.md](docs/Events.md)
|
|
217
|
-
- [Pointers.md](docs/Pointers.md)
|
|
218
|
-
- [Storage.md](docs/Storage.md)
|
|
219
|
-
|
|
220
198
|
## License
|
|
221
199
|
|
|
222
200
|
This project is licensed under the MIT License. View the full license [here](LICENSE.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/btc-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "Bitcoin Smart Contract Runtime",
|
|
5
5
|
"main": "btc/index.ts",
|
|
6
6
|
"scripts": {},
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"author": "BlobMaster41",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@types/node": "^24.
|
|
21
|
-
"assemblyscript": "^0.28.
|
|
20
|
+
"@types/node": "^24.2.1",
|
|
21
|
+
"assemblyscript": "^0.28.4"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"test/*.ts"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@assemblyscript/loader": "^0.28.
|
|
38
|
+
"@assemblyscript/loader": "^0.28.4",
|
|
39
39
|
"@btc-vision/as-bignum": "^0.0.5",
|
|
40
|
-
"@btc-vision/opnet-transform": "^0.1.
|
|
41
|
-
"@eslint/js": "^9.
|
|
40
|
+
"@btc-vision/opnet-transform": "^0.1.10",
|
|
41
|
+
"@eslint/js": "^9.33.0",
|
|
42
42
|
"gulplog": "^2.2.0",
|
|
43
43
|
"ts-node": "^10.9.2",
|
|
44
|
-
"typescript": "^5.
|
|
45
|
-
"typescript-eslint": "^8.
|
|
44
|
+
"typescript": "^5.9.2",
|
|
45
|
+
"typescript-eslint": "^8.39.0"
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -6,7 +6,10 @@ import { Revert } from '../types/Revert';
|
|
|
6
6
|
import {
|
|
7
7
|
ADDRESS_BYTE_LENGTH,
|
|
8
8
|
I128_BYTE_LENGTH,
|
|
9
|
+
I16_BYTE_LENGTH,
|
|
10
|
+
I32_BYTE_LENGTH,
|
|
9
11
|
I64_BYTE_LENGTH,
|
|
12
|
+
I8_BYTE_LENGTH,
|
|
10
13
|
U128_BYTE_LENGTH,
|
|
11
14
|
U16_BYTE_LENGTH,
|
|
12
15
|
U256_BYTE_LENGTH,
|
|
@@ -14,7 +17,6 @@ import {
|
|
|
14
17
|
U64_BYTE_LENGTH,
|
|
15
18
|
U8_BYTE_LENGTH,
|
|
16
19
|
} from '../utils';
|
|
17
|
-
import { sizeof } from 'builtins';
|
|
18
20
|
|
|
19
21
|
@final
|
|
20
22
|
export class BytesReader {
|
|
@@ -41,31 +43,31 @@ export class BytesReader {
|
|
|
41
43
|
const size = sizeof<T>();
|
|
42
44
|
|
|
43
45
|
switch (size) {
|
|
44
|
-
case
|
|
45
|
-
return this.
|
|
46
|
-
case
|
|
46
|
+
case I8_BYTE_LENGTH:
|
|
47
|
+
return this.readI8() as T;
|
|
48
|
+
case I16_BYTE_LENGTH:
|
|
47
49
|
return this.readI16() as T;
|
|
48
|
-
case
|
|
50
|
+
case I32_BYTE_LENGTH:
|
|
49
51
|
return this.readI32() as T;
|
|
50
|
-
case
|
|
52
|
+
case I64_BYTE_LENGTH:
|
|
51
53
|
return this.readI64() as T;
|
|
52
54
|
default:
|
|
53
|
-
throw new
|
|
55
|
+
throw new Revert(`Invalid size ${size}`);
|
|
54
56
|
}
|
|
55
57
|
} else {
|
|
56
58
|
const size = sizeof<T>();
|
|
57
59
|
|
|
58
60
|
switch (size) {
|
|
59
|
-
case
|
|
61
|
+
case U8_BYTE_LENGTH:
|
|
60
62
|
return this.readU8() as T;
|
|
61
|
-
case
|
|
63
|
+
case U16_BYTE_LENGTH:
|
|
62
64
|
return this.readU16() as T;
|
|
63
|
-
case
|
|
65
|
+
case U32_BYTE_LENGTH:
|
|
64
66
|
return this.readU32() as T;
|
|
65
|
-
case
|
|
67
|
+
case U64_BYTE_LENGTH:
|
|
66
68
|
return this.readU64() as T;
|
|
67
69
|
default:
|
|
68
|
-
throw new
|
|
70
|
+
throw new Revert(`Invalid size ${size}`);
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
} else if (id === idof<u256>()) {
|
|
@@ -81,21 +83,35 @@ export class BytesReader {
|
|
|
81
83
|
} else if (id === idof<string>()) {
|
|
82
84
|
return this.readStringWithLength() as T;
|
|
83
85
|
} else {
|
|
84
|
-
throw new
|
|
86
|
+
throw new Revert(`Unsupported type ${id}`);
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
public readI8(): i8 {
|
|
91
|
+
this.verifyEnd(this.currentOffset + I8_BYTE_LENGTH);
|
|
92
|
+
const value = this.buffer.getInt8(this.currentOffset);
|
|
93
|
+
this.currentOffset += I8_BYTE_LENGTH;
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
public readI16(): i16 {
|
|
89
|
-
this.verifyEnd(this.currentOffset +
|
|
98
|
+
this.verifyEnd(this.currentOffset + I16_BYTE_LENGTH);
|
|
90
99
|
const value = this.buffer.getInt16(this.currentOffset, true);
|
|
91
|
-
this.currentOffset +=
|
|
100
|
+
this.currentOffset += I16_BYTE_LENGTH;
|
|
92
101
|
return value;
|
|
93
102
|
}
|
|
94
103
|
|
|
95
104
|
public readI32(): i32 {
|
|
96
|
-
this.verifyEnd(this.currentOffset +
|
|
105
|
+
this.verifyEnd(this.currentOffset + I32_BYTE_LENGTH);
|
|
97
106
|
const value = this.buffer.getInt32(this.currentOffset, true);
|
|
98
|
-
this.currentOffset +=
|
|
107
|
+
this.currentOffset += I32_BYTE_LENGTH;
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public readI64(be: boolean = true): i64 {
|
|
112
|
+
this.verifyEnd(this.currentOffset + I64_BYTE_LENGTH);
|
|
113
|
+
const value = this.buffer.getInt64(this.currentOffset, !be);
|
|
114
|
+
this.currentOffset += I64_BYTE_LENGTH;
|
|
99
115
|
return value;
|
|
100
116
|
}
|
|
101
117
|
|
|
@@ -146,13 +162,6 @@ export class BytesReader {
|
|
|
146
162
|
return be ? u256.fromBytesBE(raw) : u256.fromBytesLE(raw);
|
|
147
163
|
}
|
|
148
164
|
|
|
149
|
-
public readI64(be: boolean = true): i64 {
|
|
150
|
-
this.verifyEnd(this.currentOffset + I64_BYTE_LENGTH);
|
|
151
|
-
const value = this.buffer.getInt64(this.currentOffset, !be);
|
|
152
|
-
this.currentOffset += I64_BYTE_LENGTH;
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
165
|
public readU128(be: boolean = true): u128 {
|
|
157
166
|
this.verifyEnd(this.currentOffset + U128_BYTE_LENGTH);
|
|
158
167
|
const raw: u8[] = this.readBytesArray(U128_BYTE_LENGTH);
|
|
@@ -211,10 +220,6 @@ export class BytesReader {
|
|
|
211
220
|
return String.UTF8.decode(bytes.buffer);
|
|
212
221
|
}
|
|
213
222
|
|
|
214
|
-
/**
|
|
215
|
-
* [u16 length][raw bytes].
|
|
216
|
-
* The AS writer calls `writeStringWithLength(value: string)` => writes length big-endian by default.
|
|
217
|
-
*/
|
|
218
223
|
public readStringWithLength(be: boolean = true): string {
|
|
219
224
|
const length = this.readU32(be);
|
|
220
225
|
return this.readString(length);
|
|
@@ -243,13 +248,8 @@ export class BytesReader {
|
|
|
243
248
|
|
|
244
249
|
// ------------------- Arrays ------------------- //
|
|
245
250
|
|
|
246
|
-
/**
|
|
247
|
-
* The AS writer does `writeU32(length)` for U256 arrays, so we read a u32.
|
|
248
|
-
* If you changed it to a `u16`, then do readU16() here.
|
|
249
|
-
*/
|
|
250
251
|
public readU256Array(be: boolean = true): u256[] {
|
|
251
|
-
|
|
252
|
-
const length = this.readU32();
|
|
252
|
+
const length = this.readU16();
|
|
253
253
|
const result = new Array<u256>(length);
|
|
254
254
|
for (let i: u32 = 0; i < length; i++) {
|
|
255
255
|
result[i] = this.readU256(be);
|
|
@@ -257,9 +257,6 @@ export class BytesReader {
|
|
|
257
257
|
return result;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
/**
|
|
261
|
-
* The AS writer uses a [u16 length] for U64 arrays.
|
|
262
|
-
*/
|
|
263
260
|
public readU64Array(be: boolean = true): u64[] {
|
|
264
261
|
const length = this.readU16(be);
|
|
265
262
|
const result = new Array<u64>(length);
|
|
@@ -296,10 +293,6 @@ export class BytesReader {
|
|
|
296
293
|
return result;
|
|
297
294
|
}
|
|
298
295
|
|
|
299
|
-
/**
|
|
300
|
-
* The AS writer uses a [u8 length] for transaction inputs/outputs in the example,
|
|
301
|
-
* but for an "AddressArray" we use [u16 length].
|
|
302
|
-
*/
|
|
303
296
|
public readAddressArray(be: boolean = true): Address[] {
|
|
304
297
|
const length = this.readU16(be);
|
|
305
298
|
const result = new Array<Address>(length);
|
|
@@ -309,9 +302,6 @@ export class BytesReader {
|
|
|
309
302
|
return result;
|
|
310
303
|
}
|
|
311
304
|
|
|
312
|
-
/**
|
|
313
|
-
* Map of [u16 length] entries, each entry = [Address, U256], consistent with the writer’s `writeAddressMapU256`.
|
|
314
|
-
*/
|
|
315
305
|
public readAddressMapU256(be: boolean = true): AddressMap<u256> {
|
|
316
306
|
const length = this.readU16(be);
|
|
317
307
|
const result = new AddressMap<u256>();
|
|
@@ -334,6 +324,7 @@ export class BytesReader {
|
|
|
334
324
|
}
|
|
335
325
|
|
|
336
326
|
public setOffset(offset: i32): void {
|
|
327
|
+
this.verifyEnd(offset);
|
|
337
328
|
this.currentOffset = offset;
|
|
338
329
|
}
|
|
339
330
|
|
|
@@ -342,7 +333,7 @@ export class BytesReader {
|
|
|
342
333
|
*/
|
|
343
334
|
public verifyEnd(size: i32): void {
|
|
344
335
|
if (size > this.buffer.byteLength) {
|
|
345
|
-
throw new
|
|
336
|
+
throw new Revert(
|
|
346
337
|
`Attempt to read beyond buffer length. Requested up to offset ${size}, ` +
|
|
347
338
|
`but buffer is only ${this.buffer.byteLength} bytes.`,
|
|
348
339
|
);
|
|
@@ -6,6 +6,10 @@ import { Revert } from '../types/Revert';
|
|
|
6
6
|
import {
|
|
7
7
|
ADDRESS_BYTE_LENGTH,
|
|
8
8
|
I128_BYTE_LENGTH,
|
|
9
|
+
I16_BYTE_LENGTH,
|
|
10
|
+
I32_BYTE_LENGTH,
|
|
11
|
+
I64_BYTE_LENGTH,
|
|
12
|
+
I8_BYTE_LENGTH,
|
|
9
13
|
U128_BYTE_LENGTH,
|
|
10
14
|
U16_BYTE_LENGTH,
|
|
11
15
|
U256_BYTE_LENGTH,
|
|
@@ -33,20 +37,19 @@ export class BytesWriter {
|
|
|
33
37
|
public write<T>(value: T): void {
|
|
34
38
|
if (isInteger<T>()) {
|
|
35
39
|
const size = sizeof<T>();
|
|
36
|
-
if (size === 1) {
|
|
37
|
-
this.writeU8(<u8>value);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
40
|
|
|
41
41
|
if (isSigned<T>()) {
|
|
42
42
|
switch (size) {
|
|
43
|
-
case
|
|
43
|
+
case I8_BYTE_LENGTH:
|
|
44
|
+
this.writeI8(<i8>value);
|
|
45
|
+
break;
|
|
46
|
+
case I16_BYTE_LENGTH:
|
|
44
47
|
this.writeI16(<i16>value);
|
|
45
48
|
break;
|
|
46
|
-
case
|
|
49
|
+
case I32_BYTE_LENGTH:
|
|
47
50
|
this.writeI32(<i32>value);
|
|
48
51
|
break;
|
|
49
|
-
case
|
|
52
|
+
case I64_BYTE_LENGTH:
|
|
50
53
|
this.writeI64(<i64>value);
|
|
51
54
|
break;
|
|
52
55
|
default:
|
|
@@ -54,13 +57,16 @@ export class BytesWriter {
|
|
|
54
57
|
}
|
|
55
58
|
} else {
|
|
56
59
|
switch (size) {
|
|
57
|
-
case
|
|
60
|
+
case U8_BYTE_LENGTH:
|
|
61
|
+
this.writeU8(<u8>value);
|
|
62
|
+
break;
|
|
63
|
+
case U16_BYTE_LENGTH:
|
|
58
64
|
this.writeU16(<u16>value);
|
|
59
65
|
break;
|
|
60
|
-
case
|
|
66
|
+
case U32_BYTE_LENGTH:
|
|
61
67
|
this.writeU32(<u32>value);
|
|
62
68
|
break;
|
|
63
|
-
case
|
|
69
|
+
case U64_BYTE_LENGTH:
|
|
64
70
|
this.writeU64(<u64>value);
|
|
65
71
|
break;
|
|
66
72
|
default:
|
|
@@ -121,21 +127,27 @@ export class BytesWriter {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
public writeI64(value: i64, be: boolean = true): void {
|
|
124
|
-
this.allocSafe(
|
|
130
|
+
this.allocSafe(I64_BYTE_LENGTH);
|
|
125
131
|
this.buffer.setInt64(this.currentOffset, value, !be);
|
|
126
|
-
this.currentOffset +=
|
|
132
|
+
this.currentOffset += I64_BYTE_LENGTH;
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
public writeI32(value: i32, be: boolean = true): void {
|
|
130
|
-
this.allocSafe(
|
|
136
|
+
this.allocSafe(I32_BYTE_LENGTH);
|
|
131
137
|
this.buffer.setInt32(this.currentOffset, value, !be);
|
|
132
|
-
this.currentOffset +=
|
|
138
|
+
this.currentOffset += I32_BYTE_LENGTH;
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
public writeI16(value: i16, be: boolean = true): void {
|
|
136
|
-
this.allocSafe(
|
|
142
|
+
this.allocSafe(I16_BYTE_LENGTH);
|
|
137
143
|
this.buffer.setInt16(this.currentOffset, value, !be);
|
|
138
|
-
this.currentOffset +=
|
|
144
|
+
this.currentOffset += I16_BYTE_LENGTH;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public writeI8(value: u8): void {
|
|
148
|
+
this.allocSafe(I8_BYTE_LENGTH);
|
|
149
|
+
this.buffer.setInt8(this.currentOffset, value);
|
|
150
|
+
this.currentOffset += I8_BYTE_LENGTH;
|
|
139
151
|
}
|
|
140
152
|
|
|
141
153
|
/**
|
|
@@ -289,6 +301,38 @@ export class BytesWriter {
|
|
|
289
301
|
this.writeBytes(bytes);
|
|
290
302
|
}
|
|
291
303
|
|
|
304
|
+
// zero-copy bulk writer
|
|
305
|
+
public writeRaw(data: Uint8Array): void {
|
|
306
|
+
const n = data.length;
|
|
307
|
+
this.allocSafe(n);
|
|
308
|
+
|
|
309
|
+
const off = this.currentOffset;
|
|
310
|
+
const dst = this.typedArray;
|
|
311
|
+
|
|
312
|
+
memory.copy(changetype<usize>(dst.buffer) + <usize>off, changetype<usize>(data.buffer), n);
|
|
313
|
+
|
|
314
|
+
this.currentOffset = off + n;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
public writeRawSlice(data: Uint8Array, offset: i32, length: i32): void {
|
|
318
|
+
if (offset < 0 || length < 0 || offset + length > data.length) {
|
|
319
|
+
throw new Revert('writeRawSlice bounds');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
this.allocSafe(length);
|
|
323
|
+
|
|
324
|
+
const off = this.currentOffset;
|
|
325
|
+
const dst = this.typedArray;
|
|
326
|
+
|
|
327
|
+
memory.copy(
|
|
328
|
+
changetype<usize>(dst.buffer) + <usize>off,
|
|
329
|
+
changetype<usize>(data.buffer) + <usize>offset,
|
|
330
|
+
length,
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
this.currentOffset = off + length;
|
|
334
|
+
}
|
|
335
|
+
|
|
292
336
|
/**
|
|
293
337
|
* Equivalent to TS’s writeAddressValueTuple, except specialized for u256 values.
|
|
294
338
|
*/
|
|
@@ -318,10 +362,6 @@ export class BytesWriter {
|
|
|
318
362
|
return this.currentOffset;
|
|
319
363
|
}
|
|
320
364
|
|
|
321
|
-
public setOffset(offset: u32): void {
|
|
322
|
-
this.currentOffset = offset;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
365
|
/**
|
|
326
366
|
* Ensures we have space for `size` more bytes without going past the current buffer.
|
|
327
367
|
* If not, calls `resize()` which by default throws a Revert.
|