@btc-vision/btc-runtime 1.0.15 → 1.0.16
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/package.json +1 -1
- package/runtime/buffer/BytesReader.ts +11 -0
- package/runtime/buffer/BytesWriter.ts +10 -0
- package/runtime/contracts/OP_20.ts +14 -33
- package/runtime/contracts/OP_NET.ts +3 -7
- package/runtime/env/BTCEnvironment.ts +25 -1
- package/runtime/env/global.ts +9 -0
- package/runtime/index.ts +3 -0
- package/runtime/math/abi.ts +1 -1
- package/runtime/math/sha256.ts +6 -272
- package/runtime/shared-libraries/TransferHelper.ts +64 -0
package/package.json
CHANGED
|
@@ -176,6 +176,17 @@ export class BytesReader {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
public readAddressArray(): Address[] {
|
|
180
|
+
const length = this.readU16();
|
|
181
|
+
const result = new Array<Address>(length);
|
|
182
|
+
|
|
183
|
+
for (let i: u16 = 0; i < length; i++) {
|
|
184
|
+
result[i] = this.readAddress();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
|
|
179
190
|
private verifyChecksum(): void {
|
|
180
191
|
const writtenChecksum = this.readU32();
|
|
181
192
|
|
|
@@ -70,6 +70,16 @@ export class BytesWriter {
|
|
|
70
70
|
this.currentOffset += 8;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
public writeAddressArray(value: Address[]): void {
|
|
74
|
+
if (value.length > 65535) throw new Revert('Array size is too large');
|
|
75
|
+
|
|
76
|
+
this.writeU16(value.length);
|
|
77
|
+
|
|
78
|
+
for (let i: i32 = 0; i < value.length; i++) {
|
|
79
|
+
this.writeAddress(value[i]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
public writeStorage(storage: BlockchainStorage): void {
|
|
74
84
|
this.writeU32(storage.size);
|
|
75
85
|
|
|
@@ -14,14 +14,6 @@ import { MultiAddressMemoryMap } from '../memory/MultiAddressMemoryMap';
|
|
|
14
14
|
import { StoredU256 } from '../storage/StoredU256';
|
|
15
15
|
import { ApproveEvent, BurnEvent, MintEvent, TransferEvent } from '../events/predefined';
|
|
16
16
|
|
|
17
|
-
const allowanceSelector = encodeSelector('allowance');
|
|
18
|
-
const approveSelector = encodeSelector('approve');
|
|
19
|
-
const balanceOfSelector = encodeSelector('balanceOf');
|
|
20
|
-
const burnSelector = encodeSelector('burn');
|
|
21
|
-
const mintSelector = encodeSelector('mint');
|
|
22
|
-
const transferSelector = encodeSelector('transfer');
|
|
23
|
-
const transferFromSelector = encodeSelector('transferFrom');
|
|
24
|
-
|
|
25
17
|
export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
26
18
|
protected readonly allowanceMap: MultiAddressMemoryMap<Address, Address, MemorySlotData<u256>>;
|
|
27
19
|
protected readonly balanceOfMap: AddressMemoryMap<Address, MemorySlotData<u256>>;
|
|
@@ -128,19 +120,19 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
128
120
|
|
|
129
121
|
public callMethod(method: Selector, calldata: Calldata): BytesWriter {
|
|
130
122
|
switch (method) {
|
|
131
|
-
case
|
|
123
|
+
case encodeSelector('allowance'):
|
|
132
124
|
return this.allowance(calldata);
|
|
133
|
-
case
|
|
125
|
+
case encodeSelector('approve'):
|
|
134
126
|
return this.approve(calldata);
|
|
135
|
-
case
|
|
127
|
+
case encodeSelector('balanceOf'):
|
|
136
128
|
return this.balanceOf(calldata);
|
|
137
|
-
case
|
|
129
|
+
case encodeSelector('burn'):
|
|
138
130
|
return this.burn(calldata);
|
|
139
|
-
case
|
|
131
|
+
case encodeSelector('mint'):
|
|
140
132
|
return this.mint(calldata);
|
|
141
|
-
case
|
|
133
|
+
case encodeSelector('transfer'):
|
|
142
134
|
return this.transfer(calldata);
|
|
143
|
-
case
|
|
135
|
+
case encodeSelector('transferFrom'):
|
|
144
136
|
return this.transferFrom(calldata);
|
|
145
137
|
default:
|
|
146
138
|
return super.callMethod(method, calldata);
|
|
@@ -174,14 +166,13 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
174
166
|
}
|
|
175
167
|
|
|
176
168
|
/** REDEFINED METHODS */
|
|
177
|
-
protected _allowance(owner:
|
|
169
|
+
protected _allowance(owner: Address, spender: Address): u256 {
|
|
178
170
|
const senderMap = this.allowanceMap.get(owner);
|
|
179
|
-
if (!senderMap.has(spender)) throw new Revert();
|
|
180
171
|
|
|
181
172
|
return senderMap.get(spender);
|
|
182
173
|
}
|
|
183
174
|
|
|
184
|
-
protected _approve(spender:
|
|
175
|
+
protected _approve(spender: Address, value: u256): boolean {
|
|
185
176
|
const callee = Blockchain.callee();
|
|
186
177
|
|
|
187
178
|
const senderMap = this.allowanceMap.get(callee);
|
|
@@ -225,10 +216,8 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
225
216
|
|
|
226
217
|
protected _mint(to: Address, value: u256, onlyOwner: boolean = true): boolean {
|
|
227
218
|
const callee = Blockchain.callee();
|
|
228
|
-
const caller = Blockchain.caller();
|
|
229
219
|
|
|
230
220
|
if (onlyOwner) this.onlyOwner(callee);
|
|
231
|
-
if (caller !== callee) throw new Revert(`callee != caller`);
|
|
232
221
|
|
|
233
222
|
if (!this.balanceOfMap.has(to)) {
|
|
234
223
|
this.balanceOfMap.set(to, value);
|
|
@@ -305,27 +294,19 @@ export abstract class OP_20 extends OP_NET implements IOP_20 {
|
|
|
305
294
|
}
|
|
306
295
|
|
|
307
296
|
protected _transferFrom(from: Address, to: Address, value: u256): boolean {
|
|
308
|
-
if (!this.allowanceMap.has(from)) throw new Revert();
|
|
309
|
-
|
|
310
297
|
const spender = Blockchain.callee();
|
|
311
298
|
if (Blockchain.caller() !== from) {
|
|
312
299
|
throw new Revert('Not caller.');
|
|
313
300
|
}
|
|
314
301
|
|
|
315
|
-
const fromAllowanceMap = this.allowanceMap.get(from);
|
|
316
|
-
const allowed: u256 = fromAllowanceMap.get(spender);
|
|
317
|
-
if (allowed < value) throw new Revert(`Insufficient allowance`);
|
|
318
|
-
|
|
319
302
|
if (this.isSelf(spender)) throw new Revert('Can not transfer from self account');
|
|
320
303
|
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const allowance: u256 = senderMap.get(spender);
|
|
325
|
-
if (allowance < value) throw new Revert(`Insufficient allowance`);
|
|
304
|
+
const fromAllowanceMap = this.allowanceMap.get(from);
|
|
305
|
+
const allowed: u256 = fromAllowanceMap.get(spender);
|
|
306
|
+
if (allowed < value) throw new Revert(`Insufficient allowance ${allowed} < ${value}`);
|
|
326
307
|
|
|
327
|
-
const newAllowance: u256 = SafeMath.sub(
|
|
328
|
-
|
|
308
|
+
const newAllowance: u256 = SafeMath.sub(allowed, value);
|
|
309
|
+
fromAllowanceMap.set(from, newAllowance);
|
|
329
310
|
|
|
330
311
|
this._unsafeTransferFrom(from, to, value);
|
|
331
312
|
|
|
@@ -7,10 +7,6 @@ import { encodeSelector, Selector } from '../math/abi';
|
|
|
7
7
|
import { Revert } from '../types/Revert';
|
|
8
8
|
import { MAX_EVENT_DATA_SIZE, NetEvent } from '../events/NetEvent';
|
|
9
9
|
|
|
10
|
-
const isAddressOwnerSelector = encodeSelector('isAddressOwner');
|
|
11
|
-
const addressSelector = encodeSelector('address');
|
|
12
|
-
const ownerSelector = encodeSelector('owner');
|
|
13
|
-
|
|
14
10
|
export class OP_NET implements IBTC {
|
|
15
11
|
constructor() {}
|
|
16
12
|
|
|
@@ -24,7 +20,7 @@ export class OP_NET implements IBTC {
|
|
|
24
20
|
|
|
25
21
|
public callMethod(method: Selector, calldata: Calldata): BytesWriter {
|
|
26
22
|
switch (method) {
|
|
27
|
-
case
|
|
23
|
+
case encodeSelector('isAddressOwner'):
|
|
28
24
|
return this.isAddressOwner(calldata);
|
|
29
25
|
default:
|
|
30
26
|
throw new Revert('Method not found');
|
|
@@ -35,10 +31,10 @@ export class OP_NET implements IBTC {
|
|
|
35
31
|
const response = new BytesWriter();
|
|
36
32
|
|
|
37
33
|
switch (method) {
|
|
38
|
-
case
|
|
34
|
+
case encodeSelector('address'):
|
|
39
35
|
response.writeAddress(this.address);
|
|
40
36
|
break;
|
|
41
|
-
case
|
|
37
|
+
case encodeSelector('owner'):
|
|
42
38
|
response.writeAddress(this.owner);
|
|
43
39
|
break;
|
|
44
40
|
default:
|
|
@@ -11,7 +11,15 @@ import { Potential } from '../lang/Definitions';
|
|
|
11
11
|
import { Map } from '../generic/Map';
|
|
12
12
|
import { OP_NET } from '../contracts/OP_NET';
|
|
13
13
|
import { PointerStorage } from '../types';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
callContract,
|
|
16
|
+
deploy,
|
|
17
|
+
deployFromAddress,
|
|
18
|
+
encodeAddress,
|
|
19
|
+
loadPointer,
|
|
20
|
+
log,
|
|
21
|
+
storePointer,
|
|
22
|
+
} from './global';
|
|
15
23
|
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
16
24
|
|
|
17
25
|
export * from '../env/global';
|
|
@@ -119,6 +127,10 @@ export class BlockchainEnvironment {
|
|
|
119
127
|
throw this.error('Cannot call self');
|
|
120
128
|
}
|
|
121
129
|
|
|
130
|
+
if (!destinationContract) {
|
|
131
|
+
throw this.error('Destination contract is required');
|
|
132
|
+
}
|
|
133
|
+
|
|
122
134
|
const call = new BytesWriter();
|
|
123
135
|
call.writeAddress(destinationContract);
|
|
124
136
|
call.writeBytesWithLength(calldata.getBuffer());
|
|
@@ -164,6 +176,18 @@ export class BlockchainEnvironment {
|
|
|
164
176
|
return buffer.getBuffer();
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
public encodeVirtualAddress(virtualAddress: Uint8Array): Address {
|
|
180
|
+
const writer: BytesWriter = new BytesWriter();
|
|
181
|
+
writer.writeBytesWithLength(virtualAddress);
|
|
182
|
+
|
|
183
|
+
const buffer: Uint8Array = writer.getBuffer();
|
|
184
|
+
const cb: Potential<Uint8Array> = encodeAddress(buffer);
|
|
185
|
+
if (!cb) throw this.error('Failed to encode virtual address');
|
|
186
|
+
|
|
187
|
+
const reader: BytesReader = new BytesReader(cb as Uint8Array);
|
|
188
|
+
return reader.readAddress();
|
|
189
|
+
}
|
|
190
|
+
|
|
167
191
|
public deployContract(hash: u256, bytecode: Uint8Array): BytesReader {
|
|
168
192
|
const writer = new BytesWriter();
|
|
169
193
|
writer.writeU256(hash);
|
package/runtime/env/global.ts
CHANGED
|
@@ -21,3 +21,12 @@ export declare function callContract(data: Uint8Array): Uint8Array;
|
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
@external('env', 'log')
|
|
23
23
|
export declare function log(data: Uint8Array): void;
|
|
24
|
+
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
@external('env', 'encodeAddress')
|
|
27
|
+
export declare function encodeAddress(data: Uint8Array): Uint8Array;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
@external('env', 'sha256')
|
|
32
|
+
export declare function sha256(data: Uint8Array): Uint8Array;
|
package/runtime/index.ts
CHANGED
package/runtime/math/abi.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-
import { Sha256 } from './sha256';
|
|
4
3
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
5
4
|
import { u256 } from 'as-bignum/assembly';
|
|
5
|
+
import { Sha256 } from './sha256';
|
|
6
6
|
|
|
7
7
|
export type Selector = u32;
|
|
8
8
|
|
package/runtime/math/sha256.ts
CHANGED
|
@@ -1,278 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function setU8(t: Uint8Array, s: Uint8Array, o: isize = 0): void {
|
|
4
|
-
memory.copy(t.dataStart + o, s.dataStart, s.length);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function store64_be(x: Uint8Array, offset: isize, u: u64): void {
|
|
8
|
-
store<u64>(changetype<usize>(x.buffer) + offset, bswap(u));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function load32_be(x: Uint8Array, offset: isize): u32 {
|
|
12
|
-
return bswap(load<u32>(changetype<usize>(x.buffer) + offset));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function store32_be(x: Uint8Array, offset: isize, u: u32): void {
|
|
16
|
-
store<u32>(changetype<usize>(x.buffer) + offset, bswap(u));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
class Internal {
|
|
20
|
-
static K: u32[] = [
|
|
21
|
-
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
|
22
|
-
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
|
|
23
|
-
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
|
|
24
|
-
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
|
25
|
-
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
|
26
|
-
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
|
27
|
-
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
|
|
28
|
-
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
29
|
-
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
|
30
|
-
0xc67178f2,
|
|
31
|
-
];
|
|
32
|
-
static iv: u8[] = [
|
|
33
|
-
0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5,
|
|
34
|
-
0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0,
|
|
35
|
-
0xcd, 0x19,
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
@inline
|
|
39
|
-
static Sigma0(x: u32): u32 {
|
|
40
|
-
return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@inline
|
|
44
|
-
static Sigma1(x: u32): u32 {
|
|
45
|
-
return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@inline
|
|
49
|
-
static sigma0(x: u32): u32 {
|
|
50
|
-
return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@inline
|
|
54
|
-
static sigma1(x: u32): u32 {
|
|
55
|
-
return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@inline
|
|
59
|
-
static Ch(x: u32, y: u32, z: u32): u32 {
|
|
60
|
-
return z ^ (x & (y ^ z));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@inline
|
|
64
|
-
static Maj(x: u32, y: u32, z: u32): u32 {
|
|
65
|
-
return (x & (y ^ z)) ^ (y & z);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
static expand(w: StaticArray<u32>): void {
|
|
69
|
-
for (let i = 0; i < 16; i++) {
|
|
70
|
-
unchecked(
|
|
71
|
-
(w[i] +=
|
|
72
|
-
w[(i + 9) & 15] +
|
|
73
|
-
Internal.sigma1(w[(i + 14) & 15]) +
|
|
74
|
-
Internal.sigma0(w[(i + 1) & 15])),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
static handle(r: StaticArray<u32>, w: StaticArray<u32>, c: u32[]): void {
|
|
80
|
-
for (let i = 0; i < 16; i++) {
|
|
81
|
-
var x = r[7 & (7 - i)] + w[i] + c[i];
|
|
82
|
-
x += unchecked(Internal.Sigma1(r[7 & (4 - i)]));
|
|
83
|
-
x += unchecked(Internal.Ch(r[7 & (4 - i)], r[7 & (5 - i)], r[7 & (6 - i)]));
|
|
84
|
-
unchecked((r[7 & (3 - i)] += x));
|
|
85
|
-
x += unchecked(Internal.Sigma0(r[7 & (0 - i)]));
|
|
86
|
-
x += unchecked(Internal.Maj(r[7 & (0 - i)], r[7 & (1 - i)], r[7 & (2 - i)]));
|
|
87
|
-
unchecked((r[7 & (7 - i)] = x));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
static _hashblocks(st: Uint8Array, m: Uint8Array, n_: isize): isize {
|
|
92
|
-
let z = new StaticArray<u32>(8),
|
|
93
|
-
r = new StaticArray<u32>(8),
|
|
94
|
-
w = new StaticArray<u32>(16);
|
|
95
|
-
for (let i = 0; i < 8; ++i) {
|
|
96
|
-
unchecked((z[i] = r[i] = load32_be(st, i << 2)));
|
|
97
|
-
}
|
|
98
|
-
let pos = 0,
|
|
99
|
-
n = n_;
|
|
100
|
-
while (n >= 64) {
|
|
101
|
-
for (let i = 0; i < 16; ++i) {
|
|
102
|
-
w[i] = load32_be(m, (i << 2) + pos);
|
|
103
|
-
}
|
|
104
|
-
Internal.handle(r, w, Internal.K.slice(0));
|
|
105
|
-
Internal.expand(w);
|
|
106
|
-
Internal.handle(r, w, Internal.K.slice(16));
|
|
107
|
-
Internal.expand(w);
|
|
108
|
-
Internal.handle(r, w, Internal.K.slice(32));
|
|
109
|
-
Internal.expand(w);
|
|
110
|
-
Internal.handle(r, w, Internal.K.slice(48));
|
|
111
|
-
for (let i = 0; i < 8; ++i) {
|
|
112
|
-
let x = unchecked(r[i] + z[i]);
|
|
113
|
-
unchecked((z[i] = x));
|
|
114
|
-
unchecked((r[i] = x));
|
|
115
|
-
}
|
|
116
|
-
pos += 64;
|
|
117
|
-
n -= 64;
|
|
118
|
-
}
|
|
119
|
-
for (let i = 0; i < 8; ++i) {
|
|
120
|
-
store32_be(st, i << 2, unchecked(z[i]));
|
|
121
|
-
}
|
|
122
|
-
return n;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static _hashInit(): Uint8Array {
|
|
126
|
-
let st = new Uint8Array(32 + 64);
|
|
127
|
-
|
|
128
|
-
for (let i = 0; i < 32; ++i) {
|
|
129
|
-
st[i] = Internal.iv[i];
|
|
130
|
-
}
|
|
131
|
-
return st;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
static _hashUpdate(st: Uint8Array, m: Uint8Array, n: isize, r: isize): isize {
|
|
135
|
-
let obuffered = st.subarray(32);
|
|
136
|
-
let buffered = new Uint8Array(64);
|
|
137
|
-
setU8(buffered, obuffered.subarray(0, 64));
|
|
138
|
-
|
|
139
|
-
let still_available_in_buffer = <isize>64 - r;
|
|
140
|
-
let copiable_to_buffer = min(n, still_available_in_buffer);
|
|
141
|
-
setU8(buffered, m.subarray(0, <aisize>copiable_to_buffer), r);
|
|
142
|
-
r += copiable_to_buffer;
|
|
143
|
-
n -= copiable_to_buffer;
|
|
144
|
-
let pos: isize = 0;
|
|
145
|
-
if (r === 64) {
|
|
146
|
-
Internal._hashblocks(st, buffered, 64);
|
|
147
|
-
r = 0;
|
|
148
|
-
pos = copiable_to_buffer;
|
|
149
|
-
}
|
|
150
|
-
if (n == 0) {
|
|
151
|
-
setU8(obuffered, buffered);
|
|
152
|
-
return r;
|
|
153
|
-
}
|
|
154
|
-
let left = m.subarray(<aisize>pos);
|
|
155
|
-
r = Internal._hashblocks(st, left, left.length);
|
|
156
|
-
if (r > 0) {
|
|
157
|
-
setU8(obuffered, left.subarray(left.length - <aisize>r));
|
|
158
|
-
}
|
|
159
|
-
return r;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
static _hashFinal(st: Uint8Array, out: Uint8Array, t: isize, r: isize): void {
|
|
163
|
-
let buffered = st.subarray(32);
|
|
164
|
-
let padded = new Uint8Array(128);
|
|
165
|
-
setU8(padded, buffered.subarray(0, <aisize>r));
|
|
166
|
-
padded[<aisize>r] = 0x80;
|
|
167
|
-
if (r < 56) {
|
|
168
|
-
store64_be(padded, 64 - 8, t << 3);
|
|
169
|
-
Internal._hashblocks(st, padded, 64);
|
|
170
|
-
} else {
|
|
171
|
-
store64_be(padded, 128 - 8, t << 3);
|
|
172
|
-
Internal._hashblocks(st, padded, 128);
|
|
173
|
-
}
|
|
174
|
-
for (let i = 0; i < 32; ++i) {
|
|
175
|
-
out[i] = st[i];
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
static _hash(out: Uint8Array, m: Uint8Array, n: isize): void {
|
|
180
|
-
let st = Internal._hashInit();
|
|
181
|
-
let r = Internal._hashUpdate(st, m, n, 0);
|
|
182
|
-
|
|
183
|
-
Internal._hashFinal(st, out, n, r);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
static _hmac(m: Uint8Array, k: Uint8Array): Uint8Array {
|
|
187
|
-
if (k.length > 64) {
|
|
188
|
-
k = Sha256.hash(k);
|
|
189
|
-
}
|
|
190
|
-
let b = new Uint8Array(64);
|
|
191
|
-
setU8(b, k);
|
|
192
|
-
for (let i = 0; i < b.length; ++i) {
|
|
193
|
-
b[i] ^= 0x36;
|
|
194
|
-
}
|
|
195
|
-
let out = new Uint8Array(32);
|
|
196
|
-
let st = Internal._hashInit();
|
|
197
|
-
let r = Internal._hashUpdate(st, b, b.length, 0);
|
|
198
|
-
r = Internal._hashUpdate(st, m, m.length, r);
|
|
199
|
-
Internal._hashFinal(st, out, b.length + m.length, r);
|
|
200
|
-
for (let i = 0; i < b.length; ++i) {
|
|
201
|
-
b[i] ^= 0x6a;
|
|
202
|
-
}
|
|
203
|
-
st = Internal._hashInit();
|
|
204
|
-
r = Internal._hashUpdate(st, b, b.length, 0);
|
|
205
|
-
r = Internal._hashUpdate(st, out, out.length, r);
|
|
206
|
-
Internal._hashFinal(st, out, b.length + out.length, r);
|
|
207
|
-
return out;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Hash function output size, in bytes
|
|
213
|
-
*/
|
|
214
|
-
export const SHA256_HASH_BYTES: isize = 32;
|
|
1
|
+
import { sha256 } from '../env/global';
|
|
215
2
|
|
|
216
3
|
export class Sha256 {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
st: Uint8Array;
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Initialize a multipart hash computation
|
|
223
|
-
* @returns A hash function state
|
|
224
|
-
*/
|
|
225
|
-
constructor() {
|
|
226
|
-
this.st = Internal._hashInit();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Compute a hash for a single-part message
|
|
231
|
-
* @param m Message
|
|
232
|
-
* @returns Hash
|
|
233
|
-
*/
|
|
234
|
-
static hash(m: Uint8Array): Uint8Array {
|
|
235
|
-
let h = new Uint8Array(<aisize>SHA256_HASH_BYTES);
|
|
236
|
-
Internal._hash(h, m, m.length);
|
|
237
|
-
return h;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* HMAC-SHA-256
|
|
242
|
-
* @param m Message
|
|
243
|
-
* @param k Key
|
|
244
|
-
* @returns `HMAC-SHA-256(m, k)`
|
|
245
|
-
*/
|
|
246
|
-
static hmac(m: Uint8Array, k: Uint8Array): Uint8Array {
|
|
247
|
-
return Internal._hmac(m, k);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Hash256
|
|
252
|
-
* @param {Uint8Array} m Message
|
|
253
|
-
* @returns {Uint8Array} `SHA-256(SHA-256(m))`
|
|
254
|
-
*/
|
|
255
|
-
static hash256(m: Uint8Array): Uint8Array {
|
|
256
|
-
return Sha256.hash(Sha256.hash(m));
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Absorb data to be hashed
|
|
261
|
-
* @param m (partial) message
|
|
262
|
-
*/
|
|
263
|
-
update(m: Uint8Array): void {
|
|
264
|
-
let n = m.length;
|
|
265
|
-
this.t += n;
|
|
266
|
-
this.r = Internal._hashUpdate(this.st, m, n, this.r as isize);
|
|
4
|
+
static hash(buffer: Uint8Array): Uint8Array {
|
|
5
|
+
return sha256(buffer);
|
|
267
6
|
}
|
|
268
7
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
*/
|
|
273
|
-
final(): Uint8Array {
|
|
274
|
-
let h = new Uint8Array(<aisize>SHA256_HASH_BYTES);
|
|
275
|
-
Internal._hashFinal(this.st, h, this.t as isize, this.r as isize);
|
|
276
|
-
return h;
|
|
8
|
+
static hash256(buffer: Uint8Array): Uint8Array {
|
|
9
|
+
const hash = sha256(buffer);
|
|
10
|
+
return sha256(hash);
|
|
277
11
|
}
|
|
278
12
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { u256 } from 'as-bignum/assembly/integer/u256';
|
|
2
|
+
import { encodeSelector, Selector } from '../math/abi';
|
|
3
|
+
import { Address } from '../types/Address';
|
|
4
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
5
|
+
import { Blockchain } from '../env';
|
|
6
|
+
import { Revert } from '../types/Revert';
|
|
7
|
+
|
|
8
|
+
export class TransferHelper {
|
|
9
|
+
public static get APPROVE_SELECTOR(): Selector {
|
|
10
|
+
return encodeSelector('approve');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static get TRANSFER_SELECTOR(): Selector {
|
|
14
|
+
return encodeSelector('transfer');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static get TRANSFER_FROM_SELECTOR(): Selector {
|
|
18
|
+
return encodeSelector('transferFrom');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static safeApprove(token: Address, spender: Address, amount: u256): void {
|
|
22
|
+
const calldata = new BytesWriter();
|
|
23
|
+
calldata.writeSelector(this.APPROVE_SELECTOR);
|
|
24
|
+
calldata.writeAddress(spender);
|
|
25
|
+
calldata.writeU256(amount);
|
|
26
|
+
|
|
27
|
+
const response = Blockchain.call(token, calldata);
|
|
28
|
+
const isOk = response.readBoolean();
|
|
29
|
+
|
|
30
|
+
if (!isOk) {
|
|
31
|
+
throw new Revert(`TransferHelper: APPROVE_FAILED`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static safeTransfer(token: Address, to: Address, amount: u256): void {
|
|
36
|
+
const calldata = new BytesWriter();
|
|
37
|
+
calldata.writeSelector(this.TRANSFER_SELECTOR);
|
|
38
|
+
calldata.writeAddress(to);
|
|
39
|
+
calldata.writeU256(amount);
|
|
40
|
+
|
|
41
|
+
const response = Blockchain.call(token, calldata);
|
|
42
|
+
const isOk = response.readBoolean();
|
|
43
|
+
|
|
44
|
+
if (!isOk) {
|
|
45
|
+
throw new Revert(`TransferHelper: TRANSFER_FAILED`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static safeTransferFrom(token: Address, from: Address, to: Address, amount: u256): void {
|
|
50
|
+
const calldata = new BytesWriter();
|
|
51
|
+
calldata.writeSelector(this.TRANSFER_FROM_SELECTOR);
|
|
52
|
+
|
|
53
|
+
calldata.writeAddress(from);
|
|
54
|
+
calldata.writeAddress(to);
|
|
55
|
+
calldata.writeU256(amount);
|
|
56
|
+
|
|
57
|
+
const response = Blockchain.call(token, calldata);
|
|
58
|
+
const isOk = response.readBoolean();
|
|
59
|
+
|
|
60
|
+
if (!isOk) {
|
|
61
|
+
throw new Revert(`TransferHelper: TRANSFER_FROM_FAILED`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|