@btc-vision/btc-runtime 1.10.5 → 1.10.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 [ORANGE PILLS INC, 2140 S DUPONT HWY CAMDEN, DE 19934]
3
+ Copyright (c) 2025 [Orange Pill Labs Holding Ltd.]
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btc-vision/btc-runtime",
3
- "version": "1.10.5",
3
+ "version": "1.10.7",
4
4
  "description": "Bitcoin Smart Contract Runtime",
5
5
  "main": "btc/index.ts",
6
6
  "scripts": {
@@ -0,0 +1,261 @@
1
+ import { u256 } from '@btc-vision/as-bignum/assembly';
2
+ import { BytesWriter } from '../buffer/BytesWriter';
3
+ import { Blockchain } from '../env';
4
+ import { Calldata } from '../types';
5
+ import { Address } from '../types/Address';
6
+ import { Revert } from '../types/Revert';
7
+ import { StoredU256 } from '../storage/StoredU256';
8
+ import { EMPTY_POINTER } from '../math/bytes';
9
+ import { OP20 } from './OP20';
10
+ import { Selector } from '../math/abi';
11
+ import { AddressMemoryMap } from '../memory/AddressMemoryMap';
12
+ import {
13
+ MaxStalenessUpdatedEvent,
14
+ PegAuthorityRenouncedEvent,
15
+ PegAuthorityTransferredEvent,
16
+ PegAuthorityTransferStartedEvent,
17
+ PegRateUpdatedEvent,
18
+ } from '../events/op20s/OP20SEvents';
19
+
20
+ // Selectors: sha256 first 4 bytes
21
+ export const PEG_RATE_SELECTOR: u32 = 0x4d1f6caf;
22
+ export const PEG_AUTHORITY_SELECTOR: u32 = 0xd767a583;
23
+ export const PEG_UPDATED_AT_SELECTOR: u32 = 0x1e99d1a1;
24
+ export const MAX_STALENESS_SELECTOR: u32 = 0x0b17a602;
25
+ export const IS_STALE_SELECTOR: u32 = 0x147c08ef;
26
+
27
+ const pegRatePointer: u16 = Blockchain.nextPointer;
28
+ const pegAuthorityPointer: u16 = Blockchain.nextPointer;
29
+ const pegUpdatedAtPointer: u16 = Blockchain.nextPointer;
30
+ const maxStalenessPointer: u16 = Blockchain.nextPointer;
31
+ const pendingAuthorityPointer: u16 = Blockchain.nextPointer;
32
+
33
+ export abstract class OP20S extends OP20 {
34
+ protected readonly _pegRate: StoredU256;
35
+ protected readonly _pegAuthorityMap: AddressMemoryMap;
36
+ protected readonly _pegUpdatedAt: StoredU256;
37
+ protected readonly _maxStaleness: StoredU256;
38
+ protected readonly _pendingAuthorityMap: AddressMemoryMap;
39
+
40
+ public constructor() {
41
+ super();
42
+ this._pegRate = new StoredU256(pegRatePointer, EMPTY_POINTER);
43
+ this._pegAuthorityMap = new AddressMemoryMap(pegAuthorityPointer);
44
+ this._pegUpdatedAt = new StoredU256(pegUpdatedAtPointer, EMPTY_POINTER);
45
+ this._maxStaleness = new StoredU256(maxStalenessPointer, EMPTY_POINTER);
46
+ this._pendingAuthorityMap = new AddressMemoryMap(pendingAuthorityPointer);
47
+ }
48
+
49
+ @method()
50
+ @returns({ name: 'rate', type: ABIDataTypes.UINT256 })
51
+ public pegRate(_: Calldata): BytesWriter {
52
+ const w = new BytesWriter(32);
53
+ w.writeU256(this._pegRate.value);
54
+ return w;
55
+ }
56
+
57
+ @method()
58
+ @returns({ name: 'authority', type: ABIDataTypes.ADDRESS })
59
+ public pegAuthority(_: Calldata): BytesWriter {
60
+ const w = new BytesWriter(32);
61
+ w.writeAddress(this._getPegAuthority());
62
+ return w;
63
+ }
64
+
65
+ @method()
66
+ @returns({ name: 'updatedAt', type: ABIDataTypes.UINT64 })
67
+ public pegUpdatedAt(_: Calldata): BytesWriter {
68
+ const w = new BytesWriter(8);
69
+ w.writeU64(this._pegUpdatedAt.value.toU64());
70
+ return w;
71
+ }
72
+
73
+ @method()
74
+ @returns({ name: 'staleness', type: ABIDataTypes.UINT64 })
75
+ public maxStaleness(_: Calldata): BytesWriter {
76
+ const w = new BytesWriter(8);
77
+ w.writeU64(this._maxStaleness.value.toU64());
78
+ return w;
79
+ }
80
+
81
+ @method()
82
+ @returns({ name: 'stale', type: ABIDataTypes.BOOL })
83
+ public isStale(_: Calldata): BytesWriter {
84
+ const w = new BytesWriter(1);
85
+ w.writeBoolean(this._isStale());
86
+ return w;
87
+ }
88
+
89
+ @method({ name: 'newRate', type: ABIDataTypes.UINT256 })
90
+ @emit('PegRateUpdated')
91
+ public updatePegRate(calldata: Calldata): BytesWriter {
92
+ this._onlyPegAuthority();
93
+
94
+ const newRate = calldata.readU256();
95
+ if (newRate.isZero()) {
96
+ throw new Revert('Invalid peg rate');
97
+ }
98
+
99
+ const oldRate = this._pegRate.value;
100
+ const blockNumber = Blockchain.block.number;
101
+
102
+ this._pegRate.value = newRate;
103
+ this._pegUpdatedAt.value = u256.fromU64(blockNumber);
104
+
105
+ this.emitEvent(new PegRateUpdatedEvent(oldRate, newRate, blockNumber));
106
+
107
+ return new BytesWriter(0);
108
+ }
109
+
110
+ @method({ name: 'newStaleness', type: ABIDataTypes.UINT64 })
111
+ @emit('MaxStalenessUpdated')
112
+ public updateMaxStaleness(calldata: Calldata): BytesWriter {
113
+ this._onlyPegAuthority();
114
+
115
+ const newStaleness = calldata.readU64();
116
+ if (newStaleness == 0) {
117
+ throw new Revert('Invalid max staleness');
118
+ }
119
+
120
+ const oldStaleness = this._maxStaleness.value.toU64();
121
+ this._maxStaleness.value = u256.fromU64(newStaleness);
122
+
123
+ this.emitEvent(new MaxStalenessUpdatedEvent(oldStaleness, newStaleness));
124
+
125
+ return new BytesWriter(0);
126
+ }
127
+
128
+ @method({ name: 'newAuthority', type: ABIDataTypes.ADDRESS })
129
+ @emit('PegAuthorityTransferStarted')
130
+ public transferPegAuthority(calldata: Calldata): BytesWriter {
131
+ this._onlyPegAuthority();
132
+
133
+ const newAuthority = calldata.readAddress();
134
+ if (newAuthority.equals(Address.zero())) {
135
+ throw new Revert('Invalid new authority');
136
+ }
137
+
138
+ const currentAuthority = this._getPegAuthority();
139
+ this._setPendingAuthority(newAuthority);
140
+
141
+ this.emitEvent(new PegAuthorityTransferStartedEvent(currentAuthority, newAuthority));
142
+
143
+ return new BytesWriter(0);
144
+ }
145
+
146
+ @method()
147
+ @emit('PegAuthorityTransferred')
148
+ public acceptPegAuthority(_: Calldata): BytesWriter {
149
+ const pending = this._getPendingAuthority();
150
+ if (pending.equals(Address.zero())) {
151
+ throw new Revert('No pending authority');
152
+ }
153
+ if (!Blockchain.tx.sender.equals(pending)) {
154
+ throw new Revert('Not pending authority');
155
+ }
156
+
157
+ const previousAuthority = this._getPegAuthority();
158
+ this._setPegAuthority(pending);
159
+ this._setPendingAuthority(Address.zero());
160
+
161
+ this.emitEvent(new PegAuthorityTransferredEvent(previousAuthority, pending));
162
+
163
+ return new BytesWriter(0);
164
+ }
165
+
166
+ @method()
167
+ @emit('PegAuthorityRenounced')
168
+ public renouncePegAuthority(_: Calldata): BytesWriter {
169
+ this._onlyPegAuthority();
170
+
171
+ const previousAuthority = this._getPegAuthority();
172
+ this._setPegAuthority(Address.zero());
173
+ this._setPendingAuthority(Address.zero());
174
+
175
+ this.emitEvent(new PegAuthorityRenouncedEvent(previousAuthority));
176
+
177
+ return new BytesWriter(0);
178
+ }
179
+
180
+ protected initializePeg(pegAuthority: Address, initialPegRate: u256, maxStaleness: u64): void {
181
+ if (pegAuthority.equals(Address.zero())) {
182
+ throw new Revert('Invalid peg authority');
183
+ }
184
+ if (initialPegRate.isZero()) {
185
+ throw new Revert('Invalid initial peg rate');
186
+ }
187
+ if (maxStaleness == 0) {
188
+ throw new Revert('Invalid max staleness');
189
+ }
190
+
191
+ this._setPegAuthority(pegAuthority);
192
+ this._pegRate.value = initialPegRate;
193
+ this._pegUpdatedAt.value = u256.fromU64(Blockchain.block.number);
194
+ this._maxStaleness.value = u256.fromU64(maxStaleness);
195
+
196
+ this.emitEvent(new PegRateUpdatedEvent(u256.Zero, initialPegRate, Blockchain.block.number));
197
+ }
198
+
199
+ protected _isStale(): boolean {
200
+ const currentBlock = Blockchain.block.number;
201
+ const updatedAt = this._pegUpdatedAt.value.toU64();
202
+ const maxStale = this._maxStaleness.value.toU64();
203
+
204
+ return currentBlock > updatedAt + maxStale;
205
+ }
206
+
207
+ protected _requireFreshPeg(): void {
208
+ if (this._isStale()) {
209
+ throw new Revert('Peg rate stale');
210
+ }
211
+ }
212
+
213
+ protected _onlyPegAuthority(): void {
214
+ if (!Blockchain.tx.sender.equals(this._getPegAuthority())) {
215
+ throw new Revert('Not peg authority');
216
+ }
217
+ }
218
+
219
+ protected _getPegAuthority(): Address {
220
+ const stored = this._pegAuthorityMap.get(Address.zero());
221
+ if (stored.isZero()) return Address.zero();
222
+ return this._u256ToAddress(stored);
223
+ }
224
+
225
+ protected _setPegAuthority(addr: Address): void {
226
+ this._pegAuthorityMap.set(Address.zero(), this._addressToU256(addr));
227
+ }
228
+
229
+ protected _getPendingAuthority(): Address {
230
+ const stored = this._pendingAuthorityMap.get(Address.zero());
231
+ if (stored.isZero()) return Address.zero();
232
+ return this._u256ToAddress(stored);
233
+ }
234
+
235
+ protected _setPendingAuthority(addr: Address): void {
236
+ this._pendingAuthorityMap.set(Address.zero(), this._addressToU256(addr));
237
+ }
238
+
239
+ protected _addressToU256(addr: Address): u256 {
240
+ return u256.fromUint8ArrayBE(addr);
241
+ }
242
+
243
+ protected _u256ToAddress(val: u256): Address {
244
+ if (val.isZero()) return Address.zero();
245
+ const bytes = val.toUint8Array(true);
246
+ return Address.fromUint8Array(bytes);
247
+ }
248
+
249
+ protected override isSelectorExcluded(selector: Selector): boolean {
250
+ if (
251
+ selector == PEG_RATE_SELECTOR ||
252
+ selector == PEG_AUTHORITY_SELECTOR ||
253
+ selector == PEG_UPDATED_AT_SELECTOR ||
254
+ selector == MAX_STALENESS_SELECTOR ||
255
+ selector == IS_STALE_SELECTOR
256
+ ) {
257
+ return true;
258
+ }
259
+ return super.isSelectorExcluded(selector);
260
+ }
261
+ }
@@ -0,0 +1,8 @@
1
+ import { Calldata } from '../../types';
2
+ import { BytesWriter } from '../../buffer/BytesWriter';
3
+
4
+ export interface IOP20S {
5
+ pegRate(calldata: Calldata): BytesWriter;
6
+ pegAuthority(calldata: Calldata): BytesWriter;
7
+ pegUpdatedAt(calldata: Calldata): BytesWriter;
8
+ }
@@ -0,0 +1,60 @@
1
+ import { u256 } from '@btc-vision/as-bignum/assembly';
2
+ import { NetEvent } from '../NetEvent';
3
+ import { BytesWriter } from '../../buffer/BytesWriter';
4
+ import { ADDRESS_BYTE_LENGTH, U256_BYTE_LENGTH, U64_BYTE_LENGTH } from '../../utils';
5
+ import { Address } from '../../types/Address';
6
+
7
+ @final
8
+ export class PegRateUpdatedEvent extends NetEvent {
9
+ constructor(oldRate: u256, newRate: u256, updatedAt: u64) {
10
+ const data: BytesWriter = new BytesWriter(U256_BYTE_LENGTH * 2 + U64_BYTE_LENGTH);
11
+ data.writeU256(oldRate);
12
+ data.writeU256(newRate);
13
+ data.writeU64(updatedAt);
14
+
15
+ super('PegRateUpdated', data);
16
+ }
17
+ }
18
+
19
+ @final
20
+ export class PegAuthorityTransferStartedEvent extends NetEvent {
21
+ constructor(currentAuthority: Address, pendingAuthority: Address) {
22
+ const data: BytesWriter = new BytesWriter(ADDRESS_BYTE_LENGTH * 2);
23
+ data.writeAddress(currentAuthority);
24
+ data.writeAddress(pendingAuthority);
25
+
26
+ super('PegAuthorityTransferStarted', data);
27
+ }
28
+ }
29
+
30
+ @final
31
+ export class PegAuthorityTransferredEvent extends NetEvent {
32
+ constructor(previousAuthority: Address, newAuthority: Address) {
33
+ const data: BytesWriter = new BytesWriter(ADDRESS_BYTE_LENGTH * 2);
34
+ data.writeAddress(previousAuthority);
35
+ data.writeAddress(newAuthority);
36
+
37
+ super('PegAuthorityTransferred', data);
38
+ }
39
+ }
40
+
41
+ @final
42
+ export class PegAuthorityRenouncedEvent extends NetEvent {
43
+ constructor(previousAuthority: Address) {
44
+ const data: BytesWriter = new BytesWriter(ADDRESS_BYTE_LENGTH);
45
+ data.writeAddress(previousAuthority);
46
+
47
+ super('PegAuthorityRenounced', data);
48
+ }
49
+ }
50
+
51
+ @final
52
+ export class MaxStalenessUpdatedEvent extends NetEvent {
53
+ constructor(oldStaleness: u64, newStaleness: u64) {
54
+ const data: BytesWriter = new BytesWriter(U64_BYTE_LENGTH * 2);
55
+ data.writeU64(oldStaleness);
56
+ data.writeU64(newStaleness);
57
+
58
+ super('MaxStalenessUpdated', data);
59
+ }
60
+ }
package/runtime/index.ts CHANGED
@@ -3,7 +3,9 @@ export * from './env';
3
3
 
4
4
  /** Contracts */
5
5
  export * from './contracts/interfaces/IOP20';
6
+ export * from './contracts/interfaces/IOP20S';
6
7
  export * from './contracts/OP20';
8
+ export * from './contracts/OP20S';
7
9
  export * from './contracts/OP_NET';
8
10
  export * from './contracts/interfaces/OP20InitParameters';
9
11
 
@@ -17,6 +19,7 @@ export * from './interfaces/IBTC';
17
19
  /** Events */
18
20
  export * from './events/NetEvent';
19
21
  export * from './events/predefined';
22
+ export * from './events/op20s/OP20SEvents';
20
23
 
21
24
  /** Env */
22
25
  export * from './env/classes/UTXO';