@btc-vision/btc-runtime 1.2.5 → 1.3.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.
Files changed (39) hide show
  1. package/README.md +73 -37
  2. package/package.json +7 -4
  3. package/runtime/buffer/BytesReader.ts +11 -6
  4. package/runtime/buffer/BytesWriter.ts +9 -17
  5. package/runtime/contracts/DeployableOP_20.ts +4 -16
  6. package/runtime/contracts/OP_NET.ts +2 -2
  7. package/runtime/contracts/interfaces/IOP_20.ts +0 -2
  8. package/runtime/env/BlockchainEnvironment.ts +17 -23
  9. package/runtime/generic/AddressMap.ts +62 -0
  10. package/runtime/generic/Map.ts +9 -8
  11. package/runtime/index.ts +18 -4
  12. package/runtime/math/abi.ts +1 -19
  13. package/runtime/memory/AddressMemoryMap.ts +23 -9
  14. package/runtime/memory/KeyMerger.ts +13 -4
  15. package/runtime/memory/MultiAddressMemoryMap.ts +7 -7
  16. package/runtime/memory/MultiStringMemoryMap.ts +62 -0
  17. package/runtime/memory/StringMemoryMap.ts +57 -0
  18. package/runtime/memory/Uint8ArrayMerger.ts +67 -0
  19. package/runtime/secp256k1/ECPoint.ts +121 -0
  20. package/runtime/storage/Serializable.ts +19 -9
  21. package/runtime/storage/StorageBacked.ts +5 -0
  22. package/runtime/storage/StorageLayout.ts +7 -0
  23. package/runtime/storage/StorageSlot.ts +106 -0
  24. package/runtime/storage/StorageStruct.ts +23 -0
  25. package/runtime/storage/StorageValue.ts +36 -0
  26. package/runtime/storage/StoredAddress.ts +47 -0
  27. package/runtime/storage/StoredBoolean.ts +8 -5
  28. package/runtime/storage/StoredString.ts +12 -6
  29. package/runtime/storage/StoredU256.ts +51 -15
  30. package/runtime/tests/assert.ts +6 -3
  31. package/runtime/tests/env.ts +2 -2
  32. package/runtime/tests/tests.ts +18 -16
  33. package/runtime/types/Address.ts +121 -2
  34. package/runtime/types/SafeMath.ts +24 -0
  35. package/runtime/utils/b32.ts +243 -0
  36. package/runtime/utils/box.ts +126 -107
  37. package/runtime/utils/encodings.ts +46 -0
  38. package/runtime/utils/hex.ts +50 -47
  39. package/runtime/utils/index.ts +3 -2
package/README.md CHANGED
@@ -42,17 +42,17 @@ execution while integrating deeply with Bitcoin's decentralized architecture.
42
42
  ## Installation
43
43
 
44
44
  1. Clone the repository:
45
- ```bash
46
- git clone https://github.com/btc-vision/btc-runtime.git
47
- ```
45
+ ```bash
46
+ git clone https://github.com/btc-vision/btc-runtime.git
47
+ ```
48
48
  2. Navigate to the repository directory:
49
- ```bash
50
- cd btc-runtime
51
- ```
49
+ ```bash
50
+ cd btc-runtime
51
+ ```
52
52
  3. Install the necessary dependencies:
53
- ```bash
54
- npm install
55
- ```
53
+ ```bash
54
+ npm install
55
+ ```
56
56
 
57
57
  ## Core Concepts
58
58
 
@@ -95,59 +95,95 @@ Here is a real-world example of how to create a basic token contract using the O
95
95
  contract follows the OP20 standard.
96
96
 
97
97
  ```typescript
98
- import { u128, u256 } from 'as-bignum/assembly';
99
98
  import {
100
- Address, Blockchain,
99
+ Address,
100
+ Blockchain,
101
101
  BytesWriter,
102
102
  Calldata,
103
+ DeployableOP_20,
103
104
  encodeSelector,
104
105
  Map,
105
106
  OP20InitParameters,
106
107
  Selector,
108
+ AddressMap
107
109
  } from '@btc-vision/btc-runtime/runtime';
108
- import { DeployableOP_20 } from '@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20';
110
+ import { u128, u256 } from 'as-bignum/assembly';
109
111
 
110
112
  @final
111
113
  export class MyToken extends DeployableOP_20 {
112
- constructor() {
114
+ public constructor() {
113
115
  super();
114
116
 
115
- // DO NOT USE TO DEFINE VARIABLE THAT ARE NOT CONSTANT. SEE "solidityLikeConstructor" BELOW.
117
+ // IMPORTANT. THIS WILL RUN EVERYTIME THE CONTRACT IS INTERACTED WITH. FOR SPECIFIC INITIALIZATION, USE "onDeployment" METHOD.
116
118
  }
117
119
 
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.
120
+ // "solidityLikeConstructor" This is a solidity-like constructor. This method will only run once when the contract is deployed.
121
+ public override onDeployment(_calldata: Calldata): void {
122
+ const maxSupply: u256 = u128.fromString('100000000000000000000000000').toU256(); // Your max supply.
123
+ const decimals: u8 = 18; // Your decimals.
124
+ const name: string = 'MyToken'; // Your token name.
125
+ const symbol: string = 'TOKEN'; // Your token symbol.
127
126
 
128
- this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
127
+ this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
129
128
 
130
- // Add your logic here. Eg, minting the initial supply:
131
- // this._mint(Blockchain.origin, maxSupply);
132
- }
129
+ // Add your logic here. Eg, minting the initial supply:
130
+ this._mint(Blockchain.tx.origin, maxSupply);
133
131
  }
134
132
 
135
- public override callMethod(method: Selector, calldata: Calldata): BytesWriter {
133
+ public override execute(method: Selector, calldata: Calldata): BytesWriter {
136
134
  switch (method) {
135
+ case encodeSelector('airdrop'):
136
+ return this.airdrop(calldata);
137
+ case encodeSelector('airdropWithAmount'):
138
+ return this.airdropWithAmount(calldata);
137
139
  default:
138
- return super.callMethod(method, calldata);
140
+ return super.execute(method, calldata);
139
141
  }
140
142
  }
141
- }
142
- ```
143
143
 
144
- ### Emitting Events
144
+ private airdrop(calldata: Calldata): BytesWriter {
145
+ this.onlyOwner(Blockchain.tx.sender);
145
146
 
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);
147
+ const drops: AddressMap<u256> = calldata.readAddressValueTuple();
148
+
149
+ const addresses: Address[] = drops.keys();
150
+ for (let i: i32 = 0; i < addresses.length; i++) {
151
+ const address = addresses[i];
152
+ const amount = drops.get(address);
153
+
154
+ this._mint(address, amount, false);
155
+ }
156
+
157
+ const writer: BytesWriter = new BytesWriter(1);
158
+ writer.writeBoolean(true);
159
+
160
+ return writer;
161
+ }
162
+
163
+ private _optimizedMint(address: Address, amount: u256): void {
164
+ this.balanceOfMap.set(address, amount);
165
+
166
+ this._totalSupply.addNoCommit(amount);
167
+
168
+ this.createMintEvent(address, amount);
169
+ }
170
+
171
+ private airdropWithAmount(calldata: Calldata): BytesWriter {
172
+ this.onlyOwner(Blockchain.tx.sender);
173
+
174
+ const amount: u256 = calldata.readU256();
175
+ const addresses: Address[] = calldata.readAddressArray();
176
+
177
+ for (let i: i32 = 0; i < addresses.length; i++) {
178
+ this._optimizedMint(addresses[i], amount);
179
+ }
180
+
181
+ this._totalSupply.commit();
182
+
183
+ const writer: BytesWriter = new BytesWriter(1);
184
+ writer.writeBoolean(true);
185
+
186
+ return writer;
151
187
  }
152
188
  }
153
189
  ```
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@btc-vision/btc-runtime",
3
- "version": "1.2.5",
3
+ "version": "1.3.0",
4
4
  "description": "Bitcoin Smart Contract Runtime",
5
5
  "main": "btc/index.ts",
6
6
  "scripts": {
7
- "build": "cross-env node scripts/asc tests/tests.ts"
7
+ "build": "cross-env node scripts/asc tests/tests.ts",
8
+ "test": "ts-mocha tests/**/*.spec.ts"
8
9
  },
9
10
  "types": "btc/index.ts",
10
11
  "keywords": [
@@ -20,7 +21,7 @@
20
21
  "license": "MIT",
21
22
  "devDependencies": {
22
23
  "@types/mocha": "^10.0.8",
23
- "@types/node": "^22.5.5",
24
+ "@types/node": "^22.7.5",
24
25
  "assemblyscript": "^0.27.30",
25
26
  "cross-env": "^7.0.3",
26
27
  "fs-extra": "^11.2.0",
@@ -45,8 +46,10 @@
45
46
  "@eslint/js": "^9.10.0",
46
47
  "as-bignum": "^0.3.0",
47
48
  "gulplog": "^2.2.0",
49
+ "mocha": "^10.7.3",
48
50
  "ts-node": "^10.9.2",
49
51
  "typescript": "^5.6.2",
50
- "typescript-eslint": "^8.6.0"
52
+ "typescript-eslint": "^8.6.0",
53
+ "yargs": "^17.7.2"
51
54
  }
52
55
  }
@@ -2,10 +2,10 @@ import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
2
2
  import { Selector } from '../math/abi';
3
3
  import { i128, u128, u256 } from 'as-bignum/assembly';
4
4
  import { Revert } from '../types/Revert';
5
- import { Map } from '../generic/Map';
6
5
  import { TransactionInput, TransactionOutput } from '../env/classes/UTXO';
7
6
  import { StaticArray } from 'staticarray';
8
7
  import { i256 } from '../math/i256';
8
+ import { AddressMap } from '../generic/AddressMap';
9
9
 
10
10
  @final
11
11
  export class BytesReader {
@@ -107,8 +107,8 @@ export class BytesReader {
107
107
  return bytes;
108
108
  }
109
109
 
110
- public readMultiBytesAddressMap(): Map<Address, Uint8Array[]> {
111
- const map: Map<Address, Uint8Array[]> = new Map<Address, Uint8Array[]>();
110
+ public readMultiBytesAddressMap(): AddressMap<Uint8Array[]> {
111
+ const map: AddressMap<Uint8Array[]> = new AddressMap<Uint8Array[]>();
112
112
  const size: u8 = this.readU8();
113
113
 
114
114
  if (size > 8) throw new Revert('Too many contract called.');
@@ -192,9 +192,9 @@ export class BytesReader {
192
192
  return result;
193
193
  }
194
194
 
195
- public readAddressValueTuple(): Map<Address, u256> {
195
+ public readAddressValueTuple(): AddressMap<u256> {
196
196
  const length: u16 = this.readU16();
197
- const result = new Map<Address, u256>();
197
+ const result = new AddressMap<u256>();
198
198
 
199
199
  for (let i: u16 = 0; i < length; i++) {
200
200
  const address = this.readAddress();
@@ -230,7 +230,12 @@ export class BytesReader {
230
230
  }
231
231
 
232
232
  public readAddress(): Address {
233
- return this.readString(<u16>ADDRESS_BYTE_LENGTH);
233
+ const bytes: Address = new Address();
234
+ for (let i: u32 = 0; i < u32(ADDRESS_BYTE_LENGTH); i++) {
235
+ bytes[i] = this.readU8();
236
+ }
237
+
238
+ return bytes;
234
239
  }
235
240
 
236
241
  public getOffset(): i32 {
@@ -3,9 +3,9 @@ import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
3
3
  import { Selector } from '../math/abi';
4
4
  import { BytesReader } from './BytesReader';
5
5
  import { Revert } from '../types/Revert';
6
- import { Map } from '../generic/Map';
7
6
  import { ArrayBuffer } from 'arraybuffer';
8
7
  import { i256 } from '../math/i256';
8
+ import { AddressMap } from '../generic/AddressMap';
9
9
 
10
10
  @final
11
11
  export class BytesWriter {
@@ -154,7 +154,7 @@ export class BytesWriter {
154
154
  this.writeString(value);
155
155
  }
156
156
 
157
- public writeAddressValueTupleMap(map: Map<Address, u256>): void {
157
+ public writeAddressValueTupleMap(map: AddressMap<u256>): void {
158
158
  if (map.size > 65535) throw new Revert('Map size is too large');
159
159
 
160
160
  /*const requiredSize: u32 = 2 + map.size * (ADDRESS_BYTE_LENGTH + 32);
@@ -177,7 +177,7 @@ export class BytesWriter {
177
177
  }
178
178
  }
179
179
 
180
- public writeLimitedAddressBytesMap(map: Map<Address, Uint8Array[]>): void {
180
+ public writeLimitedAddressBytesMap(map: AddressMap<Uint8Array[]>): void {
181
181
  if (map.size > 8) throw new Revert('Too many contract called.'); // no more than 8 different contracts.
182
182
 
183
183
  /*let requiredSize: u32 = 1 + (map.size * ADDRESS_BYTE_LENGTH + 1);
@@ -269,22 +269,14 @@ export class BytesWriter {
269
269
  return value1 < value2 ? value1 : value2;
270
270
  }
271
271
 
272
- private fromAddress(value: Address): Uint8Array {
273
- if (value.length > ADDRESS_BYTE_LENGTH) {
274
- throw new Revert(`Address is too long ${value.length} > ${ADDRESS_BYTE_LENGTH} bytes`);
275
- }
276
-
277
- const length: i32 = this.min(value.length + 1, ADDRESS_BYTE_LENGTH);
278
- const bytes: Uint8Array = new Uint8Array(length);
279
- for (let i: i32 = 0; i < value.length; i++) {
280
- bytes[i] = value.charCodeAt(i);
281
- }
282
-
283
- if (value.length < ADDRESS_BYTE_LENGTH) {
284
- bytes[value.length] = 0;
272
+ private fromAddress(pubKey: Address): Uint8Array {
273
+ if (pubKey.byteLength > ADDRESS_BYTE_LENGTH) {
274
+ throw new Revert(
275
+ `Address is too long ${pubKey.byteLength} > ${ADDRESS_BYTE_LENGTH} bytes`,
276
+ );
285
277
  }
286
278
 
287
- return bytes;
279
+ return pubKey;
288
280
  }
289
281
 
290
282
  private resize(size: u32): void {
@@ -12,10 +12,10 @@ import { Address } from '../types/Address';
12
12
  import { Revert } from '../types/Revert';
13
13
  import { SafeMath } from '../types/SafeMath';
14
14
 
15
+ import { Calldata } from '../types';
15
16
  import { IOP_20 } from './interfaces/IOP_20';
16
17
  import { OP20InitParameters } from './interfaces/OP20InitParameters';
17
18
  import { OP_NET } from './OP_NET';
18
- import { Calldata } from '../types';
19
19
 
20
20
  const maxSupplyPointer: u16 = Blockchain.nextPointer;
21
21
  const decimalsPointer: u16 = Blockchain.nextPointer;
@@ -27,7 +27,7 @@ const balanceOfMapPointer: u16 = Blockchain.nextPointer;
27
27
 
28
28
  export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
29
29
  protected readonly allowanceMap: MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>;
30
- protected readonly balanceOfMap: AddressMemoryMap<Address, MemorySlotData<u256>>;
30
+ protected readonly balanceOfMap: AddressMemoryMap<MemorySlotData<u256>>;
31
31
 
32
32
  protected readonly _maxSupply: StoredU256;
33
33
  protected readonly _decimals: StoredU256;
@@ -42,7 +42,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
42
42
  u256.Zero,
43
43
  );
44
44
 
45
- this.balanceOfMap = new AddressMemoryMap<Address, MemorySlotData<u256>>(
45
+ this.balanceOfMap = new AddressMemoryMap<MemorySlotData<u256>>(
46
46
  balanceOfMapPointer,
47
47
  u256.Zero,
48
48
  );
@@ -150,15 +150,6 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
150
150
  return response;
151
151
  }
152
152
 
153
- public mint(callData: Calldata): BytesWriter {
154
- const response = new BytesWriter(1);
155
- const resp = this._mint(callData.readAddress(), callData.readU256());
156
-
157
- response.writeBoolean(resp);
158
-
159
- return response;
160
- }
161
-
162
153
  public transfer(callData: Calldata): BytesWriter {
163
154
  const response = new BytesWriter(1);
164
155
  const resp = this._transfer(callData.readAddress(), callData.readU256());
@@ -213,8 +204,6 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
213
204
  return this.balanceOf(calldata);
214
205
  case encodeSelector('burn'):
215
206
  return this.burn(calldata);
216
- case encodeSelector('mint'):
217
- return this.mint(calldata);
218
207
  case encodeSelector('transfer'):
219
208
  return this.transfer(calldata);
220
209
  case encodeSelector('transferFrom'):
@@ -297,7 +286,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
297
286
  return true;
298
287
  }
299
288
 
300
- protected _transfer(to: string, value: u256): boolean {
289
+ protected _transfer(to: Address, value: u256): boolean {
301
290
  const sender = Blockchain.tx.sender;
302
291
 
303
292
  if (!this.balanceOfMap.has(sender)) throw new Revert();
@@ -317,7 +306,6 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
317
306
  const newToBalance: u256 = SafeMath.add(toBalance, value);
318
307
 
319
308
  this.balanceOfMap.set(to, newToBalance);
320
-
321
309
  this.createTransferEvent(sender, to, value);
322
310
 
323
311
  return true;
@@ -8,11 +8,11 @@ import { MAX_EVENT_DATA_SIZE, NetEvent } from '../events/NetEvent';
8
8
  import { Calldata } from '../types';
9
9
 
10
10
  export class OP_NET implements IBTC {
11
- public get address(): string {
11
+ public get address(): Address {
12
12
  return Blockchain.contractAddress;
13
13
  }
14
14
 
15
- public get owner(): string {
15
+ public get owner(): Address {
16
16
  return Blockchain.owner;
17
17
  }
18
18
 
@@ -16,6 +16,4 @@ export interface IOP_20 {
16
16
  allowance(callData: Calldata): BytesWriter;
17
17
 
18
18
  burn(callData: Calldata): BytesWriter;
19
-
20
- mint(callData: Calldata): BytesWriter;
21
19
  }
@@ -3,7 +3,6 @@ import { MemorySlotPointer } from '../memory/MemorySlotPointer';
3
3
  import { MemorySlotData } from '../memory/MemorySlot';
4
4
  import { u256 } from 'as-bignum/assembly';
5
5
  import { BytesReader } from '../buffer/BytesReader';
6
- import { encodePointerHash } from '../math/abi';
7
6
  import { BytesWriter } from '../buffer/BytesWriter';
8
7
  import { NetEvent } from '../events/NetEvent';
9
8
  import { Potential } from '../lang/Definitions';
@@ -34,7 +33,7 @@ export function runtimeError(msg: string): Error {
34
33
  export class BlockchainEnvironment {
35
34
  private static readonly MAX_U16: u16 = 65535;
36
35
 
37
- public readonly DEAD_ADDRESS: Address = 'bc1dead';
36
+ public readonly DEAD_ADDRESS: Address = Address.dead();
38
37
 
39
38
  private storage: PointerStorage = new MapU256();
40
39
  private _selfContract: Potential<OP_NET> = null;
@@ -128,7 +127,7 @@ export class BlockchainEnvironment {
128
127
  }
129
128
 
130
129
  public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
131
- if (destinationContract === this._contractAddress) {
130
+ if (destinationContract === this.contractAddress) {
132
131
  throw this.error('Cannot call self');
133
132
  }
134
133
 
@@ -163,9 +162,10 @@ export class BlockchainEnvironment {
163
162
  emit(buffer.getBuffer());
164
163
  }
165
164
 
166
- public encodeVirtualAddress(virtualAddress: Uint8Array): Address {
167
- const writer: BytesWriter = new BytesWriter(virtualAddress.byteLength + 4);
168
- writer.writeBytesWithLength(virtualAddress);
165
+ public encodeVirtualAddress(virtualAddress: u8[]): Address {
166
+ const writer: BytesWriter = new BytesWriter(virtualAddress.length + 4);
167
+ writer.writeU32(virtualAddress.length);
168
+ writer.writeBytesU8Array(virtualAddress);
169
169
 
170
170
  const buffer: Uint8Array = writer.getBuffer();
171
171
  const cb: Potential<Uint8Array> = encodeAddress(buffer);
@@ -210,11 +210,9 @@ export class BlockchainEnvironment {
210
210
  }
211
211
 
212
212
  public getStorageAt(
213
- pointer: u16,
214
- subPointer: MemorySlotPointer,
213
+ pointerHash: MemorySlotPointer,
215
214
  defaultValue: MemorySlotData<u256>,
216
215
  ): MemorySlotData<u256> {
217
- const pointerHash: MemorySlotPointer = encodePointerHash(pointer, subPointer);
218
216
  this.ensureStorageAtPointer(pointerHash, defaultValue);
219
217
 
220
218
  if (this.storage.has(pointerHash)) {
@@ -224,20 +222,14 @@ export class BlockchainEnvironment {
224
222
  return defaultValue;
225
223
  }
226
224
 
227
- public hasStorageAt(pointer: u16, subPointer: MemorySlotPointer): bool {
225
+ public hasStorageAt(pointerHash: MemorySlotPointer): bool {
228
226
  // We mark zero as the default value for the storage, if something is 0, the storage slot get deleted or is non-existent
229
- const val: u256 = this.getStorageAt(pointer, subPointer, u256.Zero);
227
+ const val: u256 = this.getStorageAt(pointerHash, u256.Zero);
230
228
 
231
229
  return u256.ne(val, u256.Zero);
232
230
  }
233
231
 
234
- public setStorageAt(
235
- pointer: u16,
236
- keyPointer: MemorySlotPointer,
237
- value: MemorySlotData<u256>,
238
- ): void {
239
- const pointerHash: u256 = encodePointerHash(pointer, keyPointer);
240
-
232
+ public setStorageAt(pointerHash: MemorySlotPointer, value: MemorySlotData<u256>): void {
241
233
  this._internalSetStorageAt(pointerHash, value);
242
234
  }
243
235
 
@@ -288,12 +280,14 @@ export class BlockchainEnvironment {
288
280
  pointerHash: MemorySlotPointer,
289
281
  defaultValue: MemorySlotData<u256>,
290
282
  ): void {
291
- if (!this.hasPointerStorageHash(pointerHash)) {
292
- if (u256.eq(defaultValue, u256.Zero)) {
293
- return;
294
- }
283
+ if (this.hasPointerStorageHash(pointerHash)) {
284
+ return;
285
+ }
295
286
 
296
- this._internalSetStorageAt(pointerHash, defaultValue);
287
+ if (u256.eq(defaultValue, u256.Zero)) {
288
+ return;
297
289
  }
290
+
291
+ this._internalSetStorageAt(pointerHash, defaultValue);
298
292
  }
299
293
  }
@@ -0,0 +1,62 @@
1
+ import { Revert } from '../types/Revert';
2
+ import { Map } from './Map';
3
+ import { Address } from '../types/Address';
4
+
5
+ @final
6
+ export class AddressMap<V> extends Map<Address, V> {
7
+ public set(key: Address, value: V): void {
8
+ const index: i32 = this._keys.indexOf(key);
9
+ if (index == -1) {
10
+ this._keys.push(key);
11
+ this._values.push(value);
12
+ } else {
13
+ this._values[index] = value;
14
+ }
15
+ }
16
+
17
+ public indexOf(address: Address): i32 {
18
+ for (let i: i32 = 0; i < this._keys.length; i++) {
19
+ const key = this._keys[i];
20
+
21
+ if (address.equals(key)) {
22
+ return i;
23
+ }
24
+ }
25
+
26
+ return -1;
27
+ }
28
+
29
+ public has(key: Address): bool {
30
+ for (let i: i32 = 0; i < this._keys.length; i++) {
31
+ if (key.equals(this._keys[i])) {
32
+ return true;
33
+ }
34
+ }
35
+
36
+ return false;
37
+ }
38
+
39
+ public get(key: Address): V {
40
+ const index: i32 = this.indexOf(key);
41
+ if (index == -1) {
42
+ throw new Revert('Key not found in map');
43
+ }
44
+ return this._values[index];
45
+ }
46
+
47
+ public delete(key: Address): bool {
48
+ const index: i32 = this.indexOf(key);
49
+ if (index == -1) {
50
+ return false;
51
+ }
52
+
53
+ this._keys.splice(index, 1);
54
+ this._values.splice(index, 1);
55
+
56
+ return true;
57
+ }
58
+
59
+ public getAddresses(): Address[] {
60
+ return this._keys;
61
+ }
62
+ }
@@ -27,7 +27,13 @@ export class Map<K, V> {
27
27
  }
28
28
 
29
29
  public indexOf(key: K): i32 {
30
- return this._keys.indexOf(key);
30
+ for (let i: i32 = 0; i < this._keys.length; i++) {
31
+ if (this._keys[i] == key) {
32
+ return i;
33
+ }
34
+ }
35
+
36
+ return -1;
31
37
  }
32
38
 
33
39
  public get(key: K): V {
@@ -39,13 +45,7 @@ export class Map<K, V> {
39
45
  }
40
46
 
41
47
  public has(key: K): bool {
42
- for (let i: i32 = 0; i < this._keys.length; i++) {
43
- if (this._keys[i] == key) {
44
- return true;
45
- }
46
- }
47
-
48
- return false;
48
+ return this.indexOf(key) != -1;
49
49
  }
50
50
 
51
51
  public delete(key: K): bool {
@@ -53,6 +53,7 @@ export class Map<K, V> {
53
53
  if (index == -1) {
54
54
  return false;
55
55
  }
56
+
56
57
  this._keys.splice(index, 1);
57
58
  this._values.splice(index, 1);
58
59
  return true;
package/runtime/index.ts CHANGED
@@ -13,6 +13,7 @@ export * from './buffer/BytesReader';
13
13
  export * from './buffer/BytesWriter';
14
14
 
15
15
  /** Interfaces */
16
+ export * from './interfaces/IBTC';
16
17
  export * from './interfaces/DeployContractResponse';
17
18
 
18
19
  /** Events */
@@ -24,9 +25,12 @@ export * from './env/classes/UTXO';
24
25
  export * from './env/classes/Transaction';
25
26
  export * from './env/classes/Block';
26
27
 
27
- /** Types */
28
+ /** Maps */
28
29
  export * from './generic/Map';
29
- export * from './interfaces/IBTC';
30
+ export * from './generic/MapU256';
31
+ export * from './generic/AddressMap';
32
+
33
+ /** Types */
30
34
  export * from './types';
31
35
 
32
36
  /** Definitions */
@@ -42,24 +46,34 @@ export * from './math/cyrb53';
42
46
  export * from './math/sha256';
43
47
  export * from './math/rnd';
44
48
  export * from './math/i256';
49
+ export * from './secp256k1/ECPoint';
45
50
 
46
51
  /** Memory */
47
52
  export * from './memory/AddressMemoryMap';
53
+ export * from './memory/StringMemoryMap';
54
+ export * from './memory/MultiStringMemoryMap';
48
55
  export * from './memory/MemorySlot';
49
56
  export * from './memory/MemorySlotPointer';
50
57
  export * from './memory/KeyMerger';
51
58
  export * from './memory/MultiAddressMemoryMap';
59
+ export * from './memory/Uint8ArrayMerger';
52
60
 
53
61
  /** Storage */
54
62
  export * from './storage/StoredU256';
55
63
  export * from './storage/StoredString';
64
+ export * from './storage/StoredAddress';
56
65
  export * from './storage/StoredBoolean';
57
66
  export * from './storage/Serializable';
58
67
 
68
+ export * from './storage/StorageBacked';
69
+ export * from './storage/StorageSlot';
70
+ export * from './storage/StorageStruct';
71
+ export * from './storage/StorageLayout';
72
+ export * from './storage/StorageValue';
73
+
59
74
  /** Shared libraries */
60
75
  export * from './shared-libraries/TransferHelper';
61
76
  export * from './shared-libraries/OP20Utils';
62
77
 
63
78
  /** Utils */
64
- export * from './utils/hex';
65
- export * from './utils/box';
79
+ export * from './utils';
@@ -1,7 +1,6 @@
1
1
  // SO IN TYPESCRIPT, WE CAN NOT USE TWO METHOD WITH THE SAME NAME. SO NOT ADDING THE TYPE TO THE HASH IS A DESIGN CHOICE.
2
2
  import { bytes32, bytes4 } from './bytes';
3
3
  import { MemorySlotPointer } from '../memory/MemorySlotPointer';
4
- import { u256 } from 'as-bignum/assembly';
5
4
  import { Sha256 } from './sha256';
6
5
 
7
6
  export type Selector = u32;
@@ -13,25 +12,8 @@ export function encodeSelector(name: string): Selector {
13
12
  return bytes4(hash);
14
13
  }
15
14
 
16
- export function encodePointer(str: string): MemorySlotPointer {
17
- const typed = Uint8Array.wrap(String.UTF8.encode(str));
15
+ export function encodePointer(typed: Uint8Array): MemorySlotPointer {
18
16
  const hash = Sha256.hash(typed);
19
17
 
20
18
  return bytes32(hash);
21
19
  }
22
-
23
- export function encodePointerHash(pointer: u16, sub: u256): MemorySlotPointer {
24
- const finalBuffer: Uint8Array = new Uint8Array(34);
25
- const mergedKey: u8[] = [u8(pointer & u16(0xff)), u8((pointer >> u16(8)) & u16(0xff))];
26
-
27
- for (let i: i32 = 0; i < mergedKey.length; i++) {
28
- finalBuffer[i] = mergedKey[i];
29
- }
30
-
31
- const subKey = sub.toUint8Array();
32
- for (let i: i32 = 0; i < subKey.length; i++) {
33
- finalBuffer[mergedKey.length + i] = subKey[i];
34
- }
35
-
36
- return bytes32(Sha256.hash(finalBuffer));
37
- }