@btc-vision/btc-runtime 1.8.1 → 1.9.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/README.md +57 -79
- package/package.json +8 -8
- package/runtime/buffer/BytesReader.ts +36 -45
- package/runtime/buffer/BytesWriter.ts +60 -20
- package/runtime/contracts/OP20.ts +636 -0
- package/runtime/contracts/OP_NET.ts +3 -3
- package/runtime/contracts/interfaces/IOP20.ts +15 -0
- package/runtime/contracts/interfaces/OP20InitParameters.ts +3 -1
- package/runtime/env/BlockchainEnvironment.ts +28 -7
- package/runtime/env/classes/Transaction.ts +1 -2
- package/runtime/env/global.ts +171 -23
- package/runtime/events/NetEvent.ts +1 -1
- package/runtime/events/predefined/{ApproveEvent.ts → ApprovedEvent.ts} +3 -3
- package/runtime/events/predefined/{MintEvent.ts → BurnedEvent.ts} +5 -6
- package/runtime/events/predefined/{TransferEvent.ts → MintedEvent.ts} +5 -6
- package/runtime/events/predefined/TransferredEvent.ts +18 -0
- package/runtime/events/predefined/index.ts +4 -4
- package/runtime/exports/index.ts +4 -4
- package/runtime/index.ts +13 -3
- package/runtime/math/abi.ts +10 -6
- package/runtime/math/bytes.ts +5 -17
- package/runtime/memory/AddressMemoryMap.ts +4 -5
- package/runtime/memory/KeyMerger.ts +7 -7
- package/runtime/memory/MapOfMap.ts +2 -7
- package/runtime/memory/Nested.ts +6 -8
- package/runtime/nested/PointerManager.ts +1 -1
- package/runtime/nested/codecs/AddressCodec.ts +1 -1
- package/runtime/nested/codecs/BooleanCodec.ts +1 -1
- package/runtime/nested/codecs/Ids.ts +1 -1
- package/runtime/nested/codecs/NumericCodec.ts +1 -1
- package/runtime/nested/codecs/StringCodec.ts +1 -1
- package/runtime/nested/codecs/VariableBytesCodec.ts +3 -3
- package/runtime/nested/storage/StorageMap.ts +3 -3
- package/runtime/nested/storage/StorageSet.ts +2 -2
- package/runtime/plugins/Plugin.ts +5 -7
- package/runtime/script/Bech32.ts +369 -0
- package/runtime/script/BitcoinAddresses.ts +208 -0
- package/runtime/script/BitcoinCodec.ts +395 -0
- package/runtime/script/Networks.ts +94 -0
- package/runtime/script/Opcodes.ts +155 -0
- package/runtime/script/Script.ts +463 -0
- package/runtime/script/ScriptUtils.ts +101 -0
- package/runtime/script/Segwit.ts +185 -0
- package/runtime/script/reader/ScriptReader.ts +247 -0
- package/runtime/secp256k1/ECPoint.ts +6 -12
- package/runtime/shared-libraries/TransferHelper.ts +72 -31
- package/runtime/storage/AdvancedStoredString.ts +1 -1
- package/runtime/storage/StoredAddress.ts +1 -1
- package/runtime/storage/StoredBoolean.ts +2 -4
- package/runtime/storage/StoredString.ts +6 -3
- package/runtime/storage/StoredU256.ts +1 -3
- package/runtime/storage/StoredU32.ts +1 -6
- package/runtime/storage/StoredU64.ts +1 -4
- package/runtime/storage/arrays/StoredBooleanArray.ts +7 -12
- package/runtime/storage/arrays/StoredPackedArray.ts +3 -13
- package/runtime/storage/maps/StoredMapU256.ts +5 -5
- package/runtime/types/Address.ts +49 -39
- package/runtime/types/SafeMath.ts +19 -18
- package/runtime/types/SafeMathI128.ts +14 -13
- package/runtime/utils/hex.ts +41 -19
- package/runtime/utils/index.ts +0 -2
- package/runtime/contracts/DeployableOP_20.ts +0 -415
- package/runtime/contracts/OP_20.ts +0 -9
- package/runtime/contracts/interfaces/IOP_20.ts +0 -19
- package/runtime/events/predefined/BurnEvent.ts +0 -14
- package/runtime/utils/b32.ts +0 -243
- package/runtime/utils/box.ts +0 -134
- package/runtime/utils/encodings.ts +0 -45
- /package/{LICENSE → LICENSE.md} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { i128 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
+
import { Revert } from './Revert';
|
|
2
3
|
|
|
3
4
|
export class SafeMathI128 {
|
|
4
5
|
public static readonly ZERO: i128 = i128.fromI32(0);
|
|
@@ -13,14 +14,14 @@ export class SafeMathI128 {
|
|
|
13
14
|
* Throws if (a + b) overflows or underflows the signed 128-bit range.
|
|
14
15
|
*/
|
|
15
16
|
public static add(a: i128, b: i128): i128 {
|
|
16
|
-
|
|
17
|
+
const c = i128.add(a, b);
|
|
17
18
|
|
|
18
19
|
// Overflow check for 2's complement:
|
|
19
20
|
// If a and b have the same sign, but c differs, overflow occurred.
|
|
20
21
|
// We can detect sign mismatch using ((a ^ c) & (b ^ c)) < 0
|
|
21
22
|
// (i.e., the sign bit is set in that expression).
|
|
22
23
|
if (((a ^ c) & (b ^ c)).isNeg()) {
|
|
23
|
-
throw new
|
|
24
|
+
throw new Revert('SafeMathI128: addition overflow');
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
return c;
|
|
@@ -31,12 +32,12 @@ export class SafeMathI128 {
|
|
|
31
32
|
* Throws if (a - b) overflows or underflows the signed 128-bit range.
|
|
32
33
|
*/
|
|
33
34
|
public static sub(a: i128, b: i128): i128 {
|
|
34
|
-
|
|
35
|
+
const c = i128.sub(a, b);
|
|
35
36
|
|
|
36
37
|
// Subtraction is (a + (-b)). We can do a direct check like:
|
|
37
38
|
// If (a ^ b) & (a ^ c) has sign bit set => overflow.
|
|
38
39
|
if (((a ^ b) & (a ^ c)).isNeg()) {
|
|
39
|
-
throw new
|
|
40
|
+
throw new Revert('SafeMathI128: subtraction overflow');
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
return c;
|
|
@@ -56,7 +57,7 @@ export class SafeMathI128 {
|
|
|
56
57
|
if (b != SafeMathI128.ZERO) {
|
|
57
58
|
let divCheck = i128.div(c, b);
|
|
58
59
|
if (divCheck != a) {
|
|
59
|
-
throw new
|
|
60
|
+
throw new Revert('SafeMathI128: multiplication overflow');
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -65,12 +66,12 @@ export class SafeMathI128 {
|
|
|
65
66
|
|
|
66
67
|
/*public static div(a: i128, b: i128): i128 {
|
|
67
68
|
if (b == SafeMathI128.ZERO) {
|
|
68
|
-
throw new
|
|
69
|
+
throw new Revert('SafeMathI128: division by zero');
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
// Check i128 edge case: MIN / -1 => possible overflow if no corresponding positive.
|
|
72
73
|
if (a == SafeMathI128.MIN && b == SafeMathI128.NEG_ONE) {
|
|
73
|
-
throw new
|
|
74
|
+
throw new Revert('SafeMathI128: division overflow (MIN / -1)');
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
return i128.div(a, b);
|
|
@@ -78,14 +79,14 @@ export class SafeMathI128 {
|
|
|
78
79
|
|
|
79
80
|
/*public static mod(a: i128, b: i128): i128 {
|
|
80
81
|
if (b == SafeMathI128.ZERO) {
|
|
81
|
-
throw new
|
|
82
|
+
throw new Revert('SafeMathI128: modulo by zero');
|
|
82
83
|
}
|
|
83
84
|
// Similar edge case as division:
|
|
84
85
|
if (a == SafeMathI128.MIN && b == SafeMathI128.NEG_ONE) {
|
|
85
86
|
// Some implementations might treat MIN % -1 == 0,
|
|
86
87
|
// but if the library doesn't, you may handle it similarly to division.
|
|
87
88
|
// We'll assume we throw to be safe:
|
|
88
|
-
throw new
|
|
89
|
+
throw new Revert('SafeMathI128: modulo overflow (MIN % -1)');
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
// Use i128.rem, i128.mod, or the operator as appropriate.
|
|
@@ -97,7 +98,7 @@ export class SafeMathI128 {
|
|
|
97
98
|
*/
|
|
98
99
|
public static inc(value: i128): i128 {
|
|
99
100
|
if (value == SafeMathI128.MAX) {
|
|
100
|
-
throw new
|
|
101
|
+
throw new Revert('SafeMathI128: inc overflow');
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
return SafeMathI128.add(value, SafeMathI128.ONE);
|
|
@@ -108,7 +109,7 @@ export class SafeMathI128 {
|
|
|
108
109
|
*/
|
|
109
110
|
public static dec(value: i128): i128 {
|
|
110
111
|
if (value == SafeMathI128.MIN) {
|
|
111
|
-
throw new
|
|
112
|
+
throw new Revert('SafeMathI128: dec underflow');
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
return SafeMathI128.sub(value, SafeMathI128.ONE);
|
|
@@ -121,7 +122,7 @@ export class SafeMathI128 {
|
|
|
121
122
|
if (x.isNeg()) {
|
|
122
123
|
// If x == MIN, -x can overflow.
|
|
123
124
|
if (x == SafeMathI128.MIN) {
|
|
124
|
-
throw new
|
|
125
|
+
throw new Revert('SafeMathI128: abs overflow on MIN');
|
|
125
126
|
}
|
|
126
127
|
return x.neg();
|
|
127
128
|
}
|
|
@@ -133,7 +134,7 @@ export class SafeMathI128 {
|
|
|
133
134
|
*/
|
|
134
135
|
public static neg(x: i128): i128 {
|
|
135
136
|
if (x == SafeMathI128.MIN) {
|
|
136
|
-
throw new
|
|
137
|
+
throw new Revert('SafeMathI128: neg overflow on MIN');
|
|
137
138
|
}
|
|
138
139
|
return x.neg();
|
|
139
140
|
}
|
package/runtime/utils/hex.ts
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
import { Revert } from '../types/Revert';
|
|
2
|
+
|
|
3
|
+
function hexCharToValue(char: u8): u8 {
|
|
4
|
+
if (char >= 48 && char <= 57) {
|
|
5
|
+
// '0' to '9'
|
|
6
|
+
return char - 48;
|
|
7
|
+
} else if (char >= 97 && char <= 102) {
|
|
8
|
+
// 'a' to 'f'
|
|
9
|
+
return char - 97 + 10;
|
|
10
|
+
} else if (char >= 65 && char <= 70) {
|
|
11
|
+
// 'A' to 'F'
|
|
12
|
+
return char - 65 + 10;
|
|
13
|
+
} else {
|
|
14
|
+
throw new Revert('Invalid hex character: ' + String.fromCharCode(char));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function decodeHexArray(hex: string): u8[] {
|
|
19
|
+
// Remove 0x prefix if present
|
|
20
|
+
if (hex.startsWith('0x') || hex.startsWith('0X')) {
|
|
21
|
+
hex = hex.substring(2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate length is even
|
|
25
|
+
if (hex.length % 2 !== 0) {
|
|
26
|
+
throw new Revert('Hex string must have even length');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = new Array<u8>(hex.length / 2);
|
|
30
|
+
const hexBytes = String.UTF8.encode(hex);
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
33
|
+
const high = hexCharToValue(load<u8>(changetype<usize>(hexBytes) + i));
|
|
34
|
+
const low = hexCharToValue(load<u8>(changetype<usize>(hexBytes) + i + 1));
|
|
35
|
+
result[i / 2] = (high << 4) | low;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
1
41
|
const hexLookupTable: StaticArray<u8> = [
|
|
2
42
|
48, 48, 48, 49, 48, 50, 48, 51, 48, 52, 48, 53, 48, 54, 48, 55, 48, 56, 48, 57, 48, 97, 48, 98,
|
|
3
43
|
48, 99, 48, 100, 48, 101, 48, 102, 49, 48, 49, 49, 49, 50, 49, 51, 49, 52, 49, 53, 49, 54, 49,
|
|
@@ -26,7 +66,7 @@ const hexLookupTable: StaticArray<u8> = [
|
|
|
26
66
|
|
|
27
67
|
export function encodeHexUTF8(start: usize, len: usize): ArrayBuffer {
|
|
28
68
|
const result = new ArrayBuffer(2 + <i32>len * 2);
|
|
29
|
-
store<u16>(changetype<usize>(result), <u16>0x7830);
|
|
69
|
+
store<u16>(changetype<usize>(result), <u16>0x7830); // Stores "0x" prefix
|
|
30
70
|
for (let i: usize = 0; i < len; i++) {
|
|
31
71
|
store<u16>(
|
|
32
72
|
2 + changetype<usize>(result) + i * 2,
|
|
@@ -43,21 +83,3 @@ export function encodeHex(start: usize, len: usize): string {
|
|
|
43
83
|
export function encodeHexFromBuffer(data: ArrayBuffer): string {
|
|
44
84
|
return encodeHex(changetype<usize>(data), data.byteLength);
|
|
45
85
|
}
|
|
46
|
-
|
|
47
|
-
export function decodeHex(hex: string): ArrayBuffer {
|
|
48
|
-
const result = new ArrayBuffer(hex.length / 2);
|
|
49
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
50
|
-
store<u8>(changetype<usize>(result) + i / 2, <u8>parseInt(hex.substring(i, i + 2), 16));
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function decodeHexArray(hex: string): u8[] {
|
|
56
|
-
const result = new Array<u8>(hex.length / 2);
|
|
57
|
-
|
|
58
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
59
|
-
result[i / 2] = <u8>parseInt(hex.substring(i, i + 2), 16);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return result;
|
|
63
|
-
}
|
package/runtime/utils/index.ts
CHANGED
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
-
|
|
3
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
|
-
import { Blockchain } from '../env';
|
|
5
|
-
import { ApproveEvent, BurnEvent, MintEvent, TransferEvent } from '../events/predefined';
|
|
6
|
-
import { StoredString } from '../storage/StoredString';
|
|
7
|
-
import { StoredU256 } from '../storage/StoredU256';
|
|
8
|
-
import { Address } from '../types/Address';
|
|
9
|
-
import { Revert } from '../types/Revert';
|
|
10
|
-
import { SafeMath } from '../types/SafeMath';
|
|
11
|
-
import { sha256 } from '../env/global';
|
|
12
|
-
import { EMPTY_POINTER } from '../math/bytes';
|
|
13
|
-
import { AddressMemoryMap } from '../memory/AddressMemoryMap';
|
|
14
|
-
import { MapOfMap } from '../memory/MapOfMap';
|
|
15
|
-
import { Calldata } from '../types';
|
|
16
|
-
import { ADDRESS_BYTE_LENGTH, BOOLEAN_BYTE_LENGTH, U256_BYTE_LENGTH } from '../utils';
|
|
17
|
-
import { IOP_20 } from './interfaces/IOP_20';
|
|
18
|
-
import { OP20InitParameters } from './interfaces/OP20InitParameters';
|
|
19
|
-
import { OP_NET } from './OP_NET';
|
|
20
|
-
|
|
21
|
-
const nonceMapPointer: u16 = Blockchain.nextPointer;
|
|
22
|
-
const maxSupplyPointer: u16 = Blockchain.nextPointer;
|
|
23
|
-
const decimalsPointer: u16 = Blockchain.nextPointer;
|
|
24
|
-
const stringPointer: u16 = Blockchain.nextPointer;
|
|
25
|
-
const totalSupplyPointer: u16 = Blockchain.nextPointer;
|
|
26
|
-
const allowanceMapPointer: u16 = Blockchain.nextPointer;
|
|
27
|
-
const balanceOfMapPointer: u16 = Blockchain.nextPointer;
|
|
28
|
-
|
|
29
|
-
export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
30
|
-
protected readonly allowanceMap: MapOfMap<u256>;
|
|
31
|
-
protected readonly balanceOfMap: AddressMemoryMap;
|
|
32
|
-
|
|
33
|
-
protected readonly _maxSupply: StoredU256;
|
|
34
|
-
protected readonly _decimals: StoredU256;
|
|
35
|
-
protected readonly _name: StoredString;
|
|
36
|
-
protected readonly _symbol: StoredString;
|
|
37
|
-
protected readonly _nonceMap: AddressMemoryMap;
|
|
38
|
-
|
|
39
|
-
public constructor(params: OP20InitParameters | null = null) {
|
|
40
|
-
super();
|
|
41
|
-
|
|
42
|
-
this.allowanceMap = new MapOfMap<u256>(allowanceMapPointer);
|
|
43
|
-
this.balanceOfMap = new AddressMemoryMap(balanceOfMapPointer);
|
|
44
|
-
this._nonceMap = new AddressMemoryMap(nonceMapPointer);
|
|
45
|
-
|
|
46
|
-
this._totalSupply = new StoredU256(totalSupplyPointer, EMPTY_POINTER);
|
|
47
|
-
this._maxSupply = new StoredU256(maxSupplyPointer, EMPTY_POINTER);
|
|
48
|
-
this._decimals = new StoredU256(decimalsPointer, EMPTY_POINTER);
|
|
49
|
-
this._name = new StoredString(stringPointer, 0);
|
|
50
|
-
this._symbol = new StoredString(stringPointer, 1);
|
|
51
|
-
|
|
52
|
-
if (params && this._maxSupply.value.isZero()) {
|
|
53
|
-
this.instantiate(params, true);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Intentionally public for inherited classes */
|
|
58
|
-
public _totalSupply: StoredU256;
|
|
59
|
-
|
|
60
|
-
public get totalSupply(): u256 {
|
|
61
|
-
return this._totalSupply.value;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public get maxSupply(): u256 {
|
|
65
|
-
if (!this._maxSupply) throw new Revert('Max supply not set');
|
|
66
|
-
return this._maxSupply.value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public get decimals(): u8 {
|
|
70
|
-
if (!this._decimals) throw new Revert('Decimals not set');
|
|
71
|
-
return u8(this._decimals.value.toU32());
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
public get name(): string {
|
|
75
|
-
if (!this._name) throw new Revert('Name not set');
|
|
76
|
-
return this._name.value;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public get symbol(): string {
|
|
80
|
-
if (!this._symbol) throw new Revert('Symbol not set');
|
|
81
|
-
return this._symbol.value;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public instantiate(
|
|
85
|
-
params: OP20InitParameters,
|
|
86
|
-
skipDeployerVerification: boolean = false,
|
|
87
|
-
): void {
|
|
88
|
-
if (!this._maxSupply.value.isZero()) throw new Revert('Already initialized');
|
|
89
|
-
if (!skipDeployerVerification) this.onlyDeployer(Blockchain.tx.sender);
|
|
90
|
-
if (params.decimals > 32) throw new Revert('Decimals > 32');
|
|
91
|
-
|
|
92
|
-
this._maxSupply.value = params.maxSupply;
|
|
93
|
-
this._decimals.value = u256.fromU32(u32(params.decimals));
|
|
94
|
-
this._name.value = params.name;
|
|
95
|
-
this._symbol.value = params.symbol;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@method('decimals')
|
|
99
|
-
@returns({ name: 'decimals', type: ABIDataTypes.UINT8 })
|
|
100
|
-
public fn_decimals(_: Calldata): BytesWriter {
|
|
101
|
-
const w = new BytesWriter(1);
|
|
102
|
-
w.writeU8(this.decimals);
|
|
103
|
-
return w;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@method('name')
|
|
107
|
-
@returns({ name: 'name', type: ABIDataTypes.STRING })
|
|
108
|
-
public fn_name(_: Calldata): BytesWriter {
|
|
109
|
-
const w = new BytesWriter(String.UTF8.byteLength(this.name) + 4);
|
|
110
|
-
w.writeStringWithLength(this.name);
|
|
111
|
-
return w;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@method('symbol')
|
|
115
|
-
@returns({ name: 'symbol', type: ABIDataTypes.STRING })
|
|
116
|
-
public fn_symbol(_: Calldata): BytesWriter {
|
|
117
|
-
const w = new BytesWriter(String.UTF8.byteLength(this.symbol) + 4);
|
|
118
|
-
w.writeStringWithLength(this.symbol);
|
|
119
|
-
return w;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@method('totalSupply')
|
|
123
|
-
@returns({ name: 'totalSupply', type: ABIDataTypes.UINT256 })
|
|
124
|
-
public fn_totalSupply(_: Calldata): BytesWriter {
|
|
125
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
126
|
-
w.writeU256(this.totalSupply);
|
|
127
|
-
return w;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@method('maximumSupply')
|
|
131
|
-
@returns({ name: 'maximumSupply', type: ABIDataTypes.UINT256 })
|
|
132
|
-
public fn_maximumSupply(_: Calldata): BytesWriter {
|
|
133
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
134
|
-
w.writeU256(this.maxSupply);
|
|
135
|
-
return w;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
@method(
|
|
139
|
-
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
140
|
-
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
141
|
-
)
|
|
142
|
-
@returns({ name: 'remaining', type: ABIDataTypes.UINT256 })
|
|
143
|
-
public allowance(calldata: Calldata): BytesWriter {
|
|
144
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
145
|
-
const rem = this._allowance(calldata.readAddress(), calldata.readAddress());
|
|
146
|
-
w.writeU256(rem);
|
|
147
|
-
return w;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@method(
|
|
151
|
-
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
152
|
-
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
153
|
-
)
|
|
154
|
-
@returns({ name: 'success', type: ABIDataTypes.BOOL })
|
|
155
|
-
@emit('Approve')
|
|
156
|
-
public approve(calldata: Calldata): BytesWriter {
|
|
157
|
-
const ok = this._approve(Blockchain.tx.sender, calldata.readAddress(), calldata.readU256());
|
|
158
|
-
const w = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
159
|
-
w.writeBoolean(ok);
|
|
160
|
-
return w;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@method(
|
|
164
|
-
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
165
|
-
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
166
|
-
{ name: 'nonce', type: ABIDataTypes.UINT256 },
|
|
167
|
-
{ name: 'sig', type: ABIDataTypes.BYTES },
|
|
168
|
-
)
|
|
169
|
-
@returns({ name: 'success', type: ABIDataTypes.BOOL })
|
|
170
|
-
@emit('Approve')
|
|
171
|
-
public approveFrom(calldata: Calldata): BytesWriter {
|
|
172
|
-
if (Blockchain.tx.origin == Blockchain.tx.sender) {
|
|
173
|
-
throw new Revert('Direct owner approval – use approve()');
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const owner: Address = Blockchain.tx.origin;
|
|
177
|
-
const spender: Address = calldata.readAddress();
|
|
178
|
-
const value: u256 = calldata.readU256();
|
|
179
|
-
const nonce: u256 = calldata.readU256();
|
|
180
|
-
const sig = calldata.readBytesWithLength();
|
|
181
|
-
if (sig.length !== 64) throw new Revert('Invalid signature length');
|
|
182
|
-
|
|
183
|
-
const ok = this._approveFrom(owner, spender, value, nonce, sig);
|
|
184
|
-
const w = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
185
|
-
w.writeBoolean(ok);
|
|
186
|
-
return w;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
190
|
-
@returns({ name: 'nonce', type: ABIDataTypes.UINT256 })
|
|
191
|
-
public nonceOf(calldata: Calldata): BytesWriter {
|
|
192
|
-
const current = this._nonceMap.get(calldata.readAddress());
|
|
193
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
194
|
-
w.writeU256(current);
|
|
195
|
-
return w;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
199
|
-
@returns({ name: 'balance', type: ABIDataTypes.UINT256 })
|
|
200
|
-
public balanceOf(calldata: Calldata): BytesWriter {
|
|
201
|
-
const bal = this._balanceOf(calldata.readAddress());
|
|
202
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
203
|
-
w.writeU256(bal);
|
|
204
|
-
return w;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@method({ name: 'amount', type: ABIDataTypes.UINT256 })
|
|
208
|
-
@returns({ name: 'success', type: ABIDataTypes.BOOL })
|
|
209
|
-
@emit('Burn')
|
|
210
|
-
public burn(calldata: Calldata): BytesWriter {
|
|
211
|
-
const ok = this._burn(calldata.readU256());
|
|
212
|
-
const w = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
213
|
-
w.writeBoolean(ok);
|
|
214
|
-
return w;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
@method(
|
|
218
|
-
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
219
|
-
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
220
|
-
)
|
|
221
|
-
@returns({ name: 'success', type: ABIDataTypes.BOOL })
|
|
222
|
-
@emit('Transfer')
|
|
223
|
-
public transfer(calldata: Calldata): BytesWriter {
|
|
224
|
-
const ok = this._transfer(calldata.readAddress(), calldata.readU256());
|
|
225
|
-
const w = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
226
|
-
w.writeBoolean(ok);
|
|
227
|
-
return w;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
@method(
|
|
231
|
-
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
232
|
-
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
233
|
-
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
234
|
-
)
|
|
235
|
-
@returns({ name: 'success', type: ABIDataTypes.BOOL })
|
|
236
|
-
@emit('Transfer')
|
|
237
|
-
public transferFrom(calldata: Calldata): BytesWriter {
|
|
238
|
-
const ok = this._transferFrom(
|
|
239
|
-
calldata.readAddress(),
|
|
240
|
-
calldata.readAddress(),
|
|
241
|
-
calldata.readU256(),
|
|
242
|
-
);
|
|
243
|
-
const w = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
244
|
-
w.writeBoolean(ok);
|
|
245
|
-
return w;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
protected _allowance(owner: Address, spender: Address): u256 {
|
|
249
|
-
const senderMap = this.allowanceMap.get(owner);
|
|
250
|
-
return senderMap.get(spender);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
protected _approveFrom(
|
|
254
|
-
owner: Address,
|
|
255
|
-
spender: Address,
|
|
256
|
-
value: u256,
|
|
257
|
-
nonce: u256,
|
|
258
|
-
signature: Uint8Array,
|
|
259
|
-
): boolean {
|
|
260
|
-
if (owner === Blockchain.DEAD_ADDRESS) throw new Revert('Address can not be dead');
|
|
261
|
-
if (spender === Blockchain.DEAD_ADDRESS) throw new Revert('Spender can not be dead');
|
|
262
|
-
|
|
263
|
-
const storedNonce = this._nonceMap.get(owner);
|
|
264
|
-
if (!u256.eq(storedNonce, nonce)) throw new Revert('Invalid nonce');
|
|
265
|
-
|
|
266
|
-
const writer = new BytesWriter(
|
|
267
|
-
ADDRESS_BYTE_LENGTH * 3 + U256_BYTE_LENGTH + U256_BYTE_LENGTH,
|
|
268
|
-
);
|
|
269
|
-
writer.writeAddress(owner);
|
|
270
|
-
writer.writeAddress(spender);
|
|
271
|
-
writer.writeU256(value);
|
|
272
|
-
writer.writeU256(nonce);
|
|
273
|
-
writer.writeAddress(this.address);
|
|
274
|
-
|
|
275
|
-
const hash = sha256(writer.getBuffer());
|
|
276
|
-
if (!Blockchain.verifySchnorrSignature(owner, signature, hash)) {
|
|
277
|
-
throw new Revert('Invalid signature');
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
this._nonceMap.set(owner, SafeMath.add(storedNonce, u256.One));
|
|
281
|
-
|
|
282
|
-
const senderMap = this.allowanceMap.get(owner);
|
|
283
|
-
senderMap.set(spender, value);
|
|
284
|
-
|
|
285
|
-
this.createApproveEvent(owner, spender, value);
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
protected _approve(owner: Address, spender: Address, value: u256): boolean {
|
|
290
|
-
if (owner === Blockchain.DEAD_ADDRESS) throw new Revert('Address can not be dead');
|
|
291
|
-
if (spender === Blockchain.DEAD_ADDRESS) throw new Revert('Spender can not be dead');
|
|
292
|
-
|
|
293
|
-
const senderMap = this.allowanceMap.get(owner);
|
|
294
|
-
senderMap.set(spender, value);
|
|
295
|
-
|
|
296
|
-
this.createApproveEvent(owner, spender, value);
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
protected _balanceOf(owner: Address): u256 {
|
|
301
|
-
if (!this.balanceOfMap.has(owner)) return u256.Zero;
|
|
302
|
-
return this.balanceOfMap.get(owner);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
protected _burn(value: u256, onlyDeployer: boolean = true): boolean {
|
|
306
|
-
if (u256.eq(value, u256.Zero)) throw new Revert('No tokens');
|
|
307
|
-
|
|
308
|
-
if (onlyDeployer) this.onlyDeployer(Blockchain.tx.sender);
|
|
309
|
-
if (this._totalSupply.value < value) throw new Revert('Insufficient supply');
|
|
310
|
-
if (!this.balanceOfMap.has(Blockchain.tx.sender)) throw new Revert('No balance');
|
|
311
|
-
|
|
312
|
-
const balance: u256 = this.balanceOfMap.get(Blockchain.tx.sender);
|
|
313
|
-
if (balance < value) throw new Revert('Insufficient balance');
|
|
314
|
-
|
|
315
|
-
const newBalance: u256 = SafeMath.sub(balance, value);
|
|
316
|
-
this.balanceOfMap.set(Blockchain.tx.sender, newBalance);
|
|
317
|
-
|
|
318
|
-
// @ts-expect-error AssemblyScript valid
|
|
319
|
-
this._totalSupply -= value;
|
|
320
|
-
|
|
321
|
-
this.createBurnEvent(value);
|
|
322
|
-
return true;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
protected _mint(to: Address, value: u256, onlyDeployer: boolean = true): boolean {
|
|
326
|
-
if (onlyDeployer) this.onlyDeployer(Blockchain.tx.sender);
|
|
327
|
-
|
|
328
|
-
if (!this.balanceOfMap.has(to)) {
|
|
329
|
-
this.balanceOfMap.set(to, value);
|
|
330
|
-
} else {
|
|
331
|
-
const toBal: u256 = this.balanceOfMap.get(to);
|
|
332
|
-
this.balanceOfMap.set(to, SafeMath.add(toBal, value));
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// @ts-expect-error AssemblyScript valid
|
|
336
|
-
this._totalSupply += value;
|
|
337
|
-
|
|
338
|
-
if (this._totalSupply.value > this.maxSupply) throw new Revert('Max supply reached');
|
|
339
|
-
this.createMintEvent(to, value);
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
protected _transfer(to: Address, value: u256): boolean {
|
|
344
|
-
const sender = Blockchain.tx.sender;
|
|
345
|
-
if (this.isSelf(sender)) throw new Revert('Cannot transfer from self');
|
|
346
|
-
if (u256.eq(value, u256.Zero)) throw new Revert('Cannot transfer 0');
|
|
347
|
-
|
|
348
|
-
const balance: u256 = this.balanceOfMap.get(sender);
|
|
349
|
-
if (balance < value) throw new Revert('Insufficient balance');
|
|
350
|
-
|
|
351
|
-
this.balanceOfMap.set(sender, SafeMath.sub(balance, value));
|
|
352
|
-
|
|
353
|
-
const toBal: u256 = this.balanceOfMap.get(to);
|
|
354
|
-
this.balanceOfMap.set(to, SafeMath.add(toBal, value));
|
|
355
|
-
|
|
356
|
-
this.createTransferEvent(sender, to, value);
|
|
357
|
-
return true;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
@unsafe
|
|
361
|
-
protected _unsafeTransferFrom(from: Address, to: Address, value: u256): boolean {
|
|
362
|
-
const balance: u256 = this.balanceOfMap.get(from);
|
|
363
|
-
if (balance < value) {
|
|
364
|
-
throw new Revert(`TransferFrom insufficient balance`);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
this.balanceOfMap.set(from, SafeMath.sub(balance, value));
|
|
368
|
-
|
|
369
|
-
if (!this.balanceOfMap.has(to)) {
|
|
370
|
-
this.balanceOfMap.set(to, value);
|
|
371
|
-
} else {
|
|
372
|
-
const toBal: u256 = this.balanceOfMap.get(to);
|
|
373
|
-
this.balanceOfMap.set(to, SafeMath.add(toBal, value));
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
this.createTransferEvent(from, to, value);
|
|
377
|
-
return true;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
protected _transferFrom(from: Address, to: Address, value: u256): boolean {
|
|
381
|
-
if (from === Blockchain.DEAD_ADDRESS) throw new Revert('Cannot transfer from dead address');
|
|
382
|
-
|
|
383
|
-
this._spendAllowance(from, Blockchain.tx.sender, value);
|
|
384
|
-
this._unsafeTransferFrom(from, to, value);
|
|
385
|
-
return true;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
protected _spendAllowance(owner: Address, spender: Address, value: u256): void {
|
|
389
|
-
const ownerMap = this.allowanceMap.get(owner);
|
|
390
|
-
const allowed: u256 = ownerMap.get(spender);
|
|
391
|
-
|
|
392
|
-
if (allowed < value) {
|
|
393
|
-
throw new Revert('Insufficient allowance');
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
ownerMap.set(spender, SafeMath.sub(allowed, value));
|
|
397
|
-
this.allowanceMap.set(owner, ownerMap);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
protected createBurnEvent(value: u256): void {
|
|
401
|
-
this.emitEvent(new BurnEvent(value));
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
protected createApproveEvent(owner: Address, spender: Address, value: u256): void {
|
|
405
|
-
this.emitEvent(new ApproveEvent(owner, spender, value));
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
protected createMintEvent(recipient: Address, value: u256): void {
|
|
409
|
-
this.emitEvent(new MintEvent(recipient, value));
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
protected createTransferEvent(from: Address, to: Address, value: u256): void {
|
|
413
|
-
this.emitEvent(new TransferEvent(from, to, value));
|
|
414
|
-
}
|
|
415
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { DeployableOP_20 } from './DeployableOP_20';
|
|
2
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
|
-
import { OP20InitParameters } from './interfaces/OP20InitParameters';
|
|
4
|
-
|
|
5
|
-
export abstract class OP_20 extends DeployableOP_20 {
|
|
6
|
-
public constructor(maxSupply: u256, decimals: u8, name: string, symbol: string) {
|
|
7
|
-
super(new OP20InitParameters(maxSupply, decimals, name, symbol));
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { BytesWriter } from '../../buffer/BytesWriter';
|
|
2
|
-
import { StoredU256 } from '../../storage/StoredU256';
|
|
3
|
-
import { Calldata } from '../../types';
|
|
4
|
-
|
|
5
|
-
export interface IOP_20 {
|
|
6
|
-
readonly _totalSupply: StoredU256;
|
|
7
|
-
|
|
8
|
-
balanceOf(callData: Calldata): BytesWriter;
|
|
9
|
-
|
|
10
|
-
transfer(callData: Calldata): BytesWriter;
|
|
11
|
-
|
|
12
|
-
transferFrom(callData: Calldata): BytesWriter;
|
|
13
|
-
|
|
14
|
-
approve(callData: Calldata): BytesWriter;
|
|
15
|
-
|
|
16
|
-
allowance(callData: Calldata): BytesWriter;
|
|
17
|
-
|
|
18
|
-
burn(callData: Calldata): BytesWriter;
|
|
19
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
-
import { BytesWriter } from '../../buffer/BytesWriter';
|
|
3
|
-
import { U256_BYTE_LENGTH } from '../../utils/lengths';
|
|
4
|
-
import { NetEvent } from '../NetEvent';
|
|
5
|
-
|
|
6
|
-
@final
|
|
7
|
-
export class BurnEvent extends NetEvent {
|
|
8
|
-
constructor(amount: u256) {
|
|
9
|
-
const data: BytesWriter = new BytesWriter(U256_BYTE_LENGTH);
|
|
10
|
-
data.writeU256(amount);
|
|
11
|
-
|
|
12
|
-
super('Burn', data);
|
|
13
|
-
}
|
|
14
|
-
}
|