@btc-vision/btc-runtime 1.0.11 → 1.0.14
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 +2 -2
- package/package.json +1 -1
- package/runtime/buffer/BytesWriter.ts +1 -1
- package/runtime/contracts/OP_20.ts +16 -23
- package/runtime/contracts/interfaces/IOP_20.ts +0 -4
- package/runtime/env/BTCEnvironment.ts +22 -25
- package/runtime/env/global.ts +4 -0
- package/runtime/index.ts +1 -0
- package/runtime/memory/AddressMemoryMap.ts +1 -1
- package/runtime/memory/KeyMerger.ts +1 -1
- package/runtime/storage/StoredString.ts +145 -0
- package/runtime/storage/StoredU256.ts +14 -16
- package/runtime/types/Address.ts +1 -1
- package/runtime/types/SafeMath.ts +37 -6
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
## Introduction
|
|
13
13
|
|
|
14
|
-
The OPNet Smart Contract Runtime
|
|
15
|
-
The runtime is written in AssemblyScript
|
|
14
|
+
The OPNet Smart Contract Runtime contains all the necessary components to effectively create smart contracts on Bitcoin
|
|
15
|
+
L1. The runtime is written in AssemblyScript.
|
|
16
16
|
|
|
17
17
|
### Installation
|
|
18
18
|
|
package/package.json
CHANGED
|
@@ -299,7 +299,7 @@ export class BytesWriter {
|
|
|
299
299
|
|
|
300
300
|
private fromAddress(value: Address): Uint8Array {
|
|
301
301
|
if (value.length > i32(ADDRESS_BYTE_LENGTH)) {
|
|
302
|
-
throw new Revert(
|
|
302
|
+
throw new Revert(`Address is too long ${value.length} > ${ADDRESS_BYTE_LENGTH} bytes`);
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
const bytes: Uint8Array = new Uint8Array(ADDRESS_BYTE_LENGTH);
|
|
@@ -23,29 +23,28 @@ const transferSelector = encodeSelector('transfer');
|
|
|
23
23
|
const transferFromSelector = encodeSelector('transferFrom');
|
|
24
24
|
|
|
25
25
|
export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
26
|
-
public readonly decimals: u8 = 8;
|
|
27
|
-
|
|
28
|
-
public readonly name: string = `OP_20`;
|
|
29
|
-
public readonly symbol: string = `OP`;
|
|
30
|
-
|
|
31
26
|
protected readonly allowanceMap: MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>;
|
|
32
27
|
protected readonly balanceOfMap: AddressMemoryMap<Address, MemorySlotData<u256>>;
|
|
33
28
|
|
|
34
|
-
protected constructor(
|
|
29
|
+
protected constructor(
|
|
30
|
+
protected readonly maxSupply: u256,
|
|
31
|
+
protected readonly decimals: u8,
|
|
32
|
+
protected readonly name: string,
|
|
33
|
+
protected readonly symbol: string,
|
|
34
|
+
) {
|
|
35
35
|
super();
|
|
36
36
|
|
|
37
37
|
this.allowanceMap = new MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>(
|
|
38
38
|
Blockchain.nextPointer,
|
|
39
39
|
u256.Zero,
|
|
40
40
|
);
|
|
41
|
+
|
|
41
42
|
this.balanceOfMap = new AddressMemoryMap<Address, MemorySlotData<u256>>(
|
|
42
43
|
Blockchain.nextPointer,
|
|
43
44
|
u256.Zero,
|
|
44
45
|
);
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
const supply: u256 = Blockchain.getStorageAt(supplyPointer, u256.Zero, u256.Zero);
|
|
48
|
-
this._totalSupply = new StoredU256(supplyPointer, u256.Zero, supply);
|
|
47
|
+
this._totalSupply = new StoredU256(Blockchain.nextPointer, u256.Zero, u256.Zero);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
public _totalSupply: StoredU256;
|
|
@@ -156,10 +155,10 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
156
155
|
response.writeU8(this.decimals);
|
|
157
156
|
break;
|
|
158
157
|
case encodeSelector('name'):
|
|
159
|
-
response.
|
|
158
|
+
response.writeStringWithLength(this.name);
|
|
160
159
|
break;
|
|
161
160
|
case encodeSelector('symbol'):
|
|
162
|
-
response.
|
|
161
|
+
response.writeStringWithLength(this.symbol);
|
|
163
162
|
break;
|
|
164
163
|
case encodeSelector('totalSupply'):
|
|
165
164
|
response.writeU256(this.totalSupply);
|
|
@@ -229,9 +228,7 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
229
228
|
const caller = Blockchain.caller();
|
|
230
229
|
|
|
231
230
|
if (onlyOwner) this.onlyOwner(callee);
|
|
232
|
-
|
|
233
231
|
if (caller !== callee) throw new Revert(`callee != caller`);
|
|
234
|
-
if (callee !== this.owner) throw new Revert('Only indexers can mint tokens');
|
|
235
232
|
|
|
236
233
|
if (!this.balanceOfMap.has(to)) {
|
|
237
234
|
this.balanceOfMap.set(to, value);
|
|
@@ -271,14 +268,10 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
271
268
|
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
272
269
|
this.balanceOfMap.set(caller, newBalance);
|
|
273
270
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
} else {
|
|
277
|
-
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
278
|
-
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
271
|
+
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
272
|
+
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
279
273
|
|
|
280
|
-
|
|
281
|
-
}
|
|
274
|
+
this.balanceOfMap.set(to, newToBalance);
|
|
282
275
|
|
|
283
276
|
this.createTransferEvent(caller, to, value);
|
|
284
277
|
|
|
@@ -345,19 +338,19 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
345
338
|
this.emitEvent(burnEvent);
|
|
346
339
|
}
|
|
347
340
|
|
|
348
|
-
|
|
341
|
+
protected createApproveEvent(owner: Address, spender: Address, value: u256): void {
|
|
349
342
|
const approveEvent = new ApproveEvent(owner, spender, value);
|
|
350
343
|
|
|
351
344
|
this.emitEvent(approveEvent);
|
|
352
345
|
}
|
|
353
346
|
|
|
354
|
-
|
|
347
|
+
protected createMintEvent(owner: Address, value: u256): void {
|
|
355
348
|
const mintEvent = new MintEvent(owner, value);
|
|
356
349
|
|
|
357
350
|
this.emitEvent(mintEvent);
|
|
358
351
|
}
|
|
359
352
|
|
|
360
|
-
|
|
353
|
+
protected createTransferEvent(from: Address, to: Address, value: u256): void {
|
|
361
354
|
const transferEvent = new TransferEvent(from, to, value);
|
|
362
355
|
|
|
363
356
|
this.emitEvent(transferEvent);
|
|
@@ -3,10 +3,6 @@ import { Calldata } from '../../universal/ABIRegistry';
|
|
|
3
3
|
import { StoredU256 } from '../../storage/StoredU256';
|
|
4
4
|
|
|
5
5
|
export interface IOP_20 {
|
|
6
|
-
readonly name: string;
|
|
7
|
-
readonly symbol: string;
|
|
8
|
-
|
|
9
|
-
readonly decimals: u8;
|
|
10
6
|
readonly _totalSupply: StoredU256;
|
|
11
7
|
|
|
12
8
|
balanceOf(callData: Calldata): BytesWriter;
|
|
@@ -11,7 +11,7 @@ import { Potential } from '../lang/Definitions';
|
|
|
11
11
|
import { Map } from '../generic/Map';
|
|
12
12
|
import { OP_NET } from '../contracts/OP_NET';
|
|
13
13
|
import { PointerStorage } from '../types';
|
|
14
|
-
import { deploy, deployFromAddress, loadPointer, storePointer } from './global';
|
|
14
|
+
import { callContract, deploy, deployFromAddress, loadPointer, log, storePointer } from './global';
|
|
15
15
|
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
16
16
|
|
|
17
17
|
export * from '../env/global';
|
|
@@ -81,6 +81,10 @@ export class BlockchainEnvironment {
|
|
|
81
81
|
return this.currentBlock;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
public get blockNumberU64(): u64 {
|
|
85
|
+
return this.currentBlock.toU64();
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
public callee(): Address {
|
|
85
89
|
if (!this._callee) {
|
|
86
90
|
throw this.error('Callee is required');
|
|
@@ -111,25 +115,25 @@ export class BlockchainEnvironment {
|
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
|
|
114
|
-
|
|
118
|
+
if (destinationContract === this._callee) {
|
|
115
119
|
throw this.error('Cannot call self');
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
const call = new BytesWriter();
|
|
123
|
+
call.writeAddress(destinationContract);
|
|
124
|
+
call.writeBytesWithLength(calldata.getBuffer());
|
|
121
125
|
|
|
122
|
-
const response:
|
|
123
|
-
destinationContract,
|
|
124
|
-
externalCalls.length - 1,
|
|
125
|
-
);
|
|
126
|
-
if (!response) {
|
|
127
|
-
throw this.error('external call failed');
|
|
128
|
-
}
|
|
126
|
+
const response: Uint8Array = callContract(call.getBuffer());
|
|
129
127
|
|
|
130
|
-
return new BytesReader(response)
|
|
128
|
+
return new BytesReader(response);
|
|
129
|
+
}
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
public log(data: string): void {
|
|
132
|
+
const writer = new BytesWriter();
|
|
133
|
+
writer.writeStringWithLength(data);
|
|
134
|
+
|
|
135
|
+
const buffer = writer.getBuffer();
|
|
136
|
+
log(buffer);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
public addEvent(event: NetEvent): void {
|
|
@@ -221,10 +225,8 @@ export class BlockchainEnvironment {
|
|
|
221
225
|
pointer: u16,
|
|
222
226
|
keyPointer: MemorySlotPointer,
|
|
223
227
|
value: MemorySlotData<u256>,
|
|
224
|
-
defaultValue: MemorySlotData<u256>,
|
|
225
228
|
): void {
|
|
226
229
|
const pointerHash: u256 = encodePointerHash(pointer, keyPointer);
|
|
227
|
-
this.ensureStorageAtPointer(pointerHash, defaultValue);
|
|
228
230
|
|
|
229
231
|
this._internalSetStorageAt(pointerHash, value);
|
|
230
232
|
}
|
|
@@ -241,11 +243,6 @@ export class BlockchainEnvironment {
|
|
|
241
243
|
return ABIRegistry.getWriteMethods();
|
|
242
244
|
}
|
|
243
245
|
|
|
244
|
-
private purgeMemory(): void {
|
|
245
|
-
this.storage.clear();
|
|
246
|
-
this.events = [];
|
|
247
|
-
}
|
|
248
|
-
|
|
249
246
|
private error(msg: string): Error {
|
|
250
247
|
return new Error(`${BlockchainEnvironment.runtimeException}: ${msg}`);
|
|
251
248
|
}
|
|
@@ -264,10 +261,6 @@ export class BlockchainEnvironment {
|
|
|
264
261
|
|
|
265
262
|
this.storage.set(pointerHash, value);
|
|
266
263
|
|
|
267
|
-
if (u256.eq(value, u256.Zero)) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
264
|
const writer: BytesWriter = new BytesWriter();
|
|
272
265
|
writer.writeU256(pointerHash);
|
|
273
266
|
writer.writeU256(value);
|
|
@@ -305,6 +298,10 @@ export class BlockchainEnvironment {
|
|
|
305
298
|
defaultValue: MemorySlotData<u256>,
|
|
306
299
|
): void {
|
|
307
300
|
if (!this.hasPointerStorageHash(pointerHash)) {
|
|
301
|
+
if (u256.eq(defaultValue, u256.Zero)) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
308
305
|
this._internalSetStorageAt(pointerHash, defaultValue);
|
|
309
306
|
}
|
|
310
307
|
}
|
package/runtime/env/global.ts
CHANGED
|
@@ -17,3 +17,7 @@ export declare function deployFromAddress(data: Uint8Array): Uint8Array;
|
|
|
17
17
|
// @ts-ignore
|
|
18
18
|
@external('env', 'call')
|
|
19
19
|
export declare function callContract(data: Uint8Array): Uint8Array;
|
|
20
|
+
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
@external('env', 'log')
|
|
23
|
+
export declare function log(data: Uint8Array): void;
|
package/runtime/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class AddressMemoryMap<K extends string, V extends MemorySlotData<u256>>
|
|
|
17
17
|
|
|
18
18
|
public set(key: K, value: V): this {
|
|
19
19
|
const keyHash: MemorySlotPointer = encodePointer(key);
|
|
20
|
-
Blockchain.setStorageAt(this.pointer, keyHash, value
|
|
20
|
+
Blockchain.setStorageAt(this.pointer, keyHash, value);
|
|
21
21
|
|
|
22
22
|
return this;
|
|
23
23
|
}
|
|
@@ -24,7 +24,7 @@ export class KeyMerger<K extends string, K2 extends string, V extends MemorySlot
|
|
|
24
24
|
const mergedKey: string = `${this.parentKey}${key2}`;
|
|
25
25
|
const keyHash: MemorySlotPointer = encodePointer(mergedKey);
|
|
26
26
|
|
|
27
|
-
Blockchain.setStorageAt(this.pointer, keyHash, value
|
|
27
|
+
Blockchain.setStorageAt(this.pointer, keyHash, value);
|
|
28
28
|
|
|
29
29
|
return this;
|
|
30
30
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { Blockchain } from '../env';
|
|
3
|
+
import { SafeMath } from '../types/SafeMath';
|
|
4
|
+
|
|
5
|
+
@final
|
|
6
|
+
export class StoredString {
|
|
7
|
+
constructor(
|
|
8
|
+
public pointer: u16,
|
|
9
|
+
private defaultValue?: string,
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
private _value: string = '';
|
|
13
|
+
|
|
14
|
+
@inline
|
|
15
|
+
public get value(): string {
|
|
16
|
+
if (!this._value) {
|
|
17
|
+
this.load();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return this._value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@inline
|
|
24
|
+
public set value(value: string) {
|
|
25
|
+
this._value = value;
|
|
26
|
+
this.save();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private min(a: u32, b: u32): u32 {
|
|
30
|
+
return a < b ? a : b;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private max(a: u32, b: u32): u32 {
|
|
34
|
+
return a > b ? a : b;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private save(): void {
|
|
38
|
+
const length: u32 = this._value.length;
|
|
39
|
+
if (length == 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (length > 2048) {
|
|
44
|
+
throw new Error('StoredString: value is too long');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Prepare the header with the length of the string in the first 4 bytes
|
|
48
|
+
let header: u256 = u256.fromU32(length);
|
|
49
|
+
header = SafeMath.shl(header, 224);
|
|
50
|
+
|
|
51
|
+
let currentPointer: u256 = u256.Zero;
|
|
52
|
+
let remainingLength: u32 = length;
|
|
53
|
+
let offset: u32 = 0;
|
|
54
|
+
|
|
55
|
+
// Save the initial chunk (first 28 bytes) in the header
|
|
56
|
+
let bytesToWrite: u32 = this.min(remainingLength, 28);
|
|
57
|
+
header = this.saveChunk(header, this._value, offset, bytesToWrite, 4);
|
|
58
|
+
Blockchain.setStorageAt(this.pointer, currentPointer, header);
|
|
59
|
+
|
|
60
|
+
remainingLength -= bytesToWrite;
|
|
61
|
+
offset += bytesToWrite;
|
|
62
|
+
|
|
63
|
+
// Save the remaining chunks in subsequent storage slots
|
|
64
|
+
while (remainingLength > 0) {
|
|
65
|
+
bytesToWrite = this.min(remainingLength, 32);
|
|
66
|
+
let storageValue: u256 = this.saveChunk(
|
|
67
|
+
u256.Zero,
|
|
68
|
+
this._value,
|
|
69
|
+
offset,
|
|
70
|
+
bytesToWrite,
|
|
71
|
+
0,
|
|
72
|
+
);
|
|
73
|
+
currentPointer = u256.add(currentPointer, u256.One);
|
|
74
|
+
Blockchain.setStorageAt(this.pointer, currentPointer, storageValue);
|
|
75
|
+
|
|
76
|
+
remainingLength -= bytesToWrite;
|
|
77
|
+
offset += bytesToWrite;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Helper method to save a chunk of the string into the storage slot
|
|
82
|
+
private saveChunk(
|
|
83
|
+
storage: u256,
|
|
84
|
+
value: string,
|
|
85
|
+
offset: u32,
|
|
86
|
+
length: u32,
|
|
87
|
+
storageOffset: u32,
|
|
88
|
+
): u256 {
|
|
89
|
+
let bytes = storage.toBytes(true);
|
|
90
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
91
|
+
let index: i32 = i32(offset + i);
|
|
92
|
+
bytes[i + storageOffset] = u8(value.charCodeAt(index));
|
|
93
|
+
}
|
|
94
|
+
return u256.fromBytes(bytes, true);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private load(): void {
|
|
98
|
+
const header: u256 = Blockchain.getStorageAt(this.pointer, u256.Zero, u256.Zero);
|
|
99
|
+
if (u256.eq(header, u256.Zero)) {
|
|
100
|
+
if (this.defaultValue) {
|
|
101
|
+
this.value = this.defaultValue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// the length of the string is stored in the first 4 bytes of the header
|
|
108
|
+
const bits: u256 = u256.shr(header, 224);
|
|
109
|
+
const length: u32 = bits.toU32();
|
|
110
|
+
|
|
111
|
+
// the rest contains the string itself
|
|
112
|
+
let currentPointer: u256 = u256.Zero;
|
|
113
|
+
let remainingLength: u32 = length;
|
|
114
|
+
let currentStorage: u256 = header;
|
|
115
|
+
|
|
116
|
+
let bytesToRead: u32 = this.min(remainingLength, 28);
|
|
117
|
+
let str: string = this.loadChunk(currentStorage, 4, bytesToRead);
|
|
118
|
+
remainingLength -= bytesToRead;
|
|
119
|
+
|
|
120
|
+
while (remainingLength > 0) {
|
|
121
|
+
// Move to the next storage slot
|
|
122
|
+
currentPointer = u256.add(currentPointer, u256.One);
|
|
123
|
+
currentStorage = Blockchain.getStorageAt(this.pointer, currentPointer, u256.Zero);
|
|
124
|
+
|
|
125
|
+
// Extract the relevant portion of the string from the current storage slot
|
|
126
|
+
let bytesToRead: u32 = this.min(remainingLength, 32);
|
|
127
|
+
str += this.loadChunk(currentStorage, 0, bytesToRead);
|
|
128
|
+
|
|
129
|
+
remainingLength -= bytesToRead;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this._value = str;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private loadChunk(value: u256, offset: u32, length: u32): string {
|
|
136
|
+
const bytes = value.toBytes(true);
|
|
137
|
+
|
|
138
|
+
let str: string = '';
|
|
139
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
140
|
+
str += String.fromCharCode(bytes[i + offset]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return str;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -9,9 +9,7 @@ export class StoredU256 {
|
|
|
9
9
|
public pointer: u16,
|
|
10
10
|
public subPointer: MemorySlotPointer,
|
|
11
11
|
private defaultValue: u256,
|
|
12
|
-
) {
|
|
13
|
-
this._value = Blockchain.getStorageAt(this.pointer, this.subPointer, this.defaultValue);
|
|
14
|
-
}
|
|
12
|
+
) {}
|
|
15
13
|
|
|
16
14
|
private _value: u256 = u256.Zero;
|
|
17
15
|
|
|
@@ -26,7 +24,7 @@ export class StoredU256 {
|
|
|
26
24
|
public set value(value: u256) {
|
|
27
25
|
this._value = value;
|
|
28
26
|
|
|
29
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
27
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
@inline
|
|
@@ -40,7 +38,7 @@ export class StoredU256 {
|
|
|
40
38
|
this.ensureValue();
|
|
41
39
|
|
|
42
40
|
this._value = SafeMath.add(this._value, value);
|
|
43
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
41
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
44
42
|
|
|
45
43
|
return this;
|
|
46
44
|
}
|
|
@@ -51,7 +49,7 @@ export class StoredU256 {
|
|
|
51
49
|
this.ensureValue();
|
|
52
50
|
|
|
53
51
|
this._value = SafeMath.sub(this._value, value);
|
|
54
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
52
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
55
53
|
|
|
56
54
|
return this;
|
|
57
55
|
}
|
|
@@ -62,7 +60,7 @@ export class StoredU256 {
|
|
|
62
60
|
this.ensureValue();
|
|
63
61
|
|
|
64
62
|
this._value = SafeMath.mul(this._value, value);
|
|
65
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
63
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
66
64
|
|
|
67
65
|
return this;
|
|
68
66
|
}
|
|
@@ -121,7 +119,7 @@ export class StoredU256 {
|
|
|
121
119
|
this.ensureValue();
|
|
122
120
|
|
|
123
121
|
this._value = u256.shr(this._value, value);
|
|
124
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
122
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
125
123
|
|
|
126
124
|
return this;
|
|
127
125
|
}
|
|
@@ -132,7 +130,7 @@ export class StoredU256 {
|
|
|
132
130
|
this.ensureValue();
|
|
133
131
|
|
|
134
132
|
this._value = u256.and(this._value, value);
|
|
135
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
133
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
136
134
|
|
|
137
135
|
return this;
|
|
138
136
|
}
|
|
@@ -143,7 +141,7 @@ export class StoredU256 {
|
|
|
143
141
|
this.ensureValue();
|
|
144
142
|
|
|
145
143
|
this._value = u256.or(this._value, value);
|
|
146
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
144
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
147
145
|
|
|
148
146
|
return this;
|
|
149
147
|
}
|
|
@@ -154,7 +152,7 @@ export class StoredU256 {
|
|
|
154
152
|
this.ensureValue();
|
|
155
153
|
|
|
156
154
|
this._value = u256.xor(this._value, value);
|
|
157
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
155
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
158
156
|
|
|
159
157
|
return this;
|
|
160
158
|
}
|
|
@@ -176,7 +174,7 @@ export class StoredU256 {
|
|
|
176
174
|
value = u256.shr(value, 1);
|
|
177
175
|
}
|
|
178
176
|
|
|
179
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
177
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
180
178
|
|
|
181
179
|
return this;
|
|
182
180
|
}
|
|
@@ -201,7 +199,7 @@ export class StoredU256 {
|
|
|
201
199
|
}
|
|
202
200
|
|
|
203
201
|
this._value = result;
|
|
204
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
202
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
205
203
|
|
|
206
204
|
return this;
|
|
207
205
|
}
|
|
@@ -212,7 +210,7 @@ export class StoredU256 {
|
|
|
212
210
|
this.ensureValue();
|
|
213
211
|
|
|
214
212
|
this._value = SafeMath.add(this._value, u256.One);
|
|
215
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
213
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
216
214
|
|
|
217
215
|
return this;
|
|
218
216
|
}
|
|
@@ -223,7 +221,7 @@ export class StoredU256 {
|
|
|
223
221
|
this.ensureValue();
|
|
224
222
|
|
|
225
223
|
this._value = SafeMath.sub(this._value, u256.One);
|
|
226
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
224
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
227
225
|
|
|
228
226
|
return this;
|
|
229
227
|
}
|
|
@@ -232,7 +230,7 @@ export class StoredU256 {
|
|
|
232
230
|
public set(value: u256): this {
|
|
233
231
|
this._value = value;
|
|
234
232
|
|
|
235
|
-
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value
|
|
233
|
+
Blockchain.setStorageAt(this.pointer, this.subPointer, this._value);
|
|
236
234
|
|
|
237
235
|
return this;
|
|
238
236
|
}
|
package/runtime/types/Address.ts
CHANGED
|
@@ -19,6 +19,30 @@ export class SafeMath {
|
|
|
19
19
|
return u256.sub(a, b);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Computes (a * b) % modulus with full precision
|
|
23
|
+
public static mulmod(a: u256, b: u256, modulus: u256): u256 {
|
|
24
|
+
if (u256.eq(modulus, u256.Zero)) throw new Error('SafeMath: modulo by zero');
|
|
25
|
+
|
|
26
|
+
const mul = SafeMath.mul(a, b);
|
|
27
|
+
return SafeMath.mod(mul, modulus);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@inline
|
|
31
|
+
@unsafe
|
|
32
|
+
@operator('%')
|
|
33
|
+
public static mod(a: u256, b: u256): u256 {
|
|
34
|
+
if (u256.eq(b, u256.Zero)) {
|
|
35
|
+
throw new Error('SafeMath: modulo by zero');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let result = a.clone();
|
|
39
|
+
while (u256.ge(result, b)) {
|
|
40
|
+
result = u256.sub(result, b);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
22
46
|
public static mul(a: u256, b: u256): u256 {
|
|
23
47
|
if (a === SafeMath.ZERO || b === SafeMath.ZERO) {
|
|
24
48
|
return SafeMath.ZERO;
|
|
@@ -37,7 +61,7 @@ export class SafeMath {
|
|
|
37
61
|
@inline
|
|
38
62
|
@unsafe
|
|
39
63
|
@operator('/')
|
|
40
|
-
static div(a: u256, b: u256): u256 {
|
|
64
|
+
public static div(a: u256, b: u256): u256 {
|
|
41
65
|
if (b.isZero()) {
|
|
42
66
|
throw new Error('Division by zero');
|
|
43
67
|
}
|
|
@@ -64,7 +88,7 @@ export class SafeMath {
|
|
|
64
88
|
for (let i = shift; i >= 0; i--) {
|
|
65
89
|
if (u256.ge(n, d)) {
|
|
66
90
|
n = u256.sub(n, d);
|
|
67
|
-
result = u256.or(result, SafeMath.shl(
|
|
91
|
+
result = u256.or(result, SafeMath.shl(u256.One, i));
|
|
68
92
|
}
|
|
69
93
|
d = u256.shr(d, 1); // restore d to original by shifting right
|
|
70
94
|
}
|
|
@@ -86,16 +110,23 @@ export class SafeMath {
|
|
|
86
110
|
if (u256.gt(y, u256.fromU32(3))) {
|
|
87
111
|
let z = y;
|
|
88
112
|
|
|
89
|
-
let
|
|
113
|
+
let u246_2 = u256.fromU32(2);
|
|
114
|
+
|
|
115
|
+
let d = SafeMath.div(y, u246_2);
|
|
116
|
+
let x = SafeMath.add(d, u256.One);
|
|
117
|
+
|
|
90
118
|
while (u256.lt(x, z)) {
|
|
91
119
|
z = x;
|
|
92
120
|
|
|
93
121
|
let u = SafeMath.div(y, x);
|
|
94
|
-
|
|
122
|
+
let y2 = u256.add(u, x);
|
|
123
|
+
|
|
124
|
+
x = SafeMath.div(y2, u246_2);
|
|
95
125
|
}
|
|
126
|
+
|
|
96
127
|
return z;
|
|
97
128
|
} else if (!u256.eq(y, u256.Zero)) {
|
|
98
|
-
return u256.
|
|
129
|
+
return u256.One;
|
|
99
130
|
} else {
|
|
100
131
|
return u256.Zero;
|
|
101
132
|
}
|
|
@@ -103,7 +134,7 @@ export class SafeMath {
|
|
|
103
134
|
|
|
104
135
|
@inline
|
|
105
136
|
@unsafe
|
|
106
|
-
static shl(value: u256, shift: i32): u256 {
|
|
137
|
+
public static shl(value: u256, shift: i32): u256 {
|
|
107
138
|
if (shift == 0) {
|
|
108
139
|
return value.clone();
|
|
109
140
|
}
|