@btc-vision/btc-runtime 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +62 -0
- package/README.md +34 -0
- package/package.json +46 -0
- package/runtime/buffer/BytesReader.ts +193 -0
- package/runtime/buffer/BytesWriter.ts +322 -0
- package/runtime/contracts/OP_20.ts +377 -0
- package/runtime/contracts/OP_NET.ts +77 -0
- package/runtime/contracts/interfaces/IOP_20.ts +25 -0
- package/runtime/env/BTCEnvironment.ts +372 -0
- package/runtime/env/global.ts +18 -0
- package/runtime/env/index.ts +3 -0
- package/runtime/events/NetEvent.ts +27 -0
- package/runtime/events/predefined/ApproveEvent.ts +16 -0
- package/runtime/events/predefined/BurnEvent.ts +13 -0
- package/runtime/events/predefined/ClaimEvent.ts +13 -0
- package/runtime/events/predefined/MintEvent.ts +15 -0
- package/runtime/events/predefined/StakeEvent.ts +13 -0
- package/runtime/events/predefined/TransferEvent.ts +16 -0
- package/runtime/events/predefined/UnstakeEvent.ts +13 -0
- package/runtime/events/predefined/index.ts +7 -0
- package/runtime/exports/index.ts +57 -0
- package/runtime/generic/Map.ts +55 -0
- package/runtime/index.ts +45 -0
- package/runtime/interfaces/IBTC.ts +6 -0
- package/runtime/lang/Definitions.ts +1 -0
- package/runtime/math/abi.ts +37 -0
- package/runtime/math/bytes.ts +34 -0
- package/runtime/math/cyrb53.ts +46 -0
- package/runtime/math/rnd.ts +51 -0
- package/runtime/math/sha256.ts +270 -0
- package/runtime/memory/AddressMemoryMap.ts +64 -0
- package/runtime/memory/KeyMerger.ts +72 -0
- package/runtime/memory/MemorySlot.ts +1 -0
- package/runtime/memory/MemorySlotPointer.ts +3 -0
- package/runtime/memory/MultiAddressMemoryMap.ts +76 -0
- package/runtime/storage/StoredU256.ts +320 -0
- package/runtime/types/Address.ts +5 -0
- package/runtime/types/Revert.ts +5 -0
- package/runtime/types/SafeMath.ts +137 -0
- package/runtime/types/index.ts +8 -0
- package/runtime/universal/ABIRegistry.ts +72 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { IOP_20 } from './interfaces/IOP_20';
|
|
2
|
+
import { u256 } from 'as-bignum/assembly';
|
|
3
|
+
import { Address } from '../types/Address';
|
|
4
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
5
|
+
import { Calldata } from '../universal/ABIRegistry';
|
|
6
|
+
import { OP_NET } from './OP_NET';
|
|
7
|
+
import { AddressMemoryMap } from '../memory/AddressMemoryMap';
|
|
8
|
+
import { Revert } from '../types/Revert';
|
|
9
|
+
import { SafeMath } from '../types/SafeMath';
|
|
10
|
+
import { Blockchain } from '../env';
|
|
11
|
+
import { MemorySlotData } from '../memory/MemorySlot';
|
|
12
|
+
import { encodeSelector, Selector } from '../math/abi';
|
|
13
|
+
import { MultiAddressMemoryMap } from '../memory/MultiAddressMemoryMap';
|
|
14
|
+
import { StoredU256 } from '../storage/StoredU256';
|
|
15
|
+
import { ApproveEvent, BurnEvent, MintEvent, TransferEvent } from '../events/predefined';
|
|
16
|
+
|
|
17
|
+
const allowanceSelector = encodeSelector('allowance');
|
|
18
|
+
const approveSelector = encodeSelector('approve');
|
|
19
|
+
const balanceOfSelector = encodeSelector('balanceOf');
|
|
20
|
+
const burnSelector = encodeSelector('burn');
|
|
21
|
+
const mintSelector = encodeSelector('mint');
|
|
22
|
+
const transferSelector = encodeSelector('transfer');
|
|
23
|
+
const transferFromSelector = encodeSelector('transferFrom');
|
|
24
|
+
|
|
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
|
+
protected readonly allowanceMap: MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>;
|
|
32
|
+
protected readonly balanceOfMap: AddressMemoryMap<Address, MemorySlotData<u256>>;
|
|
33
|
+
|
|
34
|
+
protected constructor(public readonly maxSupply: u256) {
|
|
35
|
+
super();
|
|
36
|
+
|
|
37
|
+
this.allowanceMap = new MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>(
|
|
38
|
+
Blockchain.nextPointer,
|
|
39
|
+
Blockchain.contractAddress,
|
|
40
|
+
u256.Zero,
|
|
41
|
+
);
|
|
42
|
+
this.balanceOfMap = new AddressMemoryMap<Address, MemorySlotData<u256>>(
|
|
43
|
+
Blockchain.nextPointer,
|
|
44
|
+
Blockchain.contractAddress,
|
|
45
|
+
u256.Zero,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const supplyPointer = Blockchain.nextPointer;
|
|
49
|
+
const supply: u256 = Blockchain.getStorageAt(
|
|
50
|
+
Blockchain.contractAddress,
|
|
51
|
+
supplyPointer,
|
|
52
|
+
u256.Zero,
|
|
53
|
+
u256.Zero,
|
|
54
|
+
);
|
|
55
|
+
this._totalSupply = new StoredU256(
|
|
56
|
+
Blockchain.contractAddress,
|
|
57
|
+
supplyPointer,
|
|
58
|
+
u256.Zero,
|
|
59
|
+
supply,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public _totalSupply: StoredU256;
|
|
64
|
+
|
|
65
|
+
public get totalSupply(): u256 {
|
|
66
|
+
return this._totalSupply.value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** METHODS */
|
|
70
|
+
public allowance(callData: Calldata): BytesWriter {
|
|
71
|
+
const response = new BytesWriter();
|
|
72
|
+
|
|
73
|
+
const resp = this._allowance(callData.readAddress(), callData.readAddress());
|
|
74
|
+
response.writeU256(resp);
|
|
75
|
+
|
|
76
|
+
return response;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public approve(callData: Calldata): BytesWriter {
|
|
80
|
+
const response = new BytesWriter();
|
|
81
|
+
|
|
82
|
+
const spender: Address = callData.readAddress();
|
|
83
|
+
const value = callData.readU256();
|
|
84
|
+
|
|
85
|
+
const resp = this._approve(spender, value);
|
|
86
|
+
response.writeBoolean(resp);
|
|
87
|
+
|
|
88
|
+
this.createApproveEvent(Blockchain.callee(), spender, value);
|
|
89
|
+
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public balanceOf(callData: Calldata): BytesWriter {
|
|
94
|
+
const response = new BytesWriter();
|
|
95
|
+
const address: Address = callData.readAddress();
|
|
96
|
+
const resp = this._balanceOf(address);
|
|
97
|
+
|
|
98
|
+
response.writeU256(resp);
|
|
99
|
+
|
|
100
|
+
return response;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public burn(callData: Calldata): BytesWriter {
|
|
104
|
+
const response = new BytesWriter();
|
|
105
|
+
const resp = this._burn(callData.readU256());
|
|
106
|
+
response.writeBoolean(resp);
|
|
107
|
+
|
|
108
|
+
return response;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public mint(callData: Calldata): BytesWriter {
|
|
112
|
+
const response = new BytesWriter();
|
|
113
|
+
const resp = this._mint(callData.readAddress(), callData.readU256());
|
|
114
|
+
|
|
115
|
+
response.writeBoolean(resp);
|
|
116
|
+
|
|
117
|
+
return response;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public transfer(callData: Calldata): BytesWriter {
|
|
121
|
+
const response = new BytesWriter();
|
|
122
|
+
const resp = this._transfer(callData.readAddress(), callData.readU256());
|
|
123
|
+
|
|
124
|
+
response.writeBoolean(resp);
|
|
125
|
+
|
|
126
|
+
return response;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public transferFrom(callData: Calldata): BytesWriter {
|
|
130
|
+
const response = new BytesWriter();
|
|
131
|
+
const resp = this._transferFrom(
|
|
132
|
+
callData.readAddress(),
|
|
133
|
+
callData.readAddress(),
|
|
134
|
+
callData.readU256(),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
response.writeBoolean(resp);
|
|
138
|
+
|
|
139
|
+
return response;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public callMethod(method: Selector, calldata: Calldata): BytesWriter {
|
|
143
|
+
switch (method) {
|
|
144
|
+
case allowanceSelector:
|
|
145
|
+
return this.allowance(calldata);
|
|
146
|
+
case approveSelector:
|
|
147
|
+
return this.approve(calldata);
|
|
148
|
+
case balanceOfSelector:
|
|
149
|
+
return this.balanceOf(calldata);
|
|
150
|
+
case burnSelector:
|
|
151
|
+
return this.burn(calldata);
|
|
152
|
+
case mintSelector:
|
|
153
|
+
return this.mint(calldata);
|
|
154
|
+
case transferSelector:
|
|
155
|
+
return this.transfer(calldata);
|
|
156
|
+
case transferFromSelector:
|
|
157
|
+
return this.transferFrom(calldata);
|
|
158
|
+
default:
|
|
159
|
+
return super.callMethod(method, calldata);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public callView(method: Selector): BytesWriter {
|
|
164
|
+
const response = new BytesWriter();
|
|
165
|
+
|
|
166
|
+
switch (method) {
|
|
167
|
+
case encodeSelector('decimals'):
|
|
168
|
+
response.writeU8(this.decimals);
|
|
169
|
+
break;
|
|
170
|
+
case encodeSelector('name'):
|
|
171
|
+
response.writeString(this.name);
|
|
172
|
+
break;
|
|
173
|
+
case encodeSelector('symbol'):
|
|
174
|
+
response.writeString(this.symbol);
|
|
175
|
+
break;
|
|
176
|
+
case encodeSelector('totalSupply'):
|
|
177
|
+
response.writeU256(this.totalSupply);
|
|
178
|
+
break;
|
|
179
|
+
case encodeSelector('maximumSupply'):
|
|
180
|
+
response.writeU256(this.maxSupply);
|
|
181
|
+
break;
|
|
182
|
+
default:
|
|
183
|
+
return super.callView(method);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return response;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** REDEFINED METHODS */
|
|
190
|
+
protected _allowance(owner: string, spender: string): u256 {
|
|
191
|
+
const senderMap = this.allowanceMap.get(owner);
|
|
192
|
+
if (!senderMap.has(spender)) throw new Revert();
|
|
193
|
+
|
|
194
|
+
return senderMap.get(spender);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected _approve(spender: string, value: u256): boolean {
|
|
198
|
+
const callee = Blockchain.callee();
|
|
199
|
+
|
|
200
|
+
const senderMap = this.allowanceMap.get(callee);
|
|
201
|
+
senderMap.set(spender, value);
|
|
202
|
+
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected _balanceOf(owner: Address): u256 {
|
|
207
|
+
const hasAddress = this.balanceOfMap.has(owner);
|
|
208
|
+
if (!hasAddress) return u256.Zero;
|
|
209
|
+
|
|
210
|
+
return this.balanceOfMap.get(owner);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
protected _burn(value: u256): boolean {
|
|
214
|
+
if (u256.eq(value, u256.Zero)) {
|
|
215
|
+
throw new Revert(`No tokens`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const callee = Blockchain.callee();
|
|
219
|
+
const caller = Blockchain.caller();
|
|
220
|
+
|
|
221
|
+
this.onlyOwner(callee); // only indexers can burn tokens
|
|
222
|
+
|
|
223
|
+
if (this._totalSupply.value < value) throw new Revert(`Insufficient total supply.`);
|
|
224
|
+
if (!this.balanceOfMap.has(caller)) throw new Revert('Empty');
|
|
225
|
+
|
|
226
|
+
const balance: u256 = this.balanceOfMap.get(caller);
|
|
227
|
+
if (balance < value) throw new Revert(`Insufficient balance`);
|
|
228
|
+
|
|
229
|
+
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
230
|
+
this.balanceOfMap.set(caller, newBalance);
|
|
231
|
+
|
|
232
|
+
// @ts-ignore
|
|
233
|
+
this._totalSupply -= value;
|
|
234
|
+
|
|
235
|
+
this.createBurnEvent(value);
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
protected _mint(to: Address, value: u256): boolean {
|
|
240
|
+
const callee = Blockchain.callee();
|
|
241
|
+
const caller = Blockchain.caller();
|
|
242
|
+
|
|
243
|
+
this.onlyOwner(callee);
|
|
244
|
+
|
|
245
|
+
if (caller !== callee) throw new Revert(`callee != caller`);
|
|
246
|
+
if (callee !== this.owner) throw new Revert('Only indexers can mint tokens');
|
|
247
|
+
|
|
248
|
+
if (!this.balanceOfMap.has(to)) {
|
|
249
|
+
this.balanceOfMap.set(to, value);
|
|
250
|
+
} else {
|
|
251
|
+
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
252
|
+
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
253
|
+
|
|
254
|
+
this.balanceOfMap.set(to, newToBalance);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// @ts-ignore
|
|
258
|
+
this._totalSupply += value;
|
|
259
|
+
|
|
260
|
+
if (this._totalSupply.value > this.maxSupply) throw new Revert('Max supply reached');
|
|
261
|
+
|
|
262
|
+
this.createMintEvent(to, value);
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected _transfer(to: string, value: u256): boolean {
|
|
267
|
+
const caller = Blockchain.callee();
|
|
268
|
+
|
|
269
|
+
if (!this.balanceOfMap.has(caller)) throw new Revert();
|
|
270
|
+
if (this.isSelf(caller)) throw new Revert('Can not transfer from self account');
|
|
271
|
+
|
|
272
|
+
if (caller === to) {
|
|
273
|
+
throw new Revert(`Cannot transfer to self`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (u256.eq(value, u256.Zero)) {
|
|
277
|
+
throw new Revert(`Cannot transfer 0 tokens`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const balance: u256 = this.balanceOfMap.get(caller);
|
|
281
|
+
if (balance < value) throw new Revert(`Insufficient balance`);
|
|
282
|
+
|
|
283
|
+
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
284
|
+
this.balanceOfMap.set(caller, newBalance);
|
|
285
|
+
|
|
286
|
+
if (!this.balanceOfMap.has(to)) {
|
|
287
|
+
this.balanceOfMap.set(to, value);
|
|
288
|
+
} else {
|
|
289
|
+
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
290
|
+
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
291
|
+
|
|
292
|
+
this.balanceOfMap.set(to, newToBalance);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
this.createTransferEvent(caller, to, value);
|
|
296
|
+
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@unsafe
|
|
301
|
+
protected _unsafeTransferFrom(from: Address, to: Address, value: u256): boolean {
|
|
302
|
+
const balance: u256 = this.balanceOfMap.get(from);
|
|
303
|
+
if (balance < value)
|
|
304
|
+
throw new Revert(
|
|
305
|
+
`TransferFrom insufficient balance of ${from} is ${balance} and value is ${value}`,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
309
|
+
|
|
310
|
+
this.balanceOfMap.set(from, newBalance);
|
|
311
|
+
|
|
312
|
+
if (!this.balanceOfMap.has(to)) {
|
|
313
|
+
this.balanceOfMap.set(to, value);
|
|
314
|
+
} else {
|
|
315
|
+
const toBalance: u256 = this.balanceOfMap.get(to);
|
|
316
|
+
const newToBalance: u256 = SafeMath.add(toBalance, value);
|
|
317
|
+
|
|
318
|
+
this.balanceOfMap.set(to, newToBalance);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.createTransferEvent(from, to, value);
|
|
322
|
+
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
protected _transferFrom(from: Address, to: Address, value: u256): boolean {
|
|
327
|
+
if (!this.allowanceMap.has(from)) throw new Revert();
|
|
328
|
+
|
|
329
|
+
const spender = Blockchain.callee();
|
|
330
|
+
if (Blockchain.caller() !== from) {
|
|
331
|
+
throw new Revert('Not caller.');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const fromAllowanceMap = this.allowanceMap.get(from);
|
|
335
|
+
const allowed: u256 = fromAllowanceMap.get(spender);
|
|
336
|
+
if (allowed < value) throw new Revert(`Insufficient allowance`);
|
|
337
|
+
|
|
338
|
+
if (this.isSelf(spender)) throw new Revert('Can not transfer from self account');
|
|
339
|
+
|
|
340
|
+
const senderMap = this.allowanceMap.get(from);
|
|
341
|
+
if (!senderMap.has(spender)) throw new Revert();
|
|
342
|
+
|
|
343
|
+
const allowance: u256 = senderMap.get(spender);
|
|
344
|
+
if (allowance < value) throw new Revert(`Insufficient allowance`);
|
|
345
|
+
|
|
346
|
+
const newAllowance: u256 = SafeMath.sub(allowance, value);
|
|
347
|
+
senderMap.set(spender, newAllowance);
|
|
348
|
+
|
|
349
|
+
this._unsafeTransferFrom(from, to, value);
|
|
350
|
+
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
protected createBurnEvent(value: u256): void {
|
|
355
|
+
const burnEvent = new BurnEvent(value);
|
|
356
|
+
|
|
357
|
+
this.emitEvent(burnEvent);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private createApproveEvent(owner: Address, spender: Address, value: u256): void {
|
|
361
|
+
const approveEvent = new ApproveEvent(owner, spender, value);
|
|
362
|
+
|
|
363
|
+
this.emitEvent(approveEvent);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private createMintEvent(owner: Address, value: u256): void {
|
|
367
|
+
const mintEvent = new MintEvent(owner, value);
|
|
368
|
+
|
|
369
|
+
this.emitEvent(mintEvent);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private createTransferEvent(from: Address, to: Address, value: u256): void {
|
|
373
|
+
const transferEvent = new TransferEvent(from, to, value);
|
|
374
|
+
|
|
375
|
+
this.emitEvent(transferEvent);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { IBTC } from '../interfaces/IBTC';
|
|
2
|
+
import { Address } from '../types/Address';
|
|
3
|
+
import { Blockchain } from '../env';
|
|
4
|
+
import { Calldata } from '../universal/ABIRegistry';
|
|
5
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
6
|
+
import { encodeSelector, Selector } from '../math/abi';
|
|
7
|
+
import { Revert } from '../types/Revert';
|
|
8
|
+
import { MAX_EVENT_DATA_SIZE, NetEvent } from '../events/NetEvent';
|
|
9
|
+
|
|
10
|
+
const isAddressOwnerSelector = encodeSelector('isAddressOwner');
|
|
11
|
+
const addressSelector = encodeSelector('address');
|
|
12
|
+
const ownerSelector = encodeSelector('owner');
|
|
13
|
+
|
|
14
|
+
export class OP_NET implements IBTC {
|
|
15
|
+
constructor() {}
|
|
16
|
+
|
|
17
|
+
public get address(): string {
|
|
18
|
+
return Blockchain.contractAddress;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public get owner(): string {
|
|
22
|
+
return Blockchain.owner;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public callMethod(method: Selector, calldata: Calldata): BytesWriter {
|
|
26
|
+
switch (method) {
|
|
27
|
+
case isAddressOwnerSelector:
|
|
28
|
+
return this.isAddressOwner(calldata);
|
|
29
|
+
default:
|
|
30
|
+
throw new Revert('Method not found');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public callView(method: Selector): BytesWriter {
|
|
35
|
+
const response = new BytesWriter();
|
|
36
|
+
|
|
37
|
+
switch (method) {
|
|
38
|
+
case addressSelector:
|
|
39
|
+
response.writeAddress(this.address);
|
|
40
|
+
break;
|
|
41
|
+
case ownerSelector:
|
|
42
|
+
response.writeAddress(this.owner);
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
throw new Revert('Method not found');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected emitEvent(event: NetEvent): void {
|
|
52
|
+
if (event.length > MAX_EVENT_DATA_SIZE) {
|
|
53
|
+
throw new Error('Event data length exceeds maximum length.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Blockchain.addEvent(event);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected isSelf(address: Address): boolean {
|
|
60
|
+
return this.address === address;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
protected onlyOwner(caller: Address): void {
|
|
64
|
+
if (this.owner !== caller) {
|
|
65
|
+
throw new Revert('Only owner can call this method');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private isAddressOwner(calldata: Calldata): BytesWriter {
|
|
70
|
+
const response = new BytesWriter();
|
|
71
|
+
const owner = calldata.readAddress();
|
|
72
|
+
|
|
73
|
+
response.writeBoolean(this.owner === owner);
|
|
74
|
+
|
|
75
|
+
return response;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BytesWriter } from '../../buffer/BytesWriter';
|
|
2
|
+
import { Calldata } from '../../universal/ABIRegistry';
|
|
3
|
+
import { StoredU256 } from '../../storage/StoredU256';
|
|
4
|
+
|
|
5
|
+
export interface IOP_20 {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly symbol: string;
|
|
8
|
+
|
|
9
|
+
readonly decimals: u8;
|
|
10
|
+
readonly _totalSupply: StoredU256;
|
|
11
|
+
|
|
12
|
+
balanceOf(callData: Calldata): BytesWriter;
|
|
13
|
+
|
|
14
|
+
transfer(callData: Calldata): BytesWriter;
|
|
15
|
+
|
|
16
|
+
transferFrom(callData: Calldata): BytesWriter;
|
|
17
|
+
|
|
18
|
+
approve(callData: Calldata): BytesWriter;
|
|
19
|
+
|
|
20
|
+
allowance(callData: Calldata): BytesWriter;
|
|
21
|
+
|
|
22
|
+
burn(callData: Calldata): BytesWriter;
|
|
23
|
+
|
|
24
|
+
mint(callData: Calldata): BytesWriter;
|
|
25
|
+
}
|