@btc-vision/btc-runtime 1.1.4 → 1.1.5
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
CHANGED
|
@@ -1,200 +1,200 @@
|
|
|
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
|
-
let bytes: Uint8Array = new Uint8Array(length);
|
|
60
|
-
for (let i: u32 = 0; i < length; i++) {
|
|
61
|
-
const byte: u8 = this.readU8();
|
|
62
|
-
if (zeroStop && byte === 0) {
|
|
63
|
-
bytes = bytes.slice(0, i);
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
bytes[i] = byte;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return bytes;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public readMultiBytesAddressMap(): Map<Address, Uint8Array[]> {
|
|
74
|
-
const map: Map<Address, Uint8Array[]> = new Map<Address, Uint8Array[]>();
|
|
75
|
-
const size: u8 = this.readU8();
|
|
76
|
-
|
|
77
|
-
if (size > 8) throw new Revert('Too many contract called.');
|
|
78
|
-
|
|
79
|
-
for (let i: u8 = 0; i < size; i++) {
|
|
80
|
-
const address: Address = this.readAddress();
|
|
81
|
-
const responseSize: u8 = this.readU8();
|
|
82
|
-
|
|
83
|
-
if (responseSize > 10) throw new Revert('Too many calls.');
|
|
84
|
-
|
|
85
|
-
const calls: Uint8Array[] = [];
|
|
86
|
-
for (let j: u8 = 0; j < responseSize; j++) {
|
|
87
|
-
const response: Uint8Array = this.readBytesWithLength();
|
|
88
|
-
calls.push(response);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
map.set(address, calls);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return map;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public readBytesWithLength(): Uint8Array {
|
|
98
|
-
const length = this.readU32();
|
|
99
|
-
|
|
100
|
-
return this.readBytes(length);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public readString(length: u16): string {
|
|
104
|
-
const bytes = this.readBytes(length, true);
|
|
105
|
-
|
|
106
|
-
return String.UTF8.decode(bytes.buffer);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public readTuple(): u256[] {
|
|
110
|
-
const length = this.readU32();
|
|
111
|
-
const result: u256[] = new Array<u256>(length);
|
|
112
|
-
|
|
113
|
-
for (let i = 0; i < length; i++) {
|
|
114
|
-
result[i] = this.readU256();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
public readAddressValueTuple(): Map<Address, u256> {
|
|
121
|
-
const length: u16 = this.readU16();
|
|
122
|
-
const result = new Map<Address, u256>();
|
|
123
|
-
|
|
124
|
-
for (let i: u16 = 0; i < length; i++) {
|
|
125
|
-
const address = this.readAddress();
|
|
126
|
-
const value = this.readU256();
|
|
127
|
-
|
|
128
|
-
if (result.has(address)) throw new Revert('Duplicate address found in map');
|
|
129
|
-
|
|
130
|
-
result.set(address, value);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return result;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
public readSelector(): Selector {
|
|
137
|
-
return this.readU32(false);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
public readStringWithLength(): string {
|
|
141
|
-
const length = this.readU16();
|
|
142
|
-
|
|
143
|
-
return this.readString(length);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public readBoolean(): boolean {
|
|
147
|
-
return this.readU8() !== 0;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
public readFloat(): f32 {
|
|
151
|
-
const value = this.buffer.getFloat32(this.currentOffset, true);
|
|
152
|
-
this.currentOffset += 4;
|
|
153
|
-
|
|
154
|
-
return value;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public readAddress(): Address {
|
|
158
|
-
return this.readString(ADDRESS_BYTE_LENGTH);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
public getOffset(): i32 {
|
|
162
|
-
return this.currentOffset;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public setOffset(offset: i32): void {
|
|
166
|
-
this.currentOffset = offset;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
public verifyEnd(size: i32): void {
|
|
170
|
-
if (this.currentOffset > this.buffer.byteLength) {
|
|
171
|
-
throw new Error(`Expected to read ${size} bytes but read ${this.currentOffset} bytes`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
public readAddressArray(): Address[] {
|
|
176
|
-
const length = this.readU16();
|
|
177
|
-
const result = new Array<Address>(length);
|
|
178
|
-
|
|
179
|
-
for (let i: u16 = 0; i < length; i++) {
|
|
180
|
-
result[i] = this.readAddress();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private verifyChecksum(): void {
|
|
187
|
-
const writtenChecksum = this.readU32();
|
|
188
|
-
|
|
189
|
-
let checksum: u32 = 0;
|
|
190
|
-
for (let i = 0; i < this.buffer.byteLength; i++) {
|
|
191
|
-
checksum += this.buffer.getUint8(i);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
checksum = checksum % 2 ** 32;
|
|
195
|
-
|
|
196
|
-
if (checksum !== writtenChecksum) {
|
|
197
|
-
throw new Error('Invalid checksum for buffer');
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
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
|
+
let bytes: Uint8Array = new Uint8Array(length);
|
|
60
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
61
|
+
const byte: u8 = this.readU8();
|
|
62
|
+
if (zeroStop && byte === 0) {
|
|
63
|
+
bytes = bytes.slice(0, i);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
bytes[i] = byte;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return bytes;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public readMultiBytesAddressMap(): Map<Address, Uint8Array[]> {
|
|
74
|
+
const map: Map<Address, Uint8Array[]> = new Map<Address, Uint8Array[]>();
|
|
75
|
+
const size: u8 = this.readU8();
|
|
76
|
+
|
|
77
|
+
if (size > 8) throw new Revert('Too many contract called.');
|
|
78
|
+
|
|
79
|
+
for (let i: u8 = 0; i < size; i++) {
|
|
80
|
+
const address: Address = this.readAddress();
|
|
81
|
+
const responseSize: u8 = this.readU8();
|
|
82
|
+
|
|
83
|
+
if (responseSize > 10) throw new Revert('Too many calls.');
|
|
84
|
+
|
|
85
|
+
const calls: Uint8Array[] = [];
|
|
86
|
+
for (let j: u8 = 0; j < responseSize; j++) {
|
|
87
|
+
const response: Uint8Array = this.readBytesWithLength();
|
|
88
|
+
calls.push(response);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
map.set(address, calls);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return map;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public readBytesWithLength(): Uint8Array {
|
|
98
|
+
const length = this.readU32();
|
|
99
|
+
|
|
100
|
+
return this.readBytes(length);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public readString(length: u16): string {
|
|
104
|
+
const bytes = this.readBytes(length, true);
|
|
105
|
+
|
|
106
|
+
return String.UTF8.decode(bytes.buffer);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public readTuple(): u256[] {
|
|
110
|
+
const length = this.readU32();
|
|
111
|
+
const result: u256[] = new Array<u256>(length);
|
|
112
|
+
|
|
113
|
+
for (let i: u32 = 0; i < length; i++) {
|
|
114
|
+
result[i] = this.readU256();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public readAddressValueTuple(): Map<Address, u256> {
|
|
121
|
+
const length: u16 = this.readU16();
|
|
122
|
+
const result = new Map<Address, u256>();
|
|
123
|
+
|
|
124
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
125
|
+
const address = this.readAddress();
|
|
126
|
+
const value = this.readU256();
|
|
127
|
+
|
|
128
|
+
if (result.has(address)) throw new Revert('Duplicate address found in map');
|
|
129
|
+
|
|
130
|
+
result.set(address, value);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public readSelector(): Selector {
|
|
137
|
+
return this.readU32(false);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public readStringWithLength(): string {
|
|
141
|
+
const length = this.readU16();
|
|
142
|
+
|
|
143
|
+
return this.readString(length);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public readBoolean(): boolean {
|
|
147
|
+
return this.readU8() !== 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public readFloat(): f32 {
|
|
151
|
+
const value = this.buffer.getFloat32(this.currentOffset, true);
|
|
152
|
+
this.currentOffset += 4;
|
|
153
|
+
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public readAddress(): Address {
|
|
158
|
+
return this.readString(ADDRESS_BYTE_LENGTH);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public getOffset(): i32 {
|
|
162
|
+
return this.currentOffset;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public setOffset(offset: i32): void {
|
|
166
|
+
this.currentOffset = offset;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public verifyEnd(size: i32): void {
|
|
170
|
+
if (this.currentOffset > this.buffer.byteLength) {
|
|
171
|
+
throw new Error(`Expected to read ${size} bytes but read ${this.currentOffset} bytes`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public readAddressArray(): Address[] {
|
|
176
|
+
const length = this.readU16();
|
|
177
|
+
const result = new Array<Address>(length);
|
|
178
|
+
|
|
179
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
180
|
+
result[i] = this.readAddress();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private verifyChecksum(): void {
|
|
187
|
+
const writtenChecksum = this.readU32();
|
|
188
|
+
|
|
189
|
+
let checksum: u32 = 0;
|
|
190
|
+
for (let i = 0; i < this.buffer.byteLength; i++) {
|
|
191
|
+
checksum += this.buffer.getUint8(i);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
checksum = checksum % 2 ** 32;
|
|
195
|
+
|
|
196
|
+
if (checksum !== writtenChecksum) {
|
|
197
|
+
throw new Error('Invalid checksum for buffer');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -9,6 +9,7 @@ import { cyrb53a } from '../math/cyrb53';
|
|
|
9
9
|
import { Revert } from '../types/Revert';
|
|
10
10
|
import { Map } from '../generic/Map';
|
|
11
11
|
import { BlockchainStorage, PointerStorage } from '../types';
|
|
12
|
+
import { ArrayBuffer } from 'arraybuffer';
|
|
12
13
|
|
|
13
14
|
export enum BufferDataType {
|
|
14
15
|
U8 = 0,
|
|
@@ -32,7 +33,9 @@ export class BytesWriter {
|
|
|
32
33
|
length: i32 = 1,
|
|
33
34
|
private readonly trackDataTypes: boolean = false,
|
|
34
35
|
) {
|
|
35
|
-
|
|
36
|
+
const arrayBuffer = new ArrayBuffer(length);
|
|
37
|
+
|
|
38
|
+
this.buffer = new DataView(arrayBuffer);
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
public bufferLength(): u32 {
|
|
@@ -239,11 +242,12 @@ export class BytesWriter {
|
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
244
|
|
|
242
|
-
public getBuffer(clear: boolean =
|
|
243
|
-
const buf =
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
public getBuffer(clear: boolean = false): Uint8Array {
|
|
246
|
+
const buf = Uint8Array.wrap(
|
|
247
|
+
this.buffer.buffer,
|
|
248
|
+
this.buffer.byteOffset,
|
|
249
|
+
this.buffer.byteLength,
|
|
250
|
+
);
|
|
247
251
|
|
|
248
252
|
if (clear) this.clear();
|
|
249
253
|
|
|
@@ -94,7 +94,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
94
94
|
throw new Revert('Already initialized');
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
if (!skipOwnerVerification) this.onlyOwner(Blockchain.
|
|
97
|
+
if (!skipOwnerVerification) this.onlyOwner(Blockchain.txOrigin);
|
|
98
98
|
|
|
99
99
|
if (params.decimals > 32) {
|
|
100
100
|
throw new Revert('Decimals can not be more than 32');
|
|
@@ -117,15 +117,16 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
public approve(callData: Calldata): BytesWriter {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
// Define the owner and spender
|
|
121
|
+
const owner = Blockchain.msgSender;
|
|
122
122
|
const spender: Address = callData.readAddress();
|
|
123
123
|
const value = callData.readU256();
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
response
|
|
125
|
+
// Response buffer
|
|
126
|
+
const response = new BytesWriter();
|
|
127
127
|
|
|
128
|
-
this.
|
|
128
|
+
const resp = this._approve(owner, spender, value);
|
|
129
|
+
response.writeBoolean(resp);
|
|
129
130
|
|
|
130
131
|
return response;
|
|
131
132
|
}
|
|
@@ -233,12 +234,16 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
233
234
|
return senderMap.get(spender);
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
protected _approve(spender: Address, value: u256): boolean {
|
|
237
|
-
|
|
237
|
+
protected _approve(owner: Address, spender: Address, value: u256): boolean {
|
|
238
|
+
if (owner === Blockchain.DEAD_ADDRESS || spender === Blockchain.DEAD_ADDRESS) {
|
|
239
|
+
throw new Revert('Cannot approve from or to dead address');
|
|
240
|
+
}
|
|
238
241
|
|
|
239
|
-
const senderMap = this.allowanceMap.get(
|
|
242
|
+
const senderMap = this.allowanceMap.get(owner);
|
|
240
243
|
senderMap.set(spender, value);
|
|
241
244
|
|
|
245
|
+
this.createApproveEvent(owner, spender, value);
|
|
246
|
+
|
|
242
247
|
return true;
|
|
243
248
|
}
|
|
244
249
|
|
|
@@ -254,19 +259,16 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
254
259
|
throw new Revert(`No tokens`);
|
|
255
260
|
}
|
|
256
261
|
|
|
257
|
-
|
|
258
|
-
const caller = Blockchain.sender;
|
|
259
|
-
|
|
260
|
-
if (onlyOwner) this.onlyOwner(callee); // only indexers can burn tokens
|
|
262
|
+
if (onlyOwner) this.onlyOwner(Blockchain.txOrigin); // only indexers can burn tokens
|
|
261
263
|
|
|
262
264
|
if (this._totalSupply.value < value) throw new Revert(`Insufficient total supply.`);
|
|
263
|
-
if (!this.balanceOfMap.has(
|
|
265
|
+
if (!this.balanceOfMap.has(Blockchain.msgSender)) throw new Revert('No balance');
|
|
264
266
|
|
|
265
|
-
const balance: u256 = this.balanceOfMap.get(
|
|
267
|
+
const balance: u256 = this.balanceOfMap.get(Blockchain.msgSender);
|
|
266
268
|
if (balance < value) throw new Revert(`Insufficient balance`);
|
|
267
269
|
|
|
268
270
|
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
269
|
-
this.balanceOfMap.set(
|
|
271
|
+
this.balanceOfMap.set(Blockchain.msgSender, newBalance);
|
|
270
272
|
|
|
271
273
|
// @ts-ignore
|
|
272
274
|
this._totalSupply -= value;
|
|
@@ -276,9 +278,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
protected _mint(to: Address, value: u256, onlyOwner: boolean = true): boolean {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (onlyOwner) this.onlyOwner(callee);
|
|
281
|
+
if (onlyOwner) this.onlyOwner(Blockchain.txOrigin);
|
|
282
282
|
|
|
283
283
|
if (!this.balanceOfMap.has(to)) {
|
|
284
284
|
this.balanceOfMap.set(to, value);
|
|
@@ -299,31 +299,27 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
protected _transfer(to: string, value: u256): boolean {
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
if (!this.balanceOfMap.has(caller)) throw new Revert();
|
|
305
|
-
if (this.isSelf(caller)) throw new Revert('Can not transfer from self account');
|
|
302
|
+
const sender = Blockchain.msgSender;
|
|
306
303
|
|
|
307
|
-
if (
|
|
308
|
-
|
|
309
|
-
}
|
|
304
|
+
if (!this.balanceOfMap.has(sender)) throw new Revert();
|
|
305
|
+
if (this.isSelf(sender)) throw new Revert('Can not transfer from self account');
|
|
310
306
|
|
|
311
307
|
if (u256.eq(value, u256.Zero)) {
|
|
312
308
|
throw new Revert(`Cannot transfer 0 tokens`);
|
|
313
309
|
}
|
|
314
310
|
|
|
315
|
-
const balance: u256 = this.balanceOfMap.get(
|
|
311
|
+
const balance: u256 = this.balanceOfMap.get(sender);
|
|
316
312
|
if (balance < value) throw new Revert(`Insufficient balance`);
|
|
317
313
|
|
|
318
314
|
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
319
|
-
this.balanceOfMap.set(
|
|
315
|
+
this.balanceOfMap.set(sender, newBalance);
|
|
320
316
|
|
|
321
317
|
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
322
318
|
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
323
319
|
|
|
324
320
|
this.balanceOfMap.set(to, newToBalance);
|
|
325
321
|
|
|
326
|
-
this.createTransferEvent(
|
|
322
|
+
this.createTransferEvent(sender, to, value);
|
|
327
323
|
|
|
328
324
|
return true;
|
|
329
325
|
}
|
|
@@ -337,7 +333,6 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
337
333
|
);
|
|
338
334
|
|
|
339
335
|
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
340
|
-
|
|
341
336
|
this.balanceOfMap.set(from, newBalance);
|
|
342
337
|
|
|
343
338
|
if (!this.balanceOfMap.has(to)) {
|
|
@@ -355,22 +350,30 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
355
350
|
}
|
|
356
351
|
|
|
357
352
|
protected _transferFrom(from: Address, to: Address, value: u256): boolean {
|
|
358
|
-
|
|
353
|
+
if (to === Blockchain.DEAD_ADDRESS || from === Blockchain.DEAD_ADDRESS) {
|
|
354
|
+
throw new Revert('Cannot transfer to or from dead address');
|
|
355
|
+
}
|
|
359
356
|
|
|
360
|
-
|
|
357
|
+
this._spendAllowance(from, Blockchain.msgSender, value);
|
|
358
|
+
this._unsafeTransferFrom(from, to, value);
|
|
361
359
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (allowed < value) throw new Revert(`Insufficient allowance ${allowed} < ${value}`);
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
365
362
|
|
|
366
|
-
|
|
367
|
-
|
|
363
|
+
protected _spendAllowance(owner: Address, spender: Address, value: u256): void {
|
|
364
|
+
const ownerAllowanceMap = this.allowanceMap.get(owner);
|
|
365
|
+
const allowed: u256 = ownerAllowanceMap.get(spender);
|
|
368
366
|
|
|
369
|
-
|
|
367
|
+
if (allowed < value) {
|
|
368
|
+
throw new Revert(
|
|
369
|
+
`Insufficient allowance ${allowed} < ${value}. Spender: ${spender} - Owner: ${owner}`,
|
|
370
|
+
);
|
|
371
|
+
}
|
|
370
372
|
|
|
371
|
-
|
|
373
|
+
const newAllowance: u256 = SafeMath.sub(allowed, value);
|
|
374
|
+
ownerAllowanceMap.set(spender, newAllowance);
|
|
372
375
|
|
|
373
|
-
|
|
376
|
+
this.allowanceMap.set(owner, ownerAllowanceMap);
|
|
374
377
|
}
|
|
375
378
|
|
|
376
379
|
protected createBurnEvent(value: u256): void {
|
|
@@ -28,7 +28,7 @@ export * from '../env/global';
|
|
|
28
28
|
export class BlockchainEnvironment {
|
|
29
29
|
private static readonly MAX_U16: u16 = 65535;
|
|
30
30
|
private static readonly runtimeException: string = 'RuntimeException';
|
|
31
|
-
|
|
31
|
+
public readonly DEAD_ADDRESS: Address = 'bc1dead';
|
|
32
32
|
private storage: PointerStorage = new MapU256();
|
|
33
33
|
private events: NetEvent[] = [];
|
|
34
34
|
private currentBlock: u256 = u256.Zero;
|
|
@@ -37,24 +37,24 @@ export class BlockchainEnvironment {
|
|
|
37
37
|
|
|
38
38
|
constructor() {}
|
|
39
39
|
|
|
40
|
-
private
|
|
40
|
+
private _txOrigin: PotentialAddress = null;
|
|
41
41
|
|
|
42
|
-
public get
|
|
43
|
-
if (!this.
|
|
42
|
+
public get txOrigin(): Address {
|
|
43
|
+
if (!this._txOrigin) {
|
|
44
44
|
throw this.error('Callee is required');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
return this.
|
|
47
|
+
return this._txOrigin as Address;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
private
|
|
50
|
+
private _msgSender: PotentialAddress = null;
|
|
51
51
|
|
|
52
|
-
public get
|
|
53
|
-
if (!this.
|
|
52
|
+
public get msgSender(): Address {
|
|
53
|
+
if (!this._msgSender) {
|
|
54
54
|
throw this.error('Caller is required');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
return this.
|
|
57
|
+
return this._msgSender as Address;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private _timestamp: u64 = 0;
|
|
@@ -124,8 +124,8 @@ export class BlockchainEnvironment {
|
|
|
124
124
|
public setEnvironment(data: Uint8Array): void {
|
|
125
125
|
const reader: BytesReader = new BytesReader(data);
|
|
126
126
|
|
|
127
|
-
this.
|
|
128
|
-
this.
|
|
127
|
+
this._msgSender = reader.readAddress();
|
|
128
|
+
this._txOrigin = reader.readAddress(); // "leftmost thing in the call chain"
|
|
129
129
|
this.currentBlock = reader.readU256();
|
|
130
130
|
|
|
131
131
|
this._owner = reader.readAddress();
|
|
@@ -137,7 +137,7 @@ export class BlockchainEnvironment {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
|
|
140
|
-
if (destinationContract === this.
|
|
140
|
+
if (destinationContract === this._contractAddress) {
|
|
141
141
|
throw this.error('Cannot call self');
|
|
142
142
|
}
|
|
143
143
|
|