@btc-vision/btc-runtime 1.9.13 → 1.9.15
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 +8 -9
- package/runtime/contracts/OP20.ts +31 -60
- package/runtime/contracts/interfaces/IOP20.ts +9 -0
- package/runtime/contracts/interfaces/IOP20Receiver.ts +6 -0
- package/runtime/events/predefined/ApprovedEvent.ts +2 -2
- package/runtime/script/BitcoinCodec.ts +1 -0
- package/runtime/script/Segwit.ts +11 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/btc-runtime",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.15",
|
|
4
4
|
"description": "Bitcoin Smart Contract Runtime",
|
|
5
5
|
"main": "btc/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"@btc-vision/as-pect-assembly": "^8.2.0",
|
|
26
26
|
"@btc-vision/as-pect-cli": "^8.2.0",
|
|
27
27
|
"@btc-vision/as-pect-transform": "^8.2.0",
|
|
28
|
-
"@types/node": "^24.
|
|
29
|
-
"assemblyscript": "^0.28.
|
|
28
|
+
"@types/node": "^24.10.0",
|
|
29
|
+
"assemblyscript": "^0.28.9"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
@@ -43,14 +43,13 @@
|
|
|
43
43
|
"test/*.ts"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@assemblyscript/loader": "^0.28.
|
|
46
|
+
"@assemblyscript/loader": "^0.28.9",
|
|
47
47
|
"@btc-vision/as-bignum": "^0.0.5",
|
|
48
|
-
"@btc-vision/opnet-transform": "^0.1.
|
|
49
|
-
"@eslint/js": "
|
|
48
|
+
"@btc-vision/opnet-transform": "^0.1.12",
|
|
49
|
+
"@eslint/js": "9.39.1",
|
|
50
50
|
"gulplog": "^2.2.0",
|
|
51
51
|
"ts-node": "^10.9.2",
|
|
52
|
-
"typescript": "^5.9.
|
|
53
|
-
"typescript-eslint": "^8.
|
|
54
|
-
"yaml": "^2.8.1"
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"typescript-eslint": "^8.46.3"
|
|
55
54
|
}
|
|
56
55
|
}
|
|
@@ -66,6 +66,9 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
66
66
|
protected readonly _symbol: StoredString;
|
|
67
67
|
protected readonly _nonceMap: AddressMemoryMap;
|
|
68
68
|
|
|
69
|
+
/** Intentionally public for inherited classes */
|
|
70
|
+
public _totalSupply: StoredU256;
|
|
71
|
+
|
|
69
72
|
public constructor() {
|
|
70
73
|
super();
|
|
71
74
|
|
|
@@ -81,38 +84,6 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
81
84
|
this._icon = new StoredString(stringPointer, 2);
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
/** Intentionally public for inherited classes */
|
|
85
|
-
public _totalSupply: StoredU256;
|
|
86
|
-
|
|
87
|
-
public get totalSupply(): u256 {
|
|
88
|
-
return this._totalSupply.value;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public get name(): string {
|
|
92
|
-
if (!this._name) throw new Revert('Name not set');
|
|
93
|
-
return this._name.value;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public get symbol(): string {
|
|
97
|
-
if (!this._symbol) throw new Revert('Symbol not set');
|
|
98
|
-
return this._symbol.value;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public get icon(): string {
|
|
102
|
-
if (!this._icon) throw new Revert('Icon not set');
|
|
103
|
-
return this._icon.value;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public get decimals(): u8 {
|
|
107
|
-
if (!this._decimals) throw new Revert('Decimals not set');
|
|
108
|
-
return u8(this._decimals.value.toU32());
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
public get maxSupply(): u256 {
|
|
112
|
-
if (!this._maxSupply) throw new Revert('Max supply not set');
|
|
113
|
-
return this._maxSupply.value;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
87
|
public instantiate(
|
|
117
88
|
params: OP20InitParameters,
|
|
118
89
|
skipDeployerVerification: boolean = false,
|
|
@@ -128,51 +99,51 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
128
99
|
this._icon.value = params.icon;
|
|
129
100
|
}
|
|
130
101
|
|
|
131
|
-
@method(
|
|
102
|
+
@method()
|
|
132
103
|
@returns({ name: 'name', type: ABIDataTypes.STRING })
|
|
133
|
-
public
|
|
134
|
-
const w = new BytesWriter(String.UTF8.byteLength(this.
|
|
135
|
-
w.writeStringWithLength(this.
|
|
104
|
+
public name(_: Calldata): BytesWriter {
|
|
105
|
+
const w = new BytesWriter(String.UTF8.byteLength(this._name.value) + 4);
|
|
106
|
+
w.writeStringWithLength(this._name.value);
|
|
136
107
|
return w;
|
|
137
108
|
}
|
|
138
109
|
|
|
139
|
-
@method(
|
|
110
|
+
@method()
|
|
140
111
|
@returns({ name: 'symbol', type: ABIDataTypes.STRING })
|
|
141
|
-
public
|
|
142
|
-
const w = new BytesWriter(String.UTF8.byteLength(this.
|
|
143
|
-
w.writeStringWithLength(this.
|
|
112
|
+
public symbol(_: Calldata): BytesWriter {
|
|
113
|
+
const w = new BytesWriter(String.UTF8.byteLength(this._symbol.value) + 4);
|
|
114
|
+
w.writeStringWithLength(this._symbol.value);
|
|
144
115
|
return w;
|
|
145
116
|
}
|
|
146
117
|
|
|
147
|
-
@method(
|
|
118
|
+
@method()
|
|
148
119
|
@returns({ name: 'icon', type: ABIDataTypes.STRING })
|
|
149
|
-
public
|
|
150
|
-
const w = new BytesWriter(String.UTF8.byteLength(this.
|
|
151
|
-
w.writeStringWithLength(this.
|
|
120
|
+
public icon(_: Calldata): BytesWriter {
|
|
121
|
+
const w = new BytesWriter(String.UTF8.byteLength(this._icon.value) + 4);
|
|
122
|
+
w.writeStringWithLength(this._icon.value);
|
|
152
123
|
return w;
|
|
153
124
|
}
|
|
154
125
|
|
|
155
|
-
@method(
|
|
126
|
+
@method()
|
|
156
127
|
@returns({ name: 'decimals', type: ABIDataTypes.UINT8 })
|
|
157
|
-
public
|
|
128
|
+
public decimals(_: Calldata): BytesWriter {
|
|
158
129
|
const w = new BytesWriter(1);
|
|
159
|
-
w.writeU8(this.
|
|
130
|
+
w.writeU8(this._decimals.value.toU32());
|
|
160
131
|
return w;
|
|
161
132
|
}
|
|
162
133
|
|
|
163
|
-
@method(
|
|
134
|
+
@method()
|
|
164
135
|
@returns({ name: 'totalSupply', type: ABIDataTypes.UINT256 })
|
|
165
|
-
public
|
|
136
|
+
public totalSupply(_: Calldata): BytesWriter {
|
|
166
137
|
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
167
|
-
w.writeU256(this.
|
|
138
|
+
w.writeU256(this._totalSupply.value);
|
|
168
139
|
return w;
|
|
169
140
|
}
|
|
170
141
|
|
|
171
|
-
@method(
|
|
142
|
+
@method()
|
|
172
143
|
@returns({ name: 'maximumSupply', type: ABIDataTypes.UINT256 })
|
|
173
|
-
public
|
|
144
|
+
public maximumSupply(_: Calldata): BytesWriter {
|
|
174
145
|
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
175
|
-
w.writeU256(this.
|
|
146
|
+
w.writeU256(this._maxSupply.value);
|
|
176
147
|
return w;
|
|
177
148
|
}
|
|
178
149
|
|
|
@@ -363,9 +334,9 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
363
334
|
{ name: 'domainSeparator', type: ABIDataTypes.BYTES32 },
|
|
364
335
|
)
|
|
365
336
|
public metadata(_: Calldata): BytesWriter {
|
|
366
|
-
const name = this.
|
|
367
|
-
const symbol = this.
|
|
368
|
-
const icon = this.
|
|
337
|
+
const name = this._name.value;
|
|
338
|
+
const symbol = this._symbol.value;
|
|
339
|
+
const icon = this._icon.value;
|
|
369
340
|
const domainSeparator = this._buildDomainSeparator();
|
|
370
341
|
|
|
371
342
|
const nameLength = String.UTF8.byteLength(name);
|
|
@@ -385,8 +356,8 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
385
356
|
w.writeStringWithLength(name);
|
|
386
357
|
w.writeStringWithLength(symbol);
|
|
387
358
|
w.writeStringWithLength(icon);
|
|
388
|
-
w.writeU8(this.
|
|
389
|
-
w.writeU256(this.
|
|
359
|
+
w.writeU8(this._decimals.value.toU32());
|
|
360
|
+
w.writeU256(this._totalSupply.value);
|
|
390
361
|
w.writeBytesWithLength(domainSeparator);
|
|
391
362
|
|
|
392
363
|
return w;
|
|
@@ -583,7 +554,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
583
554
|
protected _buildDomainSeparator(): Uint8Array {
|
|
584
555
|
const writer = new BytesWriter(32 * 5 + ADDRESS_BYTE_LENGTH);
|
|
585
556
|
writer.writeBytesU8Array(OP712_DOMAIN_TYPE_HASH);
|
|
586
|
-
writer.writeBytes(sha256String(this.
|
|
557
|
+
writer.writeBytes(sha256String(this._name.value));
|
|
587
558
|
writer.writeBytesU8Array(OP712_VERSION_HASH);
|
|
588
559
|
writer.writeBytes(Blockchain.chainId);
|
|
589
560
|
writer.writeBytes(Blockchain.protocolId);
|
|
@@ -646,7 +617,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
646
617
|
// @ts-expect-error AssemblyScript valid
|
|
647
618
|
this._totalSupply += amount;
|
|
648
619
|
|
|
649
|
-
if (this._totalSupply.value > this.
|
|
620
|
+
if (this._totalSupply.value > this._maxSupply.value) {
|
|
650
621
|
throw new Revert('Max supply reached');
|
|
651
622
|
}
|
|
652
623
|
|
|
@@ -2,12 +2,21 @@ import { BytesWriter } from '../../buffer/BytesWriter';
|
|
|
2
2
|
import { Calldata } from '../../types';
|
|
3
3
|
|
|
4
4
|
export interface IOP20 {
|
|
5
|
+
name(callData: Calldata): BytesWriter;
|
|
6
|
+
symbol(callData: Calldata): BytesWriter;
|
|
7
|
+
icon(callData: Calldata): BytesWriter;
|
|
8
|
+
decimals(callData: Calldata): BytesWriter;
|
|
9
|
+
totalSupply(callData: Calldata): BytesWriter;
|
|
5
10
|
domainSeparator(callData: Calldata): BytesWriter;
|
|
11
|
+
metadata(callData: Calldata): BytesWriter;
|
|
6
12
|
balanceOf(callData: Calldata): BytesWriter;
|
|
7
13
|
nonceOf(callData: Calldata): BytesWriter;
|
|
8
14
|
allowance(callData: Calldata): BytesWriter;
|
|
9
15
|
safeTransfer(callData: Calldata): BytesWriter;
|
|
10
16
|
safeTransferFrom(callData: Calldata): BytesWriter;
|
|
17
|
+
transfer(callData: Calldata): BytesWriter;
|
|
18
|
+
transferFrom(callData: Calldata): BytesWriter;
|
|
19
|
+
burn(callData: Calldata): BytesWriter;
|
|
11
20
|
increaseAllowance(callData: Calldata): BytesWriter;
|
|
12
21
|
decreaseAllowance(callData: Calldata): BytesWriter;
|
|
13
22
|
increaseAllowanceBySignature(callData: Calldata): BytesWriter;
|
|
@@ -6,11 +6,11 @@ import { NetEvent } from '../NetEvent';
|
|
|
6
6
|
|
|
7
7
|
@final
|
|
8
8
|
export class ApprovedEvent extends NetEvent {
|
|
9
|
-
constructor(owner: Address, spender: Address,
|
|
9
|
+
constructor(owner: Address, spender: Address, amount: u256) {
|
|
10
10
|
const data: BytesWriter = new BytesWriter(ADDRESS_BYTE_LENGTH * 2 + U256_BYTE_LENGTH);
|
|
11
11
|
data.writeAddress(owner);
|
|
12
12
|
data.writeAddress(spender);
|
|
13
|
-
data.writeU256(
|
|
13
|
+
data.writeU256(amount);
|
|
14
14
|
|
|
15
15
|
super('Approved', data);
|
|
16
16
|
}
|
|
@@ -353,6 +353,7 @@ export class BitcoinCodec {
|
|
|
353
353
|
/**
|
|
354
354
|
* Validate that a witness script is within size limits
|
|
355
355
|
* Bitcoin consensus rules limit witness scripts to 10,000 bytes
|
|
356
|
+
* Witness scripts above 3,600 bytes are non-standard and will not be relayed
|
|
356
357
|
*
|
|
357
358
|
* @param witnessScript - The script to validate
|
|
358
359
|
* @returns true if the script is within limits
|
package/runtime/script/Segwit.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { SegwitDecoded } from './ScriptUtils';
|
|
|
2
2
|
import { hash160, sha256 } from '../env/global';
|
|
3
3
|
import { Bech32 } from './Bech32';
|
|
4
4
|
import { Revert } from '../types/Revert';
|
|
5
|
+
import { BitcoinCodec } from './BitcoinCodec';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Segwit provides high-level functions for creating and decoding
|
|
@@ -23,6 +24,10 @@ export class Segwit {
|
|
|
23
24
|
* @returns The Bech32-encoded address
|
|
24
25
|
*/
|
|
25
26
|
public static p2wsh(hrp: string, witnessScript: Uint8Array): string {
|
|
27
|
+
if (BitcoinCodec.isValidWitnessScriptSize(witnessScript)) {
|
|
28
|
+
throw new Revert('Witness script size is invalid');
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
// P2WSH uses SHA256 of the script as the witness program
|
|
27
32
|
const program = sha256(witnessScript);
|
|
28
33
|
return Bech32.encode(hrp, 0, program);
|
|
@@ -33,6 +38,10 @@ export class Segwit {
|
|
|
33
38
|
* This is useful when you need to handle encoding failures gracefully
|
|
34
39
|
*/
|
|
35
40
|
public static p2wshOrNull(hrp: string, witnessScript: Uint8Array): string | null {
|
|
41
|
+
if (BitcoinCodec.isValidWitnessScriptSize(witnessScript)) {
|
|
42
|
+
throw new Revert('Witness script size is invalid');
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
const program = sha256(witnessScript);
|
|
37
46
|
return Bech32.encodeOrNull(hrp, 0, program);
|
|
38
47
|
}
|
|
@@ -49,8 +58,8 @@ export class Segwit {
|
|
|
49
58
|
* @returns The Bech32-encoded address
|
|
50
59
|
*/
|
|
51
60
|
public static p2wpkh(hrp: string, pubkey: Uint8Array): string {
|
|
52
|
-
if (pubkey.length !== 33
|
|
53
|
-
throw new Revert('Public key must be 33 bytes
|
|
61
|
+
if (pubkey.length !== 33) {
|
|
62
|
+
throw new Revert('Public key must be 33 bytes');
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
// P2WPKH uses HASH160 of the public key as the witness program
|