@layerzerolabs/onesig-core 0.0.7 → 0.0.9
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/dist/index.d.mts +51 -0
- package/dist/index.js +8 -6
- package/dist/index.mjs +245 -0
- package/package.json +4 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { BigNumber } from 'ethers';
|
|
2
|
+
import { MerkleTree } from 'merkletreejs';
|
|
3
|
+
export { MerkleTree } from 'merkletreejs';
|
|
4
|
+
import { TypedDataSigner } from '@ethersproject/abstract-signer';
|
|
5
|
+
|
|
6
|
+
interface BaseLeafData<TargetAddressType = unknown, CallData = unknown> {
|
|
7
|
+
nonce: bigint;
|
|
8
|
+
oneSigId: bigint;
|
|
9
|
+
targetOneSigAddress: TargetAddressType;
|
|
10
|
+
calls: CallData[];
|
|
11
|
+
}
|
|
12
|
+
interface SigningOptions {
|
|
13
|
+
seed: string | Uint8Array;
|
|
14
|
+
expiry: number | string | BigNumber;
|
|
15
|
+
}
|
|
16
|
+
interface GenerateLeafsResult<Leaf extends BaseLeafData = BaseLeafData<any, any>> {
|
|
17
|
+
encodeCalls: (calls: Leaf['calls']) => Buffer;
|
|
18
|
+
encodeAddress: (address: Leaf['targetOneSigAddress']) => Buffer;
|
|
19
|
+
leafs: Leaf[];
|
|
20
|
+
}
|
|
21
|
+
declare function encodeLeafHeader({ targetOneSigAddress, oneSigId, nonce }: Omit<BaseLeafData<Buffer>, 'calls'>): Buffer;
|
|
22
|
+
declare function encodeLeaf(gen: GenerateLeafsResult, index: number): string;
|
|
23
|
+
declare function makeOneSigTree(input: GenerateLeafsResult[]): MerkleTree;
|
|
24
|
+
declare function compareAddresses(a: string, b: string): number;
|
|
25
|
+
type HexStringLike = `0x${string}`;
|
|
26
|
+
type SignatureLike = Buffer | string | Signature | HexStringLike;
|
|
27
|
+
declare class Signature {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(input: SignatureLike);
|
|
30
|
+
get(): Buffer;
|
|
31
|
+
toHexString(): HexStringLike;
|
|
32
|
+
get signatureCount(): number;
|
|
33
|
+
/**
|
|
34
|
+
* Concatenate signatures without changing ordering
|
|
35
|
+
*/
|
|
36
|
+
static concatenateSignatures(input: SignatureLike[], sortMethod: false): Signature;
|
|
37
|
+
/**
|
|
38
|
+
* Concatenate signatures based on addresses provided, with each signature corresponding to the address in the same index
|
|
39
|
+
*/
|
|
40
|
+
static concatenateSignatures(input: SignatureLike[], addresses: string[]): Signature;
|
|
41
|
+
/**
|
|
42
|
+
* Concatenate signatures based on the signature data, ordering based on the recovered address
|
|
43
|
+
*/
|
|
44
|
+
static concatenateSignatures(input: SignatureLike[], digest: Buffer | string): Signature;
|
|
45
|
+
}
|
|
46
|
+
declare function getSigningData(tree: MerkleTree, { seed, expiry }: SigningOptions): Parameters<TypedDataSigner['_signTypedData']>;
|
|
47
|
+
declare function getDigestToSign(tree: MerkleTree, options: SigningOptions): string;
|
|
48
|
+
declare function signOneSigTree(tree: MerkleTree, signers: TypedDataSigner[], options: SigningOptions, enc?: 'string'): Promise<string>;
|
|
49
|
+
declare function signOneSigTree(tree: MerkleTree, signers: TypedDataSigner[], options: SigningOptions, enc: 'signature'): Promise<Signature>;
|
|
50
|
+
|
|
51
|
+
export { type BaseLeafData, type GenerateLeafsResult, Signature, type SigningOptions, compareAddresses, encodeLeaf, encodeLeafHeader, getDigestToSign, getSigningData, makeOneSigTree, signOneSigTree };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -75,16 +76,16 @@ function encodeLeafHeader({ targetOneSigAddress, oneSigId, nonce }) {
|
|
|
75
76
|
if (targetOneSigAddress.byteLength !== 32) {
|
|
76
77
|
throw new Error("Contract address must be 32 bytes");
|
|
77
78
|
}
|
|
78
|
-
const storage = Buffer.alloc(
|
|
79
|
+
const storage = Buffer.alloc(49);
|
|
79
80
|
storage[0] = 1;
|
|
80
81
|
const idStr = oneSigId.toString(16).padStart(16, "0");
|
|
81
|
-
const nonceStr = nonce.toString(16).padStart(
|
|
82
|
+
const nonceStr = nonce.toString(16).padStart(16, "0");
|
|
82
83
|
for (let i = 0; i < 32; i++) {
|
|
83
84
|
if (i < 8) {
|
|
84
85
|
storage[i + 1] = readByteFromHex(idStr, i);
|
|
86
|
+
storage[i + 41] = readByteFromHex(nonceStr, i);
|
|
85
87
|
}
|
|
86
88
|
storage[i + 9] = targetOneSigAddress[i];
|
|
87
|
-
storage[i + 41] = readByteFromHex(nonceStr, i);
|
|
88
89
|
}
|
|
89
90
|
return storage;
|
|
90
91
|
}
|
|
@@ -101,7 +102,7 @@ function encodeLeaf(gen, index) {
|
|
|
101
102
|
}),
|
|
102
103
|
gen.encodeCalls(leaf.calls)
|
|
103
104
|
]);
|
|
104
|
-
return import_ethers.ethers.utils.keccak256(leafData);
|
|
105
|
+
return import_ethers.ethers.utils.keccak256(import_ethers.ethers.utils.keccak256(leafData));
|
|
105
106
|
}
|
|
106
107
|
function makeOneSigTree(input) {
|
|
107
108
|
const encodedLeafs = [];
|
|
@@ -184,7 +185,7 @@ var _Signature = class _Signature {
|
|
|
184
185
|
return signature.get();
|
|
185
186
|
});
|
|
186
187
|
let orderedSignatures;
|
|
187
|
-
if (
|
|
188
|
+
if (sortMethod === false) {
|
|
188
189
|
orderedSignatures = signatureBuffers;
|
|
189
190
|
} else {
|
|
190
191
|
let addresses;
|
|
@@ -208,7 +209,8 @@ var _Signature = class _Signature {
|
|
|
208
209
|
});
|
|
209
210
|
orderedSignatures = indexMapping.map((index) => signatureBuffers[index]);
|
|
210
211
|
}
|
|
211
|
-
|
|
212
|
+
const combined = Buffer.concat(orderedSignatures);
|
|
213
|
+
return new this(combined);
|
|
212
214
|
}
|
|
213
215
|
};
|
|
214
216
|
_value = new WeakMap();
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
var __typeError = (msg) => {
|
|
2
|
+
throw TypeError(msg);
|
|
3
|
+
};
|
|
4
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
import { ethers } from "ethers";
|
|
11
|
+
import { MerkleTree } from "merkletreejs";
|
|
12
|
+
|
|
13
|
+
// src/error.ts
|
|
14
|
+
var _code;
|
|
15
|
+
var _OneSigCoreError = class _OneSigCoreError extends Error {
|
|
16
|
+
constructor(code, message) {
|
|
17
|
+
super(`[${code}] ${message}`);
|
|
18
|
+
__privateAdd(this, _code);
|
|
19
|
+
__privateSet(this, _code, code);
|
|
20
|
+
}
|
|
21
|
+
get code() {
|
|
22
|
+
return __privateGet(this, _code);
|
|
23
|
+
}
|
|
24
|
+
static is(input, code) {
|
|
25
|
+
if (input instanceof _OneSigCoreError) {
|
|
26
|
+
if (code) {
|
|
27
|
+
return input.code === code;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
} else {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
_code = new WeakMap();
|
|
36
|
+
var OneSigCoreError = _OneSigCoreError;
|
|
37
|
+
|
|
38
|
+
// src/index.ts
|
|
39
|
+
function readByteFromHex(input, byteOffset) {
|
|
40
|
+
const charOffset = byteOffset * 2;
|
|
41
|
+
const sub = input.substring(charOffset, charOffset + 2);
|
|
42
|
+
return parseInt(sub, 16);
|
|
43
|
+
}
|
|
44
|
+
function encodeLeafHeader({ targetOneSigAddress, oneSigId, nonce }) {
|
|
45
|
+
if (targetOneSigAddress.byteLength !== 32) {
|
|
46
|
+
throw new Error("Contract address must be 32 bytes");
|
|
47
|
+
}
|
|
48
|
+
const storage = Buffer.alloc(49);
|
|
49
|
+
storage[0] = 1;
|
|
50
|
+
const idStr = oneSigId.toString(16).padStart(16, "0");
|
|
51
|
+
const nonceStr = nonce.toString(16).padStart(16, "0");
|
|
52
|
+
for (let i = 0; i < 32; i++) {
|
|
53
|
+
if (i < 8) {
|
|
54
|
+
storage[i + 1] = readByteFromHex(idStr, i);
|
|
55
|
+
storage[i + 41] = readByteFromHex(nonceStr, i);
|
|
56
|
+
}
|
|
57
|
+
storage[i + 9] = targetOneSigAddress[i];
|
|
58
|
+
}
|
|
59
|
+
return storage;
|
|
60
|
+
}
|
|
61
|
+
function encodeLeaf(gen, index) {
|
|
62
|
+
const leaf = gen.leafs[index];
|
|
63
|
+
if (!leaf) {
|
|
64
|
+
throw new Error("Leaf does not exist");
|
|
65
|
+
}
|
|
66
|
+
const leafData = Buffer.concat([
|
|
67
|
+
encodeLeafHeader({
|
|
68
|
+
nonce: leaf.nonce,
|
|
69
|
+
oneSigId: leaf.oneSigId,
|
|
70
|
+
targetOneSigAddress: gen.encodeAddress(leaf.targetOneSigAddress)
|
|
71
|
+
}),
|
|
72
|
+
gen.encodeCalls(leaf.calls)
|
|
73
|
+
]);
|
|
74
|
+
return ethers.utils.keccak256(ethers.utils.keccak256(leafData));
|
|
75
|
+
}
|
|
76
|
+
function makeOneSigTree(input) {
|
|
77
|
+
const encodedLeafs = [];
|
|
78
|
+
const seenNonceIds = /* @__PURE__ */ new Set();
|
|
79
|
+
for (const gen of input) {
|
|
80
|
+
for (let i = 0; i < gen.leafs.length; i++) {
|
|
81
|
+
const leaf = gen.leafs[i];
|
|
82
|
+
const nonceIdCombo = `${leaf.nonce}.${leaf.oneSigId}`;
|
|
83
|
+
if (seenNonceIds.has(nonceIdCombo)) {
|
|
84
|
+
throw new OneSigCoreError(
|
|
85
|
+
"NONCE_ID_SEEN_TWICE",
|
|
86
|
+
"Two calls should not be made for the same chain/nonce twice"
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
seenNonceIds.add(nonceIdCombo);
|
|
90
|
+
encodedLeafs.push(encodeLeaf(gen, i));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const tree = new MerkleTree(encodedLeafs, ethers.utils.keccak256, { sortPairs: true });
|
|
94
|
+
return tree;
|
|
95
|
+
}
|
|
96
|
+
function compareAddresses(a, b) {
|
|
97
|
+
const aNumeric = BigInt(a);
|
|
98
|
+
const bNumeric = BigInt(b);
|
|
99
|
+
if (aNumeric === bNumeric) {
|
|
100
|
+
return 0;
|
|
101
|
+
} else if (aNumeric < bNumeric) {
|
|
102
|
+
return -1;
|
|
103
|
+
} else {
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
var _value;
|
|
108
|
+
var _Signature = class _Signature {
|
|
109
|
+
constructor(input) {
|
|
110
|
+
__privateAdd(this, _value);
|
|
111
|
+
let value = input;
|
|
112
|
+
if (value instanceof _Signature) {
|
|
113
|
+
value = value.get();
|
|
114
|
+
}
|
|
115
|
+
if (typeof value === "string") {
|
|
116
|
+
if (!value.startsWith("0x")) {
|
|
117
|
+
throw new OneSigCoreError(
|
|
118
|
+
"INVALID_SIGNATURE_INPUT",
|
|
119
|
+
"Signature takes in hex encoded strings prefixed with 0x only"
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
value = Buffer.from(value.substring(2), "hex");
|
|
123
|
+
}
|
|
124
|
+
if (value.length % 65 !== 0) {
|
|
125
|
+
throw new OneSigCoreError("INVALID_SIGNATURE_INPUT", "Each signature must be 65 bytes long");
|
|
126
|
+
}
|
|
127
|
+
__privateSet(this, _value, value);
|
|
128
|
+
}
|
|
129
|
+
get() {
|
|
130
|
+
return __privateGet(this, _value);
|
|
131
|
+
}
|
|
132
|
+
toHexString() {
|
|
133
|
+
return `0x${this.get().toString("hex")}`;
|
|
134
|
+
}
|
|
135
|
+
get signatureCount() {
|
|
136
|
+
const count = __privateGet(this, _value).length / 65;
|
|
137
|
+
if (Math.floor(count) !== count) {
|
|
138
|
+
throw new Error("Count is not an int");
|
|
139
|
+
}
|
|
140
|
+
return count;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Concatenate and order signatures based on data provided
|
|
144
|
+
* @param input An array of signatures to concat
|
|
145
|
+
* @param sortMethod Parameter specifing how to order each signature
|
|
146
|
+
* @returns The concatenated signature
|
|
147
|
+
*/
|
|
148
|
+
static concatenateSignatures(input, sortMethod) {
|
|
149
|
+
const signatureBuffers = input.map(function(singleInput) {
|
|
150
|
+
const signature = new _Signature(singleInput);
|
|
151
|
+
if (signature.signatureCount !== 1) {
|
|
152
|
+
throw new OneSigCoreError("CANNOT_CONCAT_INPUT", "Cannot concatenate pre-concatenated signatures");
|
|
153
|
+
}
|
|
154
|
+
return signature.get();
|
|
155
|
+
});
|
|
156
|
+
let orderedSignatures;
|
|
157
|
+
if (sortMethod === false) {
|
|
158
|
+
orderedSignatures = signatureBuffers;
|
|
159
|
+
} else {
|
|
160
|
+
let addresses;
|
|
161
|
+
if (typeof sortMethod === "string" || Buffer.isBuffer(sortMethod)) {
|
|
162
|
+
addresses = [];
|
|
163
|
+
for (const signature of signatureBuffers) {
|
|
164
|
+
const recovered = ethers.utils.recoverAddress(sortMethod, signature);
|
|
165
|
+
addresses.push(recovered);
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
addresses = sortMethod;
|
|
169
|
+
}
|
|
170
|
+
if (addresses.length !== signatureBuffers.length) {
|
|
171
|
+
throw new OneSigCoreError(
|
|
172
|
+
"ADDRESS_SIGNATURE_LENGTH_MISMATCH",
|
|
173
|
+
"Mismatch in addresses provided signatures"
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
const indexMapping = new Array(addresses.length).fill(0).map((_, i) => i).sort(function(a, b) {
|
|
177
|
+
return compareAddresses(addresses[a], addresses[b]);
|
|
178
|
+
});
|
|
179
|
+
orderedSignatures = indexMapping.map((index) => signatureBuffers[index]);
|
|
180
|
+
}
|
|
181
|
+
const combined = Buffer.concat(orderedSignatures);
|
|
182
|
+
return new this(combined);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
_value = new WeakMap();
|
|
186
|
+
var Signature = _Signature;
|
|
187
|
+
function getSigningData(tree, { seed, expiry }) {
|
|
188
|
+
return [
|
|
189
|
+
{
|
|
190
|
+
name: "OneSig",
|
|
191
|
+
version: "0.0.1",
|
|
192
|
+
chainId: 1,
|
|
193
|
+
// this is hardcoded to Ethereum mainnet
|
|
194
|
+
verifyingContract: "0x000000000000000000000000000000000000dEaD"
|
|
195
|
+
// this is hardcoded to a dead address
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
SignMerkleRoot: [
|
|
199
|
+
{ name: "seed", type: "bytes32" },
|
|
200
|
+
{ name: "merkleRoot", type: "bytes32" },
|
|
201
|
+
{ name: "expiry", type: "uint256" }
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
seed,
|
|
206
|
+
expiry,
|
|
207
|
+
merkleRoot: tree.getRoot()
|
|
208
|
+
}
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
function getDigestToSign(tree, options) {
|
|
212
|
+
return ethers.utils._TypedDataEncoder.hash(...getSigningData(tree, options));
|
|
213
|
+
}
|
|
214
|
+
async function signOneSigTree(tree, signers, options, enc = "string") {
|
|
215
|
+
if (signers.length <= 0) {
|
|
216
|
+
throw new OneSigCoreError("ONE_SIGNER_REQUIRED", "1+ signer must be provided");
|
|
217
|
+
}
|
|
218
|
+
const toSign = getSigningData(tree, options);
|
|
219
|
+
const signatures = await Promise.all(
|
|
220
|
+
signers.map(async function(signer) {
|
|
221
|
+
const data = await signer._signTypedData(...toSign);
|
|
222
|
+
return new Signature(data);
|
|
223
|
+
})
|
|
224
|
+
);
|
|
225
|
+
const signingDigest = ethers.utils._TypedDataEncoder.hash(...toSign);
|
|
226
|
+
const sig = Signature.concatenateSignatures(signatures, signingDigest);
|
|
227
|
+
if (enc === "signature") {
|
|
228
|
+
return sig;
|
|
229
|
+
} else if (enc === "string") {
|
|
230
|
+
return sig.toHexString();
|
|
231
|
+
} else {
|
|
232
|
+
throw new Error("Invalid encoding");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
export {
|
|
236
|
+
MerkleTree,
|
|
237
|
+
Signature,
|
|
238
|
+
compareAddresses,
|
|
239
|
+
encodeLeaf,
|
|
240
|
+
encodeLeafHeader,
|
|
241
|
+
getDigestToSign,
|
|
242
|
+
getSigningData,
|
|
243
|
+
makeOneSigTree,
|
|
244
|
+
signOneSigTree
|
|
245
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/onesig-core",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"license": "
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"license": "GPL-3.0-only",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"./package.json": "./package.json"
|
|
12
12
|
},
|
|
13
13
|
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
14
15
|
"files": [
|
|
15
16
|
"dist/**/*"
|
|
16
17
|
],
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
"access": "restricted"
|
|
59
60
|
},
|
|
60
61
|
"scripts": {
|
|
61
|
-
"build:js": "pnpm tsup",
|
|
62
|
+
"build:js": "pnpm tsup --config ../../tsup.config.ts ./src/index.ts",
|
|
62
63
|
"clean": "pnpm clean:prebuild",
|
|
63
64
|
"clean:prebuild": "rimraf dist",
|
|
64
65
|
"lint:fix": "eslint --fix '**/*.{js,ts,json}' && prettier --write .",
|