@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.
Files changed (69) hide show
  1. package/README.md +57 -79
  2. package/package.json +8 -8
  3. package/runtime/buffer/BytesReader.ts +36 -45
  4. package/runtime/buffer/BytesWriter.ts +60 -20
  5. package/runtime/contracts/OP20.ts +636 -0
  6. package/runtime/contracts/OP_NET.ts +3 -3
  7. package/runtime/contracts/interfaces/IOP20.ts +15 -0
  8. package/runtime/contracts/interfaces/OP20InitParameters.ts +3 -1
  9. package/runtime/env/BlockchainEnvironment.ts +28 -7
  10. package/runtime/env/classes/Transaction.ts +1 -2
  11. package/runtime/env/global.ts +171 -23
  12. package/runtime/events/NetEvent.ts +1 -1
  13. package/runtime/events/predefined/{ApproveEvent.ts → ApprovedEvent.ts} +3 -3
  14. package/runtime/events/predefined/{MintEvent.ts → BurnedEvent.ts} +5 -6
  15. package/runtime/events/predefined/{TransferEvent.ts → MintedEvent.ts} +5 -6
  16. package/runtime/events/predefined/TransferredEvent.ts +18 -0
  17. package/runtime/events/predefined/index.ts +4 -4
  18. package/runtime/exports/index.ts +4 -4
  19. package/runtime/index.ts +13 -3
  20. package/runtime/math/abi.ts +10 -6
  21. package/runtime/math/bytes.ts +5 -17
  22. package/runtime/memory/AddressMemoryMap.ts +4 -5
  23. package/runtime/memory/KeyMerger.ts +7 -7
  24. package/runtime/memory/MapOfMap.ts +2 -7
  25. package/runtime/memory/Nested.ts +6 -8
  26. package/runtime/nested/PointerManager.ts +1 -1
  27. package/runtime/nested/codecs/AddressCodec.ts +1 -1
  28. package/runtime/nested/codecs/BooleanCodec.ts +1 -1
  29. package/runtime/nested/codecs/Ids.ts +1 -1
  30. package/runtime/nested/codecs/NumericCodec.ts +1 -1
  31. package/runtime/nested/codecs/StringCodec.ts +1 -1
  32. package/runtime/nested/codecs/VariableBytesCodec.ts +3 -3
  33. package/runtime/nested/storage/StorageMap.ts +3 -3
  34. package/runtime/nested/storage/StorageSet.ts +2 -2
  35. package/runtime/plugins/Plugin.ts +5 -7
  36. package/runtime/script/Bech32.ts +369 -0
  37. package/runtime/script/BitcoinAddresses.ts +208 -0
  38. package/runtime/script/BitcoinCodec.ts +395 -0
  39. package/runtime/script/Networks.ts +94 -0
  40. package/runtime/script/Opcodes.ts +155 -0
  41. package/runtime/script/Script.ts +463 -0
  42. package/runtime/script/ScriptUtils.ts +101 -0
  43. package/runtime/script/Segwit.ts +185 -0
  44. package/runtime/script/reader/ScriptReader.ts +247 -0
  45. package/runtime/secp256k1/ECPoint.ts +6 -12
  46. package/runtime/shared-libraries/TransferHelper.ts +72 -31
  47. package/runtime/storage/AdvancedStoredString.ts +1 -1
  48. package/runtime/storage/StoredAddress.ts +1 -1
  49. package/runtime/storage/StoredBoolean.ts +2 -4
  50. package/runtime/storage/StoredString.ts +6 -3
  51. package/runtime/storage/StoredU256.ts +1 -3
  52. package/runtime/storage/StoredU32.ts +1 -6
  53. package/runtime/storage/StoredU64.ts +1 -4
  54. package/runtime/storage/arrays/StoredBooleanArray.ts +7 -12
  55. package/runtime/storage/arrays/StoredPackedArray.ts +3 -13
  56. package/runtime/storage/maps/StoredMapU256.ts +5 -5
  57. package/runtime/types/Address.ts +49 -39
  58. package/runtime/types/SafeMath.ts +19 -18
  59. package/runtime/types/SafeMathI128.ts +14 -13
  60. package/runtime/utils/hex.ts +41 -19
  61. package/runtime/utils/index.ts +0 -2
  62. package/runtime/contracts/DeployableOP_20.ts +0 -415
  63. package/runtime/contracts/OP_20.ts +0 -9
  64. package/runtime/contracts/interfaces/IOP_20.ts +0 -19
  65. package/runtime/events/predefined/BurnEvent.ts +0 -14
  66. package/runtime/utils/b32.ts +0 -243
  67. package/runtime/utils/box.ts +0 -134
  68. package/runtime/utils/encodings.ts +0 -45
  69. /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
- let c = i128.add(a, b);
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 Error('SafeMathI128: addition overflow');
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
- let c = i128.sub(a, b);
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 Error('SafeMathI128: subtraction overflow');
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 Error('SafeMathI128: multiplication overflow');
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 Error('SafeMathI128: division by zero');
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 Error('SafeMathI128: division overflow (MIN / -1)');
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 Error('SafeMathI128: modulo by zero');
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 Error('SafeMathI128: modulo overflow (MIN % -1)');
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 Error('SafeMathI128: inc overflow');
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 Error('SafeMathI128: dec underflow');
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 Error('SafeMathI128: abs overflow on MIN');
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 Error('SafeMathI128: neg overflow on MIN');
137
+ throw new Revert('SafeMathI128: neg overflow on MIN');
137
138
  }
138
139
  return x.neg();
139
140
  }
@@ -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
- }
@@ -1,4 +1,2 @@
1
- export * from './box';
2
- export * from './encodings';
3
1
  export * from './hex';
4
2
  export * from './lengths';
@@ -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
- }