@btc-vision/btc-runtime 1.10.6 → 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.6",
3
+ "version": "1.10.7",
4
4
  "description": "Bitcoin Smart Contract Runtime",
5
5
  "main": "btc/index.ts",
6
6
  "scripts": {
@@ -5,83 +5,51 @@ import { Calldata } from '../types';
5
5
  import { Address } from '../types/Address';
6
6
  import { Revert } from '../types/Revert';
7
7
  import { StoredU256 } from '../storage/StoredU256';
8
- import { StoredAddress } from '../storage/StoredAddress';
9
8
  import { EMPTY_POINTER } from '../math/bytes';
10
9
  import { OP20 } from './OP20';
11
- import { IOP20S } from './interfaces/IOP20S';
12
- import { OP20InitParameters } from './interfaces/OP20InitParameters';
13
- import { ADDRESS_BYTE_LENGTH, U256_BYTE_LENGTH, U64_BYTE_LENGTH } from '../utils';
14
10
  import { Selector } from '../math/abi';
15
-
16
- const pegRatePointer: u16 = Blockchain.nextPointer;
17
- const pegAuthorityPointer: u16 = Blockchain.nextPointer;
18
- const pegUpdatedAtPointer: u16 = Blockchain.nextPointer;
19
- const maxStalenessPointer: u16 = Blockchain.nextPointer;
20
- const pendingAuthorityPointer: u16 = Blockchain.nextPointer;
21
-
22
- // "pegRate()"
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
23
21
  export const PEG_RATE_SELECTOR: u32 = 0x4d1f6caf;
24
-
25
- // "pegAuthority()"
26
22
  export const PEG_AUTHORITY_SELECTOR: u32 = 0xd767a583;
27
-
28
- // "pegUpdatedAt()"
29
23
  export const PEG_UPDATED_AT_SELECTOR: u32 = 0x1e99d1a1;
30
-
31
- // "maxStaleness()"
32
24
  export const MAX_STALENESS_SELECTOR: u32 = 0x0b17a602;
33
-
34
- // "isStale()"
35
25
  export const IS_STALE_SELECTOR: u32 = 0x147c08ef;
36
26
 
37
- export interface OP20SInitParameters extends OP20InitParameters {
38
- pegAuthority: Address;
39
- initialPegRate: u256;
40
- maxStaleness: u64;
41
- }
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;
42
32
 
43
- export abstract class OP20S extends OP20 implements IOP20S {
33
+ export abstract class OP20S extends OP20 {
44
34
  protected readonly _pegRate: StoredU256;
45
- protected readonly _pegAuthority: StoredAddress;
35
+ protected readonly _pegAuthorityMap: AddressMemoryMap;
46
36
  protected readonly _pegUpdatedAt: StoredU256;
47
37
  protected readonly _maxStaleness: StoredU256;
48
- protected readonly _pendingAuthority: StoredAddress;
38
+ protected readonly _pendingAuthorityMap: AddressMemoryMap;
49
39
 
50
40
  public constructor() {
51
41
  super();
52
42
  this._pegRate = new StoredU256(pegRatePointer, EMPTY_POINTER);
53
- this._pegAuthority = new StoredAddress(pegAuthorityPointer);
43
+ this._pegAuthorityMap = new AddressMemoryMap(pegAuthorityPointer);
54
44
  this._pegUpdatedAt = new StoredU256(pegUpdatedAtPointer, EMPTY_POINTER);
55
45
  this._maxStaleness = new StoredU256(maxStalenessPointer, EMPTY_POINTER);
56
- this._pendingAuthority = new StoredAddress(pendingAuthorityPointer);
57
- }
58
-
59
- public override instantiate(
60
- params: OP20SInitParameters,
61
- skipDeployerVerification: boolean = false,
62
- ): void {
63
- super.instantiate(params, skipDeployerVerification);
64
-
65
- if (params.pegAuthority === Address.zero()) {
66
- throw new Revert('Invalid peg authority');
67
- }
68
- if (params.initialPegRate.isZero()) {
69
- throw new Revert('Invalid initial peg rate');
70
- }
71
- if (params.maxStaleness === 0) {
72
- throw new Revert('Invalid max staleness');
73
- }
74
-
75
- this._pegAuthority.value = params.pegAuthority;
76
- this._pegRate.value = params.initialPegRate;
77
- this._pegUpdatedAt.value = u256.fromU64(Blockchain.block.number);
78
- this._maxStaleness.value = u256.fromU64(params.maxStaleness);
46
+ this._pendingAuthorityMap = new AddressMemoryMap(pendingAuthorityPointer);
79
47
  }
80
48
 
81
49
  @method()
82
50
  @returns({ name: 'rate', type: ABIDataTypes.UINT256 })
83
51
  public pegRate(_: Calldata): BytesWriter {
84
- const w = new BytesWriter(U256_BYTE_LENGTH);
52
+ const w = new BytesWriter(32);
85
53
  w.writeU256(this._pegRate.value);
86
54
  return w;
87
55
  }
@@ -89,15 +57,15 @@ export abstract class OP20S extends OP20 implements IOP20S {
89
57
  @method()
90
58
  @returns({ name: 'authority', type: ABIDataTypes.ADDRESS })
91
59
  public pegAuthority(_: Calldata): BytesWriter {
92
- const w = new BytesWriter(ADDRESS_BYTE_LENGTH);
93
- w.writeAddress(this._pegAuthority.value);
60
+ const w = new BytesWriter(32);
61
+ w.writeAddress(this._getPegAuthority());
94
62
  return w;
95
63
  }
96
64
 
97
65
  @method()
98
66
  @returns({ name: 'updatedAt', type: ABIDataTypes.UINT64 })
99
67
  public pegUpdatedAt(_: Calldata): BytesWriter {
100
- const w = new BytesWriter(U64_BYTE_LENGTH);
68
+ const w = new BytesWriter(8);
101
69
  w.writeU64(this._pegUpdatedAt.value.toU64());
102
70
  return w;
103
71
  }
@@ -105,7 +73,7 @@ export abstract class OP20S extends OP20 implements IOP20S {
105
73
  @method()
106
74
  @returns({ name: 'staleness', type: ABIDataTypes.UINT64 })
107
75
  public maxStaleness(_: Calldata): BytesWriter {
108
- const w = new BytesWriter(U64_BYTE_LENGTH);
76
+ const w = new BytesWriter(8);
109
77
  w.writeU64(this._maxStaleness.value.toU64());
110
78
  return w;
111
79
  }
@@ -119,74 +87,115 @@ export abstract class OP20S extends OP20 implements IOP20S {
119
87
  }
120
88
 
121
89
  @method({ name: 'newRate', type: ABIDataTypes.UINT256 })
90
+ @emit('PegRateUpdated')
122
91
  public updatePegRate(calldata: Calldata): BytesWriter {
123
- this.onlyPegAuthority();
92
+ this._onlyPegAuthority();
124
93
 
125
94
  const newRate = calldata.readU256();
126
95
  if (newRate.isZero()) {
127
96
  throw new Revert('Invalid peg rate');
128
97
  }
129
98
 
99
+ const oldRate = this._pegRate.value;
100
+ const blockNumber = Blockchain.block.number;
101
+
130
102
  this._pegRate.value = newRate;
131
- this._pegUpdatedAt.value = u256.fromU64(Blockchain.block.number);
103
+ this._pegUpdatedAt.value = u256.fromU64(blockNumber);
104
+
105
+ this.emitEvent(new PegRateUpdatedEvent(oldRate, newRate, blockNumber));
132
106
 
133
107
  return new BytesWriter(0);
134
108
  }
135
109
 
136
110
  @method({ name: 'newStaleness', type: ABIDataTypes.UINT64 })
111
+ @emit('MaxStalenessUpdated')
137
112
  public updateMaxStaleness(calldata: Calldata): BytesWriter {
138
- this.onlyPegAuthority();
113
+ this._onlyPegAuthority();
139
114
 
140
115
  const newStaleness = calldata.readU64();
141
- if (newStaleness === 0) {
116
+ if (newStaleness == 0) {
142
117
  throw new Revert('Invalid max staleness');
143
118
  }
144
119
 
120
+ const oldStaleness = this._maxStaleness.value.toU64();
145
121
  this._maxStaleness.value = u256.fromU64(newStaleness);
146
122
 
123
+ this.emitEvent(new MaxStalenessUpdatedEvent(oldStaleness, newStaleness));
124
+
147
125
  return new BytesWriter(0);
148
126
  }
149
127
 
150
128
  @method({ name: 'newAuthority', type: ABIDataTypes.ADDRESS })
129
+ @emit('PegAuthorityTransferStarted')
151
130
  public transferPegAuthority(calldata: Calldata): BytesWriter {
152
- this.onlyPegAuthority();
131
+ this._onlyPegAuthority();
153
132
 
154
133
  const newAuthority = calldata.readAddress();
155
- if (newAuthority === Address.zero()) {
134
+ if (newAuthority.equals(Address.zero())) {
156
135
  throw new Revert('Invalid new authority');
157
136
  }
158
137
 
159
- this._pendingAuthority.value = newAuthority;
138
+ const currentAuthority = this._getPegAuthority();
139
+ this._setPendingAuthority(newAuthority);
140
+
141
+ this.emitEvent(new PegAuthorityTransferStartedEvent(currentAuthority, newAuthority));
160
142
 
161
143
  return new BytesWriter(0);
162
144
  }
163
145
 
164
146
  @method()
147
+ @emit('PegAuthorityTransferred')
165
148
  public acceptPegAuthority(_: Calldata): BytesWriter {
166
- const pending = this._pendingAuthority.value;
167
- if (pending === Address.zero()) {
149
+ const pending = this._getPendingAuthority();
150
+ if (pending.equals(Address.zero())) {
168
151
  throw new Revert('No pending authority');
169
152
  }
170
153
  if (!Blockchain.tx.sender.equals(pending)) {
171
154
  throw new Revert('Not pending authority');
172
155
  }
173
156
 
174
- this._pegAuthority.value = pending;
175
- this._pendingAuthority.value = Address.zero();
157
+ const previousAuthority = this._getPegAuthority();
158
+ this._setPegAuthority(pending);
159
+ this._setPendingAuthority(Address.zero());
160
+
161
+ this.emitEvent(new PegAuthorityTransferredEvent(previousAuthority, pending));
176
162
 
177
163
  return new BytesWriter(0);
178
164
  }
179
165
 
180
166
  @method()
167
+ @emit('PegAuthorityRenounced')
181
168
  public renouncePegAuthority(_: Calldata): BytesWriter {
182
- this.onlyPegAuthority();
169
+ this._onlyPegAuthority();
170
+
171
+ const previousAuthority = this._getPegAuthority();
172
+ this._setPegAuthority(Address.zero());
173
+ this._setPendingAuthority(Address.zero());
183
174
 
184
- this._pegAuthority.value = Address.zero();
185
- this._pendingAuthority.value = Address.zero();
175
+ this.emitEvent(new PegAuthorityRenouncedEvent(previousAuthority));
186
176
 
187
177
  return new BytesWriter(0);
188
178
  }
189
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
+
190
199
  protected _isStale(): boolean {
191
200
  const currentBlock = Blockchain.block.number;
192
201
  const updatedAt = this._pegUpdatedAt.value.toU64();
@@ -201,19 +210,49 @@ export abstract class OP20S extends OP20 implements IOP20S {
201
210
  }
202
211
  }
203
212
 
204
- protected onlyPegAuthority(): void {
205
- if (!Blockchain.tx.sender.equals(this._pegAuthority.value)) {
213
+ protected _onlyPegAuthority(): void {
214
+ if (!Blockchain.tx.sender.equals(this._getPegAuthority())) {
206
215
  throw new Revert('Not peg authority');
207
216
  }
208
217
  }
209
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
+
210
249
  protected override isSelectorExcluded(selector: Selector): boolean {
211
250
  if (
212
- selector === PEG_RATE_SELECTOR ||
213
- selector === PEG_AUTHORITY_SELECTOR ||
214
- selector === PEG_UPDATED_AT_SELECTOR ||
215
- selector === MAX_STALENESS_SELECTOR ||
216
- selector === IS_STALE_SELECTOR
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
217
256
  ) {
218
257
  return true;
219
258
  }
@@ -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
@@ -19,6 +19,7 @@ export * from './interfaces/IBTC';
19
19
  /** Events */
20
20
  export * from './events/NetEvent';
21
21
  export * from './events/predefined';
22
+ export * from './events/op20s/OP20SEvents';
22
23
 
23
24
  /** Env */
24
25
  export * from './env/classes/UTXO';