-
Notifications
You must be signed in to change notification settings - Fork 59
/
Memory.ts
144 lines (131 loc) · 4.91 KB
/
Memory.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import AccountBase from './Base';
import {
generateKeyPairFromSecret, sign, generateKeyPair, hash, messageToHash,
} from '../utils/crypto';
import { ArgumentError } from '../utils/errors';
import {
decode, encode, Encoded, Encoding,
} from '../utils/encoder';
import { concatBuffers } from '../utils/other';
import { hashTypedData, AciValue } from '../utils/typed-data';
import { buildTx } from '../tx/builder';
import { Tag, AensName } from '../tx/builder/constants';
import { produceNameId } from '../tx/builder/helpers';
const secretKeys = new WeakMap();
export function getBufferToSign(
transaction: Encoded.Transaction,
networkId: string,
innerTx: boolean,
): Uint8Array {
const prefixes = [networkId];
if (innerTx) prefixes.push('inner_tx');
const rlpBinaryTx = decode(transaction);
return concatBuffers([Buffer.from(prefixes.join('-')), hash(rlpBinaryTx)]);
}
/**
* In-memory account class
*/
export default class AccountMemory extends AccountBase {
override readonly address: Encoded.AccountAddress;
/**
* @param secretKey - Secret key
*/
constructor(secretKey: string | Uint8Array) {
super();
secretKey = typeof secretKey === 'string' ? Buffer.from(secretKey, 'hex') : secretKey;
if (secretKey.length !== 64) {
throw new ArgumentError('secretKey', '64 bytes', secretKey.length);
}
secretKeys.set(this, secretKey);
this.address = encode(
generateKeyPairFromSecret(secretKeys.get(this)).publicKey,
Encoding.AccountAddress,
);
}
/**
* Generates a new AccountMemory using a random secret key
*/
static generate(): AccountMemory {
return new AccountMemory(generateKeyPair().secretKey);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override async sign(data: string | Uint8Array, options?: any): Promise<Uint8Array> {
return sign(data, secretKeys.get(this));
}
override async signTransaction(
transaction: Encoded.Transaction,
{ innerTx, networkId, ...options }: { innerTx?: boolean; networkId?: string } = {},
): Promise<Encoded.Transaction> {
if (networkId == null) {
throw new ArgumentError('networkId', 'provided', networkId);
}
const rlpBinaryTx = decode(transaction);
const txWithNetworkId = getBufferToSign(transaction, networkId, innerTx === true);
const signatures = [await this.sign(txWithNetworkId, options)];
return buildTx({ tag: Tag.SignedTx, encodedTx: rlpBinaryTx, signatures });
}
override async signMessage(message: string, options?: any): Promise<Uint8Array> {
return this.sign(messageToHash(message), options);
}
override async signTypedData(
data: Encoded.ContractBytearray,
aci: AciValue,
{
name, version, networkId, contractAddress, ...options
}: Parameters<AccountBase['signTypedData']>[2] = {},
): Promise<Encoded.Signature> {
const dHash = hashTypedData(data, aci, {
name, version, networkId, contractAddress,
});
const signature = await this.sign(dHash, options);
return encode(signature, Encoding.Signature);
}
override async signDelegationToContract(
contractAddress: Encoded.ContractAddress,
{ networkId }: { networkId?: string } = {},
): Promise<Encoded.Signature> {
if (networkId == null) throw new ArgumentError('networkId', 'provided', networkId);
const payload = concatBuffers([
Buffer.from(networkId),
decode(this.address),
decode(contractAddress),
]);
const signature = await this.sign(payload);
return encode(signature, Encoding.Signature);
}
override async signNameDelegationToContract(
contractAddress: Encoded.ContractAddress,
name: AensName,
{ networkId }: { networkId?: string } = {},
): Promise<Encoded.Signature> {
if (networkId == null) throw new ArgumentError('networkId', 'provided', networkId);
const payload = concatBuffers([
Buffer.from(networkId),
decode(this.address),
decode(produceNameId(name)),
decode(contractAddress),
]);
const signature = await this.sign(payload);
return encode(signature, Encoding.Signature);
}
override async signOracleQueryDelegationToContract(
contractAddress: Encoded.ContractAddress,
oracleQueryId: Encoded.OracleQueryId,
{ networkId }: { networkId?: string } = {},
): Promise<Encoded.Signature> {
const oracleQueryIdDecoded = decode(oracleQueryId);
const addressDecoded = decode(this.address);
// TODO: remove after fixing https://github.com/aeternity/aesophia/issues/475
if (oracleQueryIdDecoded.compare(addressDecoded) === 0) {
throw new ArgumentError('oracleQueryId', 'not equal to account address', oracleQueryId);
}
if (networkId == null) throw new ArgumentError('networkId', 'provided', networkId);
const payload = concatBuffers([
Buffer.from(networkId),
oracleQueryIdDecoded,
decode(contractAddress),
]);
const signature = await this.sign(payload);
return encode(signature, Encoding.Signature);
}
}