@btc-vision/btc-runtime 1.11.0-rc.9 → 1.11.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 +7 -7
- package/docs/README.md +39 -39
- package/docs/advanced/bitcoin-scripts.md +17 -17
- package/docs/advanced/{contract-upgrades.md → contract-updates.md} +90 -98
- package/docs/advanced/cross-contract-calls.md +4 -4
- package/docs/advanced/plugins.md +21 -21
- package/docs/advanced/quantum-resistance.md +32 -32
- package/docs/advanced/signature-verification.md +22 -22
- package/docs/api-reference/blockchain.md +14 -14
- package/docs/api-reference/events.md +2 -2
- package/docs/api-reference/op20.md +7 -7
- package/docs/api-reference/op721.md +7 -7
- package/docs/api-reference/storage.md +2 -2
- package/docs/contracts/op-net-base.md +15 -15
- package/docs/contracts/op20-token.md +3 -3
- package/docs/contracts/op20s-signatures.md +2 -2
- package/docs/contracts/op721-nft.md +3 -3
- package/docs/contracts/reentrancy-guard.md +5 -7
- package/docs/contracts/updatable.md +384 -0
- package/docs/core-concepts/blockchain-environment.md +10 -10
- package/docs/core-concepts/decorators.md +5 -5
- package/docs/core-concepts/events.md +6 -6
- package/docs/core-concepts/pointers.md +5 -5
- package/docs/core-concepts/security.md +5 -5
- package/docs/core-concepts/storage-system.md +24 -24
- package/docs/examples/basic-token.md +8 -8
- package/docs/examples/nft-with-reservations.md +9 -9
- package/docs/examples/oracle-integration.md +13 -13
- package/docs/examples/stablecoin.md +10 -10
- package/docs/getting-started/first-contract.md +8 -8
- package/docs/getting-started/installation.md +2 -2
- package/docs/getting-started/project-structure.md +6 -6
- package/docs/storage/memory-maps.md +8 -8
- package/docs/storage/stored-arrays.md +6 -6
- package/docs/storage/stored-maps.md +8 -8
- package/docs/storage/stored-primitives.md +6 -6
- package/docs/types/address.md +13 -13
- package/docs/types/bytes-writer-reader.md +18 -18
- package/docs/types/calldata.md +12 -12
- package/package.json +10 -10
- package/runtime/constants/Exports.ts +0 -30
- package/runtime/contracts/OP20.ts +7 -7
- package/runtime/contracts/OP721.ts +60 -74
- package/runtime/contracts/OP_NET.ts +2 -2
- package/runtime/contracts/ReentrancyGuard.ts +1 -5
- package/runtime/contracts/Updatable.ts +241 -0
- package/runtime/contracts/interfaces/OP721InitParameters.ts +8 -8
- package/runtime/env/BlockchainEnvironment.ts +5 -5
- package/runtime/env/global.ts +7 -6
- package/runtime/events/predefined/{ApprovedEvent.ts → OP20ApprovedEvent.ts} +1 -1
- package/runtime/events/predefined/{BurnedEvent.ts → OP20BurnedEvent.ts} +1 -1
- package/runtime/events/predefined/{MintedEvent.ts → OP20MintedEvent.ts} +1 -1
- package/runtime/events/predefined/{TransferredEvent.ts → OP20TransferredEvent.ts} +1 -1
- package/runtime/events/predefined/OP721ApprovedEvent.ts +17 -0
- package/runtime/events/predefined/{ApprovedForAll.ts → OP721ApprovedForAllEvent.ts} +1 -1
- package/runtime/events/predefined/OP721BurnedEvent.ts +16 -0
- package/runtime/events/predefined/OP721MintedEvent.ts +16 -0
- package/runtime/events/predefined/OP721TransferredEvent.ts +18 -0
- package/runtime/events/predefined/index.ts +5 -5
- package/runtime/events/{upgradeable/UpgradeableEvents.ts → updatable/UpdatableEvents.ts} +9 -9
- package/runtime/hashing/keccak256.ts +1 -1
- package/runtime/index.ts +3 -5
- package/runtime/plugins/UpdatablePlugin.ts +276 -0
- package/runtime/script/Networks.ts +1 -1
- package/runtime/storage/StoredBoolean.ts +23 -12
- package/runtime/types/Address.ts +1 -1
- package/runtime/types/ExtendedAddress.ts +1 -1
- package/docs/contracts/upgradeable.md +0 -396
- package/runtime/contracts/Upgradeable.ts +0 -242
- package/runtime/contracts/interfaces/IOP1155.ts +0 -33
- package/runtime/contracts/interfaces/OP1155InitParameters.ts +0 -11
- package/runtime/plugins/UpgradeablePlugin.ts +0 -279
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
-
import { Blockchain } from '../env';
|
|
3
|
-
import { Plugin } from './Plugin';
|
|
4
|
-
import { StoredAddress } from '../storage/StoredAddress';
|
|
5
|
-
import { StoredU256 } from '../storage/StoredU256';
|
|
6
|
-
import { Address } from '../types/Address';
|
|
7
|
-
import { Revert } from '../types/Revert';
|
|
8
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
9
|
-
import { encodeSelector, Selector } from '../math/abi';
|
|
10
|
-
import { ADDRESS_BYTE_LENGTH } from '../utils';
|
|
11
|
-
import { Calldata } from '../types';
|
|
12
|
-
import { EMPTY_POINTER } from '../math/bytes';
|
|
13
|
-
import {
|
|
14
|
-
UpgradeAppliedEvent,
|
|
15
|
-
UpgradeCancelledEvent,
|
|
16
|
-
UpgradeSubmittedEvent,
|
|
17
|
-
} from '../events/upgradeable/UpgradeableEvents';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* UpgradeablePlugin - Plugin for upgradeable contracts with timelock protection.
|
|
21
|
-
*
|
|
22
|
-
* This plugin provides a secure upgrade mechanism with a configurable delay period.
|
|
23
|
-
* Unlike extending the Upgradeable base class, this plugin can be added to any contract.
|
|
24
|
-
*
|
|
25
|
-
* The pattern prevents instant malicious upgrades by requiring:
|
|
26
|
-
* 1. submitUpgrade() - Submit the source contract address, starts the timelock
|
|
27
|
-
* 2. Wait for the delay period to pass
|
|
28
|
-
* 3. applyUpgrade() - Apply the upgrade after the delay
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* @final
|
|
33
|
-
* export class MyContract extends OP_NET {
|
|
34
|
-
* public constructor() {
|
|
35
|
-
* super();
|
|
36
|
-
* // 144 blocks = ~24 hours
|
|
37
|
-
* this.registerPlugin(new UpgradeablePlugin(144));
|
|
38
|
-
* }
|
|
39
|
-
*
|
|
40
|
-
* // No need to modify execute() - the plugin handles upgrade methods automatically!
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export class UpgradeablePlugin extends Plugin {
|
|
45
|
-
private readonly _pendingUpgradeAddress: StoredAddress;
|
|
46
|
-
private readonly _pendingUpgradeBlock: StoredU256;
|
|
47
|
-
private readonly _upgradeDelay: u64;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Creates a new UpgradeablePlugin.
|
|
51
|
-
*
|
|
52
|
-
* @param upgradeDelay - Number of blocks to wait before upgrade can be applied.
|
|
53
|
-
* Default: 144 blocks (~24 hours)
|
|
54
|
-
* Common values:
|
|
55
|
-
* - 6 blocks = ~1 hour
|
|
56
|
-
* - 144 blocks = ~24 hours
|
|
57
|
-
* - 1008 blocks = ~1 week
|
|
58
|
-
* @param addressPointer - Storage pointer for pending upgrade address
|
|
59
|
-
* @param blockPointer - Storage pointer for pending upgrade block
|
|
60
|
-
*/
|
|
61
|
-
public constructor(
|
|
62
|
-
upgradeDelay: u64 = 144,
|
|
63
|
-
addressPointer: u16 = Blockchain.nextPointer,
|
|
64
|
-
blockPointer: u16 = Blockchain.nextPointer,
|
|
65
|
-
) {
|
|
66
|
-
super();
|
|
67
|
-
this._upgradeDelay = upgradeDelay;
|
|
68
|
-
this._pendingUpgradeAddress = new StoredAddress(addressPointer);
|
|
69
|
-
this._pendingUpgradeBlock = new StoredU256(blockPointer, EMPTY_POINTER);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Method selectors
|
|
73
|
-
public static get SUBMIT_UPGRADE_SELECTOR(): Selector {
|
|
74
|
-
return encodeSelector('submitUpgrade(address)');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public static get APPLY_UPGRADE_SELECTOR(): Selector {
|
|
78
|
-
return encodeSelector('applyUpgrade(address)');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
public static get CANCEL_UPGRADE_SELECTOR(): Selector {
|
|
82
|
-
return encodeSelector('cancelUpgrade()');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public static get PENDING_UPGRADE_SELECTOR(): Selector {
|
|
86
|
-
return encodeSelector('pendingUpgrade()');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public static get UPGRADE_DELAY_SELECTOR(): Selector {
|
|
90
|
-
return encodeSelector('upgradeDelay()');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Returns the pending upgrade source address.
|
|
95
|
-
*/
|
|
96
|
-
public get pendingUpgradeAddress(): Address {
|
|
97
|
-
return this._pendingUpgradeAddress.value;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Returns the block number when the pending upgrade was submitted.
|
|
102
|
-
*/
|
|
103
|
-
public get pendingUpgradeBlock(): u64 {
|
|
104
|
-
return this._pendingUpgradeBlock.value.lo1;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Returns the configured upgrade delay in blocks.
|
|
109
|
-
*/
|
|
110
|
-
public get upgradeDelay(): u64 {
|
|
111
|
-
return this._upgradeDelay;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Returns the block number when the pending upgrade can be applied.
|
|
116
|
-
*/
|
|
117
|
-
public get upgradeEffectiveBlock(): u64 {
|
|
118
|
-
const submitBlock = this.pendingUpgradeBlock;
|
|
119
|
-
if (submitBlock === 0) return 0;
|
|
120
|
-
return submitBlock + this._upgradeDelay;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Returns true if there is a pending upgrade.
|
|
125
|
-
*/
|
|
126
|
-
public get hasPendingUpgrade(): bool {
|
|
127
|
-
return this.pendingUpgradeBlock !== 0;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Returns true if the pending upgrade can be applied (delay has passed).
|
|
132
|
-
*/
|
|
133
|
-
public get canApplyUpgrade(): bool {
|
|
134
|
-
if (!this.hasPendingUpgrade) return false;
|
|
135
|
-
return Blockchain.block.number >= this.upgradeEffectiveBlock;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Attempts to execute an upgrade-related method.
|
|
140
|
-
* Returns the response if the method was handled, or null if not.
|
|
141
|
-
*
|
|
142
|
-
* @param method - The method selector
|
|
143
|
-
* @param calldata - The calldata
|
|
144
|
-
* @returns BytesWriter response if handled, null otherwise
|
|
145
|
-
*/
|
|
146
|
-
public override execute(method: Selector, calldata: Calldata): BytesWriter | null {
|
|
147
|
-
switch (method) {
|
|
148
|
-
case UpgradeablePlugin.SUBMIT_UPGRADE_SELECTOR:
|
|
149
|
-
return this.submitUpgrade(calldata);
|
|
150
|
-
case UpgradeablePlugin.APPLY_UPGRADE_SELECTOR:
|
|
151
|
-
return this.applyUpgrade(calldata);
|
|
152
|
-
case UpgradeablePlugin.CANCEL_UPGRADE_SELECTOR:
|
|
153
|
-
return this.cancelUpgrade();
|
|
154
|
-
case UpgradeablePlugin.PENDING_UPGRADE_SELECTOR:
|
|
155
|
-
return this.getPendingUpgrade();
|
|
156
|
-
case UpgradeablePlugin.UPGRADE_DELAY_SELECTOR:
|
|
157
|
-
return this.getUpgradeDelay();
|
|
158
|
-
default:
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Submits an upgrade for timelock.
|
|
165
|
-
*/
|
|
166
|
-
private submitUpgrade(calldata: Calldata): BytesWriter {
|
|
167
|
-
this.onlyDeployer();
|
|
168
|
-
|
|
169
|
-
if (this.hasPendingUpgrade) {
|
|
170
|
-
throw new Revert('Upgrade already pending. Cancel first.');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const sourceAddress = calldata.readAddress();
|
|
174
|
-
|
|
175
|
-
if (!Blockchain.isContract(sourceAddress)) {
|
|
176
|
-
throw new Revert('Source must be a deployed contract');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const currentBlock = Blockchain.block.number;
|
|
180
|
-
this._pendingUpgradeAddress.value = sourceAddress;
|
|
181
|
-
this._pendingUpgradeBlock.value = u256.fromU64(currentBlock);
|
|
182
|
-
|
|
183
|
-
const effectiveBlock = currentBlock + this._upgradeDelay;
|
|
184
|
-
Blockchain.emit(new UpgradeSubmittedEvent(sourceAddress, currentBlock, effectiveBlock));
|
|
185
|
-
|
|
186
|
-
return new BytesWriter(0);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Applies a pending upgrade after the timelock period has passed.
|
|
191
|
-
* Any remaining calldata after the source address is passed to onUpdate.
|
|
192
|
-
*/
|
|
193
|
-
private applyUpgrade(calldata: Calldata): BytesWriter {
|
|
194
|
-
this.onlyDeployer();
|
|
195
|
-
|
|
196
|
-
if (!this.hasPendingUpgrade) {
|
|
197
|
-
throw new Revert('No pending upgrade');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (!this.canApplyUpgrade) {
|
|
201
|
-
throw new Revert('Upgrade delay not elapsed');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const sourceAddress = calldata.readAddress();
|
|
205
|
-
const pendingAddress = this._pendingUpgradeAddress.value;
|
|
206
|
-
|
|
207
|
-
if (!sourceAddress.equals(pendingAddress)) {
|
|
208
|
-
throw new Revert('Address does not match pending upgrade');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Clear pending state before upgrade
|
|
212
|
-
this._pendingUpgradeAddress.value = Address.zero();
|
|
213
|
-
this._pendingUpgradeBlock.value = u256.Zero;
|
|
214
|
-
|
|
215
|
-
Blockchain.emit(new UpgradeAppliedEvent(sourceAddress, Blockchain.block.number));
|
|
216
|
-
|
|
217
|
-
// Extract remaining calldata for onUpdate
|
|
218
|
-
const remainingLength = calldata.byteLength - calldata.getOffset();
|
|
219
|
-
const updateCalldata = new BytesWriter(remainingLength);
|
|
220
|
-
if (remainingLength > 0) {
|
|
221
|
-
const remainingBytes = calldata.readBytes(remainingLength);
|
|
222
|
-
updateCalldata.writeBytes(remainingBytes);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Perform upgrade - new bytecode takes effect next block
|
|
226
|
-
Blockchain.updateContractFromExisting(sourceAddress, updateCalldata);
|
|
227
|
-
|
|
228
|
-
return new BytesWriter(0);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Cancels a pending upgrade.
|
|
233
|
-
*/
|
|
234
|
-
private cancelUpgrade(): BytesWriter {
|
|
235
|
-
this.onlyDeployer();
|
|
236
|
-
|
|
237
|
-
if (!this.hasPendingUpgrade) {
|
|
238
|
-
throw new Revert('No pending upgrade');
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const pendingAddress = this._pendingUpgradeAddress.value;
|
|
242
|
-
|
|
243
|
-
this._pendingUpgradeAddress.value = Address.zero();
|
|
244
|
-
this._pendingUpgradeBlock.value = u256.Zero;
|
|
245
|
-
|
|
246
|
-
Blockchain.emit(new UpgradeCancelledEvent(pendingAddress, Blockchain.block.number));
|
|
247
|
-
|
|
248
|
-
return new BytesWriter(0);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Returns the pending upgrade info.
|
|
253
|
-
*/
|
|
254
|
-
private getPendingUpgrade(): BytesWriter {
|
|
255
|
-
const response = new BytesWriter(ADDRESS_BYTE_LENGTH + 16);
|
|
256
|
-
response.writeAddress(this._pendingUpgradeAddress.value);
|
|
257
|
-
response.writeU64(this.pendingUpgradeBlock);
|
|
258
|
-
response.writeU64(this.upgradeEffectiveBlock);
|
|
259
|
-
return response;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Returns the upgrade delay.
|
|
264
|
-
*/
|
|
265
|
-
private getUpgradeDelay(): BytesWriter {
|
|
266
|
-
const response = new BytesWriter(8);
|
|
267
|
-
response.writeU64(this._upgradeDelay);
|
|
268
|
-
return response;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Validates that the caller is the contract deployer.
|
|
273
|
-
*/
|
|
274
|
-
private onlyDeployer(): void {
|
|
275
|
-
if (Blockchain.contractDeployer !== Blockchain.tx.sender) {
|
|
276
|
-
throw new Revert('Only deployer can call this method');
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|