@btc-vision/btc-runtime 1.0.31 → 1.1.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/package.json +1 -1
- package/runtime/contracts/DeployableOP_20.ts +409 -0
- package/runtime/contracts/OP_20.ts +5 -338
- package/runtime/contracts/OP_NET.ts +13 -13
- package/runtime/env/BTCEnvironment.ts +319 -319
- package/runtime/index.ts +56 -54
- package/runtime/storage/StoredBoolean.ts +48 -0
- package/runtime/storage/StoredU256.ts +2 -0
|
@@ -1,319 +1,319 @@
|
|
|
1
|
-
import { Address, PotentialAddress } from '../types/Address';
|
|
2
|
-
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
|
-
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
|
-
import { u256 } from 'as-bignum/assembly';
|
|
5
|
-
import { ABIRegistry } from '../universal/ABIRegistry';
|
|
6
|
-
import { BytesReader } from '../buffer/BytesReader';
|
|
7
|
-
import { encodePointerHash } from '../math/abi';
|
|
8
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
9
|
-
import { MAX_EVENTS, NetEvent } from '../events/NetEvent';
|
|
10
|
-
import { Potential } from '../lang/Definitions';
|
|
11
|
-
import { OP_NET } from '../contracts/OP_NET';
|
|
12
|
-
import { PointerStorage } from '../types';
|
|
13
|
-
import {
|
|
14
|
-
callContract,
|
|
15
|
-
deploy,
|
|
16
|
-
deployFromAddress,
|
|
17
|
-
encodeAddress,
|
|
18
|
-
loadPointer,
|
|
19
|
-
log,
|
|
20
|
-
storePointer,
|
|
21
|
-
} from './global';
|
|
22
|
-
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
23
|
-
import { MapU256 } from '../generic/MapU256';
|
|
24
|
-
|
|
25
|
-
export * from '../env/global';
|
|
26
|
-
|
|
27
|
-
@final
|
|
28
|
-
export class BlockchainEnvironment {
|
|
29
|
-
private static readonly MAX_U16: u16 = 65535;
|
|
30
|
-
private static readonly runtimeException: string = 'RuntimeException';
|
|
31
|
-
|
|
32
|
-
private storage: PointerStorage = new MapU256();
|
|
33
|
-
private events: NetEvent[] = [];
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private currentBlock: u256 = u256.Zero;
|
|
38
|
-
|
|
39
|
-
constructor() {}
|
|
40
|
-
|
|
41
|
-
private _timestamp: u64 = 0;
|
|
42
|
-
|
|
43
|
-
public get timestamp(): u64 {
|
|
44
|
-
return this._timestamp;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private _contract: Potential<() => OP_NET> = null;
|
|
48
|
-
|
|
49
|
-
public get contract(): OP_NET {
|
|
50
|
-
if (!this._contract) {
|
|
51
|
-
throw this.error('Contract is required');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return this._contract();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public set contract(contract: () => OP_NET) {
|
|
58
|
-
this._contract = contract;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private _nextPointer: u16 = 0;
|
|
62
|
-
|
|
63
|
-
public get nextPointer(): u16 {
|
|
64
|
-
if(this._nextPointer === BlockchainEnvironment.MAX_U16) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return this._nextPointer;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public _owner: Potential<Address> = null;
|
|
74
|
-
|
|
75
|
-
public get owner(): Address {
|
|
76
|
-
if (!this._owner) {
|
|
77
|
-
throw this.error('Owner is required');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return this._owner as Address;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public _contractAddress: Potential<Address> = null;
|
|
84
|
-
|
|
85
|
-
public get contractAddress(): Address {
|
|
86
|
-
if (!this._contractAddress) {
|
|
87
|
-
throw this.error('Contract address is required');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return this._contractAddress as Address;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
public get blockNumber(): u256 {
|
|
94
|
-
return this.currentBlock;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public get blockNumberU64(): u64 {
|
|
98
|
-
return this.currentBlock.toU64();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public
|
|
102
|
-
if (!this.
|
|
103
|
-
throw this.error('Callee is required');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return this.
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public
|
|
110
|
-
if (!this.
|
|
111
|
-
throw this.error('Caller is required');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return this.
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public setEnvironment(data: Uint8Array): void {
|
|
118
|
-
const reader: BytesReader = new BytesReader(data);
|
|
119
|
-
|
|
120
|
-
this.
|
|
121
|
-
this.
|
|
122
|
-
this.currentBlock = reader.readU256();
|
|
123
|
-
|
|
124
|
-
this._owner = reader.readAddress();
|
|
125
|
-
this._contractAddress = reader.readAddress();
|
|
126
|
-
|
|
127
|
-
this._timestamp = reader.readU64();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
|
|
131
|
-
if (destinationContract === this.
|
|
132
|
-
throw this.error('Cannot call self');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (!destinationContract) {
|
|
136
|
-
throw this.error('Destination contract is required');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const call = new BytesWriter();
|
|
140
|
-
call.writeAddress(destinationContract);
|
|
141
|
-
call.writeBytesWithLength(calldata.getBuffer());
|
|
142
|
-
|
|
143
|
-
const response: Uint8Array = callContract(call.getBuffer());
|
|
144
|
-
|
|
145
|
-
return new BytesReader(response);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
public log(data: string): void {
|
|
149
|
-
const writer = new BytesWriter();
|
|
150
|
-
writer.writeStringWithLength(data);
|
|
151
|
-
|
|
152
|
-
const buffer = writer.getBuffer();
|
|
153
|
-
log(buffer);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
public addEvent(event: NetEvent): void {
|
|
157
|
-
if (this.events.length >= i32(MAX_EVENTS)) {
|
|
158
|
-
throw this.error(`Too many events in the same transaction.`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
this.events.push(event);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
public getEvents(): Uint8Array {
|
|
165
|
-
const eventLength: u16 = u16(this.events.length);
|
|
166
|
-
if (eventLength > MAX_EVENTS) {
|
|
167
|
-
throw this.error('Too many events');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const buffer: BytesWriter = new BytesWriter();
|
|
171
|
-
buffer.writeU16(eventLength);
|
|
172
|
-
|
|
173
|
-
for (let i: u8 = 0; i < eventLength; i++) {
|
|
174
|
-
const event: NetEvent = this.events[i];
|
|
175
|
-
|
|
176
|
-
buffer.writeStringWithLength(event.eventType);
|
|
177
|
-
buffer.writeU64(event.getEventDataSelector());
|
|
178
|
-
buffer.writeBytesWithLength(event.getEventData());
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return buffer.getBuffer();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public encodeVirtualAddress(virtualAddress: Uint8Array): Address {
|
|
185
|
-
const writer: BytesWriter = new BytesWriter();
|
|
186
|
-
writer.writeBytesWithLength(virtualAddress);
|
|
187
|
-
|
|
188
|
-
const buffer: Uint8Array = writer.getBuffer();
|
|
189
|
-
const cb: Potential<Uint8Array> = encodeAddress(buffer);
|
|
190
|
-
if (!cb) throw this.error('Failed to encode virtual address');
|
|
191
|
-
|
|
192
|
-
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
193
|
-
return reader.readAddress();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public deployContract(hash: u256, bytecode: Uint8Array): DeployContractResponse {
|
|
197
|
-
const writer = new BytesWriter();
|
|
198
|
-
writer.writeU256(hash);
|
|
199
|
-
writer.writeBytes(bytecode);
|
|
200
|
-
|
|
201
|
-
const cb: Potential<Uint8Array> = deploy(writer.getBuffer());
|
|
202
|
-
if (!cb) throw this.error('Failed to deploy contract');
|
|
203
|
-
|
|
204
|
-
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
205
|
-
const virtualAddress: u256 = reader.readU256();
|
|
206
|
-
const contractAddress: Address = reader.readAddress();
|
|
207
|
-
|
|
208
|
-
return new DeployContractResponse(virtualAddress, contractAddress);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
public deployContractFromExisting(
|
|
212
|
-
existingAddress: Address,
|
|
213
|
-
salt: u256,
|
|
214
|
-
): DeployContractResponse {
|
|
215
|
-
const writer = new BytesWriter();
|
|
216
|
-
writer.writeAddress(existingAddress);
|
|
217
|
-
writer.writeU256(salt);
|
|
218
|
-
|
|
219
|
-
const buffer: Uint8Array = writer.getBuffer();
|
|
220
|
-
const cb: Potential<Uint8Array> = deployFromAddress(buffer);
|
|
221
|
-
if (!cb) throw this.error('Failed to deploy contract');
|
|
222
|
-
|
|
223
|
-
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
224
|
-
const virtualAddress: u256 = reader.readU256();
|
|
225
|
-
const contractAddress: Address = reader.readAddress();
|
|
226
|
-
|
|
227
|
-
return new DeployContractResponse(virtualAddress, contractAddress);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
public getStorageAt(
|
|
231
|
-
pointer: u16,
|
|
232
|
-
subPointer: MemorySlotPointer,
|
|
233
|
-
defaultValue: MemorySlotData<u256>,
|
|
234
|
-
): MemorySlotData<u256> {
|
|
235
|
-
const pointerHash: MemorySlotPointer = encodePointerHash(pointer, subPointer);
|
|
236
|
-
this.ensureStorageAtPointer(pointerHash, defaultValue);
|
|
237
|
-
|
|
238
|
-
if (this.storage.has(pointerHash)) {
|
|
239
|
-
return this.storage.get(pointerHash);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return defaultValue;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
public hasStorageAt(pointer: u16, subPointer: MemorySlotPointer): bool {
|
|
246
|
-
// We mark zero as the default value for the storage, if something is 0, the storage slot get deleted or is non-existent
|
|
247
|
-
const val: u256 = this.getStorageAt(pointer, subPointer, u256.Zero);
|
|
248
|
-
|
|
249
|
-
return u256.ne(val, u256.Zero);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
public setStorageAt(
|
|
253
|
-
pointer: u16,
|
|
254
|
-
keyPointer: MemorySlotPointer,
|
|
255
|
-
value: MemorySlotData<u256>,
|
|
256
|
-
): void {
|
|
257
|
-
const pointerHash: u256 = encodePointerHash(pointer, keyPointer);
|
|
258
|
-
|
|
259
|
-
this._internalSetStorageAt(pointerHash, value);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
public getViewSelectors(): Uint8Array {
|
|
263
|
-
return ABIRegistry.getViewSelectors();
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
public getMethodSelectors(): Uint8Array {
|
|
267
|
-
return ABIRegistry.getMethodSelectors();
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
public getWriteMethods(): Uint8Array {
|
|
271
|
-
return ABIRegistry.getWriteMethods();
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private error(msg: string): Error {
|
|
275
|
-
return new Error(`${BlockchainEnvironment.runtimeException}: ${msg}`);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private _internalSetStorageAt(pointerHash: u256, value: MemorySlotData<u256>): void {
|
|
279
|
-
this.storage.set(pointerHash, value);
|
|
280
|
-
|
|
281
|
-
const writer: BytesWriter = new BytesWriter();
|
|
282
|
-
writer.writeU256(pointerHash);
|
|
283
|
-
writer.writeU256(value);
|
|
284
|
-
|
|
285
|
-
const buffer: Uint8Array = writer.getBuffer();
|
|
286
|
-
storePointer(buffer);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
private hasPointerStorageHash(pointer: MemorySlotPointer): bool {
|
|
290
|
-
if (this.storage.has(pointer)) {
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// we attempt to load the requested pointer.
|
|
295
|
-
const writer = new BytesWriter();
|
|
296
|
-
writer.writeU256(pointer);
|
|
297
|
-
|
|
298
|
-
const result: Uint8Array = loadPointer(writer.getBuffer());
|
|
299
|
-
const reader: BytesReader = new BytesReader(result);
|
|
300
|
-
|
|
301
|
-
const value: u256 = reader.readU256();
|
|
302
|
-
this.storage.set(pointer, value); // cache the value
|
|
303
|
-
|
|
304
|
-
return !u256.eq(value, u256.Zero);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
private ensureStorageAtPointer(
|
|
308
|
-
pointerHash: MemorySlotPointer,
|
|
309
|
-
defaultValue: MemorySlotData<u256>,
|
|
310
|
-
): void {
|
|
311
|
-
if (!this.hasPointerStorageHash(pointerHash)) {
|
|
312
|
-
if (u256.eq(defaultValue, u256.Zero)) {
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
this._internalSetStorageAt(pointerHash, defaultValue);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
1
|
+
import { Address, PotentialAddress } from '../types/Address';
|
|
2
|
+
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
|
+
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
|
+
import { u256 } from 'as-bignum/assembly';
|
|
5
|
+
import { ABIRegistry } from '../universal/ABIRegistry';
|
|
6
|
+
import { BytesReader } from '../buffer/BytesReader';
|
|
7
|
+
import { encodePointerHash } from '../math/abi';
|
|
8
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
9
|
+
import { MAX_EVENTS, NetEvent } from '../events/NetEvent';
|
|
10
|
+
import { Potential } from '../lang/Definitions';
|
|
11
|
+
import { OP_NET } from '../contracts/OP_NET';
|
|
12
|
+
import { PointerStorage } from '../types';
|
|
13
|
+
import {
|
|
14
|
+
callContract,
|
|
15
|
+
deploy,
|
|
16
|
+
deployFromAddress,
|
|
17
|
+
encodeAddress,
|
|
18
|
+
loadPointer,
|
|
19
|
+
log,
|
|
20
|
+
storePointer,
|
|
21
|
+
} from './global';
|
|
22
|
+
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
23
|
+
import { MapU256 } from '../generic/MapU256';
|
|
24
|
+
|
|
25
|
+
export * from '../env/global';
|
|
26
|
+
|
|
27
|
+
@final
|
|
28
|
+
export class BlockchainEnvironment {
|
|
29
|
+
private static readonly MAX_U16: u16 = 65535;
|
|
30
|
+
private static readonly runtimeException: string = 'RuntimeException';
|
|
31
|
+
|
|
32
|
+
private storage: PointerStorage = new MapU256();
|
|
33
|
+
private events: NetEvent[] = [];
|
|
34
|
+
|
|
35
|
+
private _from: PotentialAddress = null;
|
|
36
|
+
private _sender: PotentialAddress = null;
|
|
37
|
+
private currentBlock: u256 = u256.Zero;
|
|
38
|
+
|
|
39
|
+
constructor() {}
|
|
40
|
+
|
|
41
|
+
private _timestamp: u64 = 0;
|
|
42
|
+
|
|
43
|
+
public get timestamp(): u64 {
|
|
44
|
+
return this._timestamp;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private _contract: Potential<() => OP_NET> = null;
|
|
48
|
+
|
|
49
|
+
public get contract(): OP_NET {
|
|
50
|
+
if (!this._contract) {
|
|
51
|
+
throw this.error('Contract is required');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this._contract();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public set contract(contract: () => OP_NET) {
|
|
58
|
+
this._contract = contract;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private _nextPointer: u16 = 0;
|
|
62
|
+
|
|
63
|
+
public get nextPointer(): u16 {
|
|
64
|
+
if (this._nextPointer === BlockchainEnvironment.MAX_U16) {
|
|
65
|
+
throw this.error(`Out of storage pointer.`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._nextPointer += 1;
|
|
69
|
+
|
|
70
|
+
return this._nextPointer;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public _owner: Potential<Address> = null;
|
|
74
|
+
|
|
75
|
+
public get owner(): Address {
|
|
76
|
+
if (!this._owner) {
|
|
77
|
+
throw this.error('Owner is required');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return this._owner as Address;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public _contractAddress: Potential<Address> = null;
|
|
84
|
+
|
|
85
|
+
public get contractAddress(): Address {
|
|
86
|
+
if (!this._contractAddress) {
|
|
87
|
+
throw this.error('Contract address is required');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this._contractAddress as Address;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public get blockNumber(): u256 {
|
|
94
|
+
return this.currentBlock;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public get blockNumberU64(): u64 {
|
|
98
|
+
return this.currentBlock.toU64();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public from(): Address {
|
|
102
|
+
if (!this._from) {
|
|
103
|
+
throw this.error('Callee is required');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this._from as Address;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public sender(): Address {
|
|
110
|
+
if (!this._sender) {
|
|
111
|
+
throw this.error('Caller is required');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return this._sender as Address;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public setEnvironment(data: Uint8Array): void {
|
|
118
|
+
const reader: BytesReader = new BytesReader(data);
|
|
119
|
+
|
|
120
|
+
this._sender = reader.readAddress();
|
|
121
|
+
this._from = reader.readAddress();
|
|
122
|
+
this.currentBlock = reader.readU256();
|
|
123
|
+
|
|
124
|
+
this._owner = reader.readAddress();
|
|
125
|
+
this._contractAddress = reader.readAddress();
|
|
126
|
+
|
|
127
|
+
this._timestamp = reader.readU64();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
|
|
131
|
+
if (destinationContract === this._from) {
|
|
132
|
+
throw this.error('Cannot call self');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!destinationContract) {
|
|
136
|
+
throw this.error('Destination contract is required');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const call = new BytesWriter();
|
|
140
|
+
call.writeAddress(destinationContract);
|
|
141
|
+
call.writeBytesWithLength(calldata.getBuffer());
|
|
142
|
+
|
|
143
|
+
const response: Uint8Array = callContract(call.getBuffer());
|
|
144
|
+
|
|
145
|
+
return new BytesReader(response);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public log(data: string): void {
|
|
149
|
+
const writer = new BytesWriter();
|
|
150
|
+
writer.writeStringWithLength(data);
|
|
151
|
+
|
|
152
|
+
const buffer = writer.getBuffer();
|
|
153
|
+
log(buffer);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public addEvent(event: NetEvent): void {
|
|
157
|
+
if (this.events.length >= i32(MAX_EVENTS)) {
|
|
158
|
+
throw this.error(`Too many events in the same transaction.`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.events.push(event);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public getEvents(): Uint8Array {
|
|
165
|
+
const eventLength: u16 = u16(this.events.length);
|
|
166
|
+
if (eventLength > MAX_EVENTS) {
|
|
167
|
+
throw this.error('Too many events');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const buffer: BytesWriter = new BytesWriter();
|
|
171
|
+
buffer.writeU16(eventLength);
|
|
172
|
+
|
|
173
|
+
for (let i: u8 = 0; i < eventLength; i++) {
|
|
174
|
+
const event: NetEvent = this.events[i];
|
|
175
|
+
|
|
176
|
+
buffer.writeStringWithLength(event.eventType);
|
|
177
|
+
buffer.writeU64(event.getEventDataSelector());
|
|
178
|
+
buffer.writeBytesWithLength(event.getEventData());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return buffer.getBuffer();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public encodeVirtualAddress(virtualAddress: Uint8Array): Address {
|
|
185
|
+
const writer: BytesWriter = new BytesWriter();
|
|
186
|
+
writer.writeBytesWithLength(virtualAddress);
|
|
187
|
+
|
|
188
|
+
const buffer: Uint8Array = writer.getBuffer();
|
|
189
|
+
const cb: Potential<Uint8Array> = encodeAddress(buffer);
|
|
190
|
+
if (!cb) throw this.error('Failed to encode virtual address');
|
|
191
|
+
|
|
192
|
+
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
193
|
+
return reader.readAddress();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public deployContract(hash: u256, bytecode: Uint8Array): DeployContractResponse {
|
|
197
|
+
const writer = new BytesWriter();
|
|
198
|
+
writer.writeU256(hash);
|
|
199
|
+
writer.writeBytes(bytecode);
|
|
200
|
+
|
|
201
|
+
const cb: Potential<Uint8Array> = deploy(writer.getBuffer());
|
|
202
|
+
if (!cb) throw this.error('Failed to deploy contract');
|
|
203
|
+
|
|
204
|
+
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
205
|
+
const virtualAddress: u256 = reader.readU256();
|
|
206
|
+
const contractAddress: Address = reader.readAddress();
|
|
207
|
+
|
|
208
|
+
return new DeployContractResponse(virtualAddress, contractAddress);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public deployContractFromExisting(
|
|
212
|
+
existingAddress: Address,
|
|
213
|
+
salt: u256,
|
|
214
|
+
): DeployContractResponse {
|
|
215
|
+
const writer = new BytesWriter();
|
|
216
|
+
writer.writeAddress(existingAddress);
|
|
217
|
+
writer.writeU256(salt);
|
|
218
|
+
|
|
219
|
+
const buffer: Uint8Array = writer.getBuffer();
|
|
220
|
+
const cb: Potential<Uint8Array> = deployFromAddress(buffer);
|
|
221
|
+
if (!cb) throw this.error('Failed to deploy contract');
|
|
222
|
+
|
|
223
|
+
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
224
|
+
const virtualAddress: u256 = reader.readU256();
|
|
225
|
+
const contractAddress: Address = reader.readAddress();
|
|
226
|
+
|
|
227
|
+
return new DeployContractResponse(virtualAddress, contractAddress);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public getStorageAt(
|
|
231
|
+
pointer: u16,
|
|
232
|
+
subPointer: MemorySlotPointer,
|
|
233
|
+
defaultValue: MemorySlotData<u256>,
|
|
234
|
+
): MemorySlotData<u256> {
|
|
235
|
+
const pointerHash: MemorySlotPointer = encodePointerHash(pointer, subPointer);
|
|
236
|
+
this.ensureStorageAtPointer(pointerHash, defaultValue);
|
|
237
|
+
|
|
238
|
+
if (this.storage.has(pointerHash)) {
|
|
239
|
+
return this.storage.get(pointerHash);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return defaultValue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public hasStorageAt(pointer: u16, subPointer: MemorySlotPointer): bool {
|
|
246
|
+
// We mark zero as the default value for the storage, if something is 0, the storage slot get deleted or is non-existent
|
|
247
|
+
const val: u256 = this.getStorageAt(pointer, subPointer, u256.Zero);
|
|
248
|
+
|
|
249
|
+
return u256.ne(val, u256.Zero);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public setStorageAt(
|
|
253
|
+
pointer: u16,
|
|
254
|
+
keyPointer: MemorySlotPointer,
|
|
255
|
+
value: MemorySlotData<u256>,
|
|
256
|
+
): void {
|
|
257
|
+
const pointerHash: u256 = encodePointerHash(pointer, keyPointer);
|
|
258
|
+
|
|
259
|
+
this._internalSetStorageAt(pointerHash, value);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public getViewSelectors(): Uint8Array {
|
|
263
|
+
return ABIRegistry.getViewSelectors();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public getMethodSelectors(): Uint8Array {
|
|
267
|
+
return ABIRegistry.getMethodSelectors();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public getWriteMethods(): Uint8Array {
|
|
271
|
+
return ABIRegistry.getWriteMethods();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private error(msg: string): Error {
|
|
275
|
+
return new Error(`${BlockchainEnvironment.runtimeException}: ${msg}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private _internalSetStorageAt(pointerHash: u256, value: MemorySlotData<u256>): void {
|
|
279
|
+
this.storage.set(pointerHash, value);
|
|
280
|
+
|
|
281
|
+
const writer: BytesWriter = new BytesWriter();
|
|
282
|
+
writer.writeU256(pointerHash);
|
|
283
|
+
writer.writeU256(value);
|
|
284
|
+
|
|
285
|
+
const buffer: Uint8Array = writer.getBuffer();
|
|
286
|
+
storePointer(buffer);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private hasPointerStorageHash(pointer: MemorySlotPointer): bool {
|
|
290
|
+
if (this.storage.has(pointer)) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// we attempt to load the requested pointer.
|
|
295
|
+
const writer = new BytesWriter();
|
|
296
|
+
writer.writeU256(pointer);
|
|
297
|
+
|
|
298
|
+
const result: Uint8Array = loadPointer(writer.getBuffer());
|
|
299
|
+
const reader: BytesReader = new BytesReader(result);
|
|
300
|
+
|
|
301
|
+
const value: u256 = reader.readU256();
|
|
302
|
+
this.storage.set(pointer, value); // cache the value
|
|
303
|
+
|
|
304
|
+
return !u256.eq(value, u256.Zero);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private ensureStorageAtPointer(
|
|
308
|
+
pointerHash: MemorySlotPointer,
|
|
309
|
+
defaultValue: MemorySlotData<u256>,
|
|
310
|
+
): void {
|
|
311
|
+
if (!this.hasPointerStorageHash(pointerHash)) {
|
|
312
|
+
if (u256.eq(defaultValue, u256.Zero)) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this._internalSetStorageAt(pointerHash, defaultValue);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|