@btc-vision/btc-runtime 1.1.2 → 1.1.3
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 +8 -7
- package/README.md +157 -5
- package/package.json +1 -1
- package/runtime/contracts/DeployableOP_20.ts +11 -11
- package/runtime/contracts/OP_NET.ts +15 -10
- package/runtime/env/BTCEnvironment.ts +19 -18
- package/runtime/storage/StoredU256.ts +3 -1
package/LICENSE.md
CHANGED
|
@@ -10,22 +10,23 @@
|
|
|
10
10
|
|
|
11
11
|
## 2. Grant of License
|
|
12
12
|
|
|
13
|
-
This License permits User to view the Software via the repository hosting the
|
|
14
|
-
provided in this Section, no other use
|
|
15
|
-
|
|
13
|
+
This License permits User to view the Software via the repository hosting the
|
|
14
|
+
Software ("Hosting Service"). Except as provided in this Section, no other use
|
|
15
|
+
of the Software is permitted. The User may not copy, republish, or distribute the Software in any way.
|
|
16
16
|
|
|
17
17
|
## 3. Restrictions
|
|
18
18
|
|
|
19
|
-
- **Modification and Distribution**: User is prohibited from modifying, merging, distributing, sublicensing, and/or
|
|
20
|
-
selling copies of the Software.
|
|
21
19
|
- **Commercial Use**: User is prohibited from using the Software for any commercial purposes.
|
|
22
|
-
- **
|
|
20
|
+
- **Claim of Ownership**: User acknowledges that the Software is the property of the Licensor and that they do not have
|
|
21
|
+
any ownership rights to the Software.
|
|
23
22
|
|
|
24
23
|
## 4. Termination
|
|
25
24
|
|
|
26
25
|
This License is effective until terminated by the Licensor. It will terminate immediately without notice from the
|
|
27
26
|
Licensor if User fails to comply with any provision of this License. Upon termination, User must destroy all copies of
|
|
28
|
-
the Software.
|
|
27
|
+
the Software. This License will also terminate if the User attempts to circumvent the restrictions set forth in Section
|
|
28
|
+
|
|
29
|
+
3.
|
|
29
30
|
|
|
30
31
|
## 5. Copyright Notice
|
|
31
32
|
|
package/README.md
CHANGED
|
@@ -9,12 +9,37 @@
|
|
|
9
9
|
|
|
10
10
|
[](https://github.com/prettier/prettier)
|
|
11
11
|
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
1. [Introduction](#introduction)
|
|
15
|
+
2. [Installation](#installation)
|
|
16
|
+
3. [Core Concepts](#core-concepts)
|
|
17
|
+
- [Blockchain Environment](#blockchain-environment)
|
|
18
|
+
- [Contracts](#contracts)
|
|
19
|
+
- [Events](#events)
|
|
20
|
+
- [Pointers and Storage Management](#pointers-and-storage-management)
|
|
21
|
+
4. [Usage Examples](#usage-examples)
|
|
22
|
+
5. [Advanced Topics](#advanced-topics)
|
|
23
|
+
6. [Additional Documentation](#additional-documentation)
|
|
24
|
+
7. [License](#license)
|
|
25
|
+
|
|
12
26
|
## Introduction
|
|
13
27
|
|
|
14
|
-
The OPNet Smart Contract Runtime
|
|
15
|
-
L1.
|
|
28
|
+
The OPNet Smart Contract Runtime provides the foundational components required for creating smart contracts on Bitcoin
|
|
29
|
+
Layer 1 (L1). Written in AssemblyScript, this runtime allows developers to leverage WebAssembly for efficient contract
|
|
30
|
+
execution while integrating deeply with Bitcoin's decentralized architecture.
|
|
31
|
+
|
|
32
|
+
### Features
|
|
16
33
|
|
|
17
|
-
|
|
34
|
+
- **AssemblyScript and WebAssembly:** Efficient and high-performance contract execution using WebAssembly.
|
|
35
|
+
- **Bitcoin Integration:** Direct interaction with Bitcoin L1, enabling the creation of decentralized applications that
|
|
36
|
+
operate on the Bitcoin network.
|
|
37
|
+
- **Comprehensive Storage Management:** Flexible and secure storage management using primary pointers and sub-pointers,
|
|
38
|
+
ensuring data integrity through cryptographic proofs.
|
|
39
|
+
- **Event Handling:** Sophisticated event system for contract state changes, allowing easy tracking and logging of
|
|
40
|
+
contract activities.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
18
43
|
|
|
19
44
|
1. Clone the repository:
|
|
20
45
|
```bash
|
|
@@ -26,9 +51,136 @@ L1. The runtime is written in AssemblyScript.
|
|
|
26
51
|
```
|
|
27
52
|
3. Install the necessary dependencies:
|
|
28
53
|
```bash
|
|
29
|
-
npm
|
|
54
|
+
npm install
|
|
30
55
|
```
|
|
31
56
|
|
|
57
|
+
## Core Concepts
|
|
58
|
+
|
|
59
|
+
### Blockchain Environment
|
|
60
|
+
|
|
61
|
+
The `Blockchain` object environment is the backbone of the OPNet runtime, providing essential functionality for
|
|
62
|
+
interacting with the blockchain, such as managing contract states, handling transactions, and emitting events.
|
|
63
|
+
|
|
64
|
+
For more detailed information, see the [Blockchain.md](docs/Blockchain.md) documentation.
|
|
65
|
+
|
|
66
|
+
### Contracts
|
|
67
|
+
|
|
68
|
+
Contracts in OPNet are AssemblyScript classes that extend the `OP_NET` base class. The constructor pattern differs from
|
|
69
|
+
Solidity's, as it runs every time a contract is instantiated, so developers should not use the constructor for
|
|
70
|
+
persistent initialization.
|
|
71
|
+
|
|
72
|
+
For a detailed guide on how to structure contracts, refer to the [Contract.md](docs/Contract.md) documentation.
|
|
73
|
+
|
|
74
|
+
### Events
|
|
75
|
+
|
|
76
|
+
Events in OPNet allow contracts to emit signals that external observers can listen to. They are crucial for tracking
|
|
77
|
+
state changes and interactions within the contract.
|
|
78
|
+
|
|
79
|
+
For a comprehensive explanation on how to define and use events, refer to the [Events.md](docs/Events.md) documentation.
|
|
80
|
+
|
|
81
|
+
### Pointers and Storage Management
|
|
82
|
+
|
|
83
|
+
Storage in OPNet is managed using a combination of pointers (`u16`) and sub-pointers (`u256`). These are encoded and
|
|
84
|
+
hashed to generate unique storage locations that are secure and verifiable. This approach ensures that the data stored
|
|
85
|
+
is tamper-proof and can be efficiently accessed.
|
|
86
|
+
|
|
87
|
+
For more details on pointers and storage management, see the [Pointers.md](docs/Pointers.md)
|
|
88
|
+
and [Storage.md](docs/Storage.md) documentation.
|
|
89
|
+
|
|
90
|
+
## Usage Examples
|
|
91
|
+
|
|
92
|
+
### Creating a Basic Token Contract
|
|
93
|
+
|
|
94
|
+
Here is a real-world example of how to create a basic token contract using the OPNet Smart Contract Runtime. This
|
|
95
|
+
contract follows the OP20 standard.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { u128, u256 } from 'as-bignum/assembly';
|
|
99
|
+
import {
|
|
100
|
+
Address, Blockchain,
|
|
101
|
+
BytesWriter,
|
|
102
|
+
Calldata,
|
|
103
|
+
encodeSelector,
|
|
104
|
+
Map,
|
|
105
|
+
OP20InitParameters,
|
|
106
|
+
Selector,
|
|
107
|
+
} from '@btc-vision/btc-runtime/runtime';
|
|
108
|
+
import { DeployableOP_20 } from '@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20';
|
|
109
|
+
|
|
110
|
+
@final
|
|
111
|
+
export class MyToken extends DeployableOP_20 {
|
|
112
|
+
constructor() {
|
|
113
|
+
super();
|
|
114
|
+
|
|
115
|
+
// DO NOT USE TO DEFINE VARIABLE THAT ARE NOT CONSTANT. SEE "solidityLikeConstructor" BELOW.
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// "solidityLikeConstructor" This is a solidity-like constructor. This method will only run once.
|
|
119
|
+
public onInstantiated(): void {
|
|
120
|
+
if (!this.isInstantiated) {
|
|
121
|
+
super.onInstantiated(); // IMPORTANT.
|
|
122
|
+
|
|
123
|
+
const maxSupply: u256 = u128.fromString('100000000000000000000000000').toU256(); // Your max supply.
|
|
124
|
+
const decimals: u8 = 18; // Your decimals.
|
|
125
|
+
const name: string = 'MyToken'; // Your token name.
|
|
126
|
+
const symbol: string = 'TOKEN'; // Your token symbol.
|
|
127
|
+
|
|
128
|
+
this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
|
|
129
|
+
|
|
130
|
+
// Add your logic here. Eg, minting the initial supply:
|
|
131
|
+
// this._mint(Blockchain.origin, maxSupply);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public override callMethod(method: Selector, calldata: Calldata): BytesWriter {
|
|
136
|
+
switch (method) {
|
|
137
|
+
default:
|
|
138
|
+
return super.callMethod(method, calldata);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Emitting Events
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
class MyContract extends OP_NET {
|
|
148
|
+
public someAction(): void {
|
|
149
|
+
const event = new CustomEvent(Blockchain.sender, u256.fromU32(100));
|
|
150
|
+
this.emitEvent(event);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Advanced Topics
|
|
156
|
+
|
|
157
|
+
### Storage Management with Cryptographic Proofs
|
|
158
|
+
|
|
159
|
+
Storage pointers and sub-pointers are encoded and hashed to create unique and secure storage locations. These storage
|
|
160
|
+
locations are managed using the `Blockchain` class's `setStorageAt` and `getStorageAt` methods, ensuring data integrity
|
|
161
|
+
and preventing tampering.
|
|
162
|
+
|
|
163
|
+
### Using Serializable Data Structures
|
|
164
|
+
|
|
165
|
+
For complex data types, the `Serializable` class allows you to manage and persist data structures across multiple
|
|
166
|
+
storage slots.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
class ComplexData extends Serializable {
|
|
170
|
+
// Implementation
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Additional Documentation
|
|
175
|
+
|
|
176
|
+
For more detailed explanations on specific topics, refer to the individual documentation files:
|
|
177
|
+
|
|
178
|
+
- [Blockchain.md](docs/Blockchain.md)
|
|
179
|
+
- [Contract.md](docs/Contract.md)
|
|
180
|
+
- [Events.md](docs/Events.md)
|
|
181
|
+
- [Pointers.md](docs/Pointers.md)
|
|
182
|
+
- [Storage.md](docs/Storage.md)
|
|
183
|
+
|
|
32
184
|
## License
|
|
33
185
|
|
|
34
|
-
View the license
|
|
186
|
+
This project is licensed under the MIT License. View the full license [here](LICENSE.md).
|
package/package.json
CHANGED
|
@@ -33,7 +33,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
33
33
|
protected readonly _name: StoredString;
|
|
34
34
|
protected readonly _symbol: StoredString;
|
|
35
35
|
|
|
36
|
-
protected constructor(params
|
|
36
|
+
protected constructor(params: OP20InitParameters | null = null) {
|
|
37
37
|
super();
|
|
38
38
|
|
|
39
39
|
this.allowanceMap = new MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>(
|
|
@@ -90,12 +90,12 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
public instantiate(params: OP20InitParameters, skipOwnerVerification: boolean = false): void {
|
|
93
|
-
if (!skipOwnerVerification) this.onlyOwner(Blockchain.origin());
|
|
94
|
-
|
|
95
93
|
if (!this._maxSupply.value.isZero()) {
|
|
96
94
|
throw new Revert('Already initialized');
|
|
97
95
|
}
|
|
98
96
|
|
|
97
|
+
if (!skipOwnerVerification) this.onlyOwner(Blockchain.origin);
|
|
98
|
+
|
|
99
99
|
if (params.decimals > 32) {
|
|
100
100
|
throw new Revert('Decimals can not be more than 32');
|
|
101
101
|
}
|
|
@@ -125,7 +125,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
125
125
|
const resp = this._approve(spender, value);
|
|
126
126
|
response.writeBoolean(resp);
|
|
127
127
|
|
|
128
|
-
this.createApproveEvent(Blockchain.origin
|
|
128
|
+
this.createApproveEvent(Blockchain.origin, spender, value);
|
|
129
129
|
|
|
130
130
|
return response;
|
|
131
131
|
}
|
|
@@ -234,7 +234,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
protected _approve(spender: Address, value: u256): boolean {
|
|
237
|
-
const callee = Blockchain.origin
|
|
237
|
+
const callee = Blockchain.origin;
|
|
238
238
|
|
|
239
239
|
const senderMap = this.allowanceMap.get(callee);
|
|
240
240
|
senderMap.set(spender, value);
|
|
@@ -254,8 +254,8 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
254
254
|
throw new Revert(`No tokens`);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
const callee = Blockchain.origin
|
|
258
|
-
const caller = Blockchain.sender
|
|
257
|
+
const callee = Blockchain.origin;
|
|
258
|
+
const caller = Blockchain.sender;
|
|
259
259
|
|
|
260
260
|
if (onlyOwner) this.onlyOwner(callee); // only indexers can burn tokens
|
|
261
261
|
|
|
@@ -276,7 +276,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
protected _mint(to: Address, value: u256, onlyOwner: boolean = true): boolean {
|
|
279
|
-
const callee = Blockchain.origin
|
|
279
|
+
const callee = Blockchain.origin;
|
|
280
280
|
|
|
281
281
|
if (onlyOwner) this.onlyOwner(callee);
|
|
282
282
|
|
|
@@ -299,7 +299,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
protected _transfer(to: string, value: u256): boolean {
|
|
302
|
-
const caller = Blockchain.origin
|
|
302
|
+
const caller = Blockchain.origin;
|
|
303
303
|
|
|
304
304
|
if (!this.balanceOfMap.has(caller)) throw new Revert();
|
|
305
305
|
if (this.isSelf(caller)) throw new Revert('Can not transfer from self account');
|
|
@@ -355,8 +355,8 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
protected _transferFrom(from: Address, to: Address, value: u256): boolean {
|
|
358
|
-
const spender = Blockchain.origin
|
|
359
|
-
if (Blockchain.sender
|
|
358
|
+
const spender = Blockchain.origin;
|
|
359
|
+
if (Blockchain.sender !== from) {
|
|
360
360
|
throw new Revert('Not caller.');
|
|
361
361
|
}
|
|
362
362
|
|
|
@@ -9,14 +9,12 @@ import { MAX_EVENT_DATA_SIZE, NetEvent } from '../events/NetEvent';
|
|
|
9
9
|
import { StoredBoolean } from '../storage/StoredBoolean';
|
|
10
10
|
|
|
11
11
|
export class OP_NET implements IBTC {
|
|
12
|
-
|
|
12
|
+
protected readonly instantiated: StoredBoolean = new StoredBoolean(
|
|
13
|
+
Blockchain.nextPointer,
|
|
14
|
+
false,
|
|
15
|
+
);
|
|
13
16
|
|
|
14
|
-
constructor() {
|
|
15
|
-
if (!this.instantiated.value) {
|
|
16
|
-
this.instantiated.value = true;
|
|
17
|
-
this.onContractInstantiate();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
17
|
+
constructor() {}
|
|
20
18
|
|
|
21
19
|
public get address(): string {
|
|
22
20
|
return Blockchain.contractAddress;
|
|
@@ -26,6 +24,16 @@ export class OP_NET implements IBTC {
|
|
|
26
24
|
return Blockchain.owner;
|
|
27
25
|
}
|
|
28
26
|
|
|
27
|
+
public get isInstantiated(): bool {
|
|
28
|
+
return this.instantiated.value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public onInstantiated(): void {
|
|
32
|
+
if (!this.isInstantiated) {
|
|
33
|
+
this.instantiated.value = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
public callMethod(method: Selector, _calldata: Calldata): BytesWriter {
|
|
30
38
|
switch (method) {
|
|
31
39
|
default:
|
|
@@ -33,9 +41,6 @@ export class OP_NET implements IBTC {
|
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
// Overwrite this method in your contract
|
|
37
|
-
public onContractInstantiate(): void {}
|
|
38
|
-
|
|
39
44
|
public callView(method: Selector): BytesWriter {
|
|
40
45
|
const response = new BytesWriter();
|
|
41
46
|
|
|
@@ -31,12 +31,29 @@ export class BlockchainEnvironment {
|
|
|
31
31
|
|
|
32
32
|
private storage: PointerStorage = new MapU256();
|
|
33
33
|
private events: NetEvent[] = [];
|
|
34
|
+
private currentBlock: u256 = u256.Zero;
|
|
35
|
+
|
|
36
|
+
constructor() {}
|
|
34
37
|
|
|
35
38
|
private _origin: PotentialAddress = null;
|
|
39
|
+
|
|
40
|
+
public get origin(): Address {
|
|
41
|
+
if (!this._origin) {
|
|
42
|
+
throw this.error('Callee is required');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this._origin as Address;
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
private _sender: PotentialAddress = null;
|
|
37
|
-
private currentBlock: u256 = u256.Zero;
|
|
38
49
|
|
|
39
|
-
|
|
50
|
+
public get sender(): Address {
|
|
51
|
+
if (!this._sender) {
|
|
52
|
+
throw this.error('Caller is required');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this._sender as Address;
|
|
56
|
+
}
|
|
40
57
|
|
|
41
58
|
private _timestamp: u64 = 0;
|
|
42
59
|
|
|
@@ -98,22 +115,6 @@ export class BlockchainEnvironment {
|
|
|
98
115
|
return this.currentBlock.toU64();
|
|
99
116
|
}
|
|
100
117
|
|
|
101
|
-
public origin(): Address {
|
|
102
|
-
if (!this._origin) {
|
|
103
|
-
throw this.error('Callee is required');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return this._origin as Address;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public sender(): Address {
|
|
110
|
-
if (!this._sender) {
|
|
111
|
-
throw this.error('Caller is required');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return this._sender as Address;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
118
|
public setEnvironment(data: Uint8Array): void {
|
|
118
119
|
const reader: BytesReader = new BytesReader(data);
|
|
119
120
|
|