@layerzerolabs/onesig-evm 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.
Files changed (29) hide show
  1. package/artifacts/contracts/MultiSig.sol/MultiSig.json +1 -1
  2. package/artifacts/contracts/OneSig.sol/OneSig.json +16 -11
  3. package/artifacts/contracts/lib/SelfCallable.sol/SelfCallable.json +16 -0
  4. package/artifacts-tron/contracts/MultiSig.sol/MultiSig.json +1 -1
  5. package/artifacts-tron/contracts/OneSig.sol/OneSig.json +16 -11
  6. package/artifacts-tron/contracts/lib/SelfCallable.sol/SelfCallable.json +16 -0
  7. package/artifacts-zk/contracts/MultiSig.sol/MultiSig.json +1 -1
  8. package/artifacts-zk/contracts/OneSig.sol/OneSig.json +16 -11
  9. package/artifacts-zk/contracts/lib/SelfCallable.sol/SelfCallable.json +17 -0
  10. package/contracts/MultiSig.sol +14 -19
  11. package/contracts/OneSig.sol +29 -27
  12. package/contracts/lib/SelfCallable.sol +16 -0
  13. package/dist/index.js +1 -0
  14. package/package.json +5 -4
  15. package/typechain-types/@openzeppelin/contracts/utils/ReentrancyGuard.ts +55 -0
  16. package/typechain-types/@openzeppelin/contracts/utils/index.ts +1 -0
  17. package/typechain-types/contracts/OneSig.ts +1 -1
  18. package/typechain-types/contracts/index.ts +2 -0
  19. package/typechain-types/contracts/lib/SelfCallable.ts +55 -0
  20. package/typechain-types/contracts/lib/index.ts +4 -0
  21. package/typechain-types/factories/@openzeppelin/contracts/utils/ReentrancyGuard__factory.ts +31 -0
  22. package/typechain-types/factories/@openzeppelin/contracts/utils/index.ts +1 -0
  23. package/typechain-types/factories/contracts/MultiSig__factory.ts +1 -1
  24. package/typechain-types/factories/contracts/OneSig__factory.ts +15 -10
  25. package/typechain-types/factories/contracts/index.ts +1 -0
  26. package/typechain-types/factories/contracts/lib/SelfCallable__factory.ts +31 -0
  27. package/typechain-types/factories/contracts/lib/index.ts +4 -0
  28. package/typechain-types/hardhat.d.ts +18 -0
  29. package/typechain-types/index.ts +4 -0
@@ -1,10 +1,10 @@
1
- // SPDX-License-Identifier: LZBL-1.2
2
- // TODO confirm the license
1
+ // SPDX-License-Identifier: GPL-3.0
3
2
 
4
3
  pragma solidity ^0.8.22;
5
4
 
6
5
  import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
7
6
  import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
7
+ import { SelfCallable } from "./lib/SelfCallable.sol";
8
8
 
9
9
  /**
10
10
  * @title MultiSig
@@ -12,7 +12,7 @@ import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableS
12
12
  * Designed to be inherited by contracts requiring multi-signature verification.
13
13
  * @dev Uses EnumerableSet to store signer addresses and ECDSA for signature recovery.
14
14
  */
15
- abstract contract MultiSig {
15
+ abstract contract MultiSig is SelfCallable {
16
16
  using EnumerableSet for EnumerableSet.AddressSet;
17
17
 
18
18
  /**
@@ -28,9 +28,6 @@ abstract contract MultiSig {
28
28
  /// @notice Error thrown when a signer address is invalid.
29
29
  error InvalidSigner();
30
30
 
31
- /// @notice Error thrown when a function is not called from this contract itself.
32
- error OnlyMultiSig();
33
-
34
31
  /// @notice Error thrown when the threshold is set to zero.
35
32
  error ZeroThreshold();
36
33
 
@@ -67,12 +64,9 @@ abstract contract MultiSig {
67
64
  event ThresholdSet(uint256 threshold);
68
65
 
69
66
  /**
70
- * @dev Restricts access to functions so they can only be called via this contract itself.
67
+ * @dev The length of a single signature in bytes (r=32, s=32, v=1).
71
68
  */
72
- modifier onlyMultiSig() {
73
- if (msg.sender != address(this)) revert OnlyMultiSig();
74
- _;
75
- }
69
+ uint8 constant SIGNATURE_LENGTH = 65;
76
70
 
77
71
  /**
78
72
  * @dev Initializes the MultiSig with a list of signers and sets the signature threshold.
@@ -91,7 +85,7 @@ abstract contract MultiSig {
91
85
  * @dev This function can only be called by the MultiSig contract itself.
92
86
  * @param _threshold The new threshold value.
93
87
  */
94
- function setThreshold(uint256 _threshold) external onlyMultiSig {
88
+ function setThreshold(uint256 _threshold) external onlySelfCall {
95
89
  _setThreshold(_threshold);
96
90
  }
97
91
 
@@ -115,7 +109,7 @@ abstract contract MultiSig {
115
109
  * @param _signer The address of the signer to add/remove.
116
110
  * @param _active True to add signer, false to remove signer.
117
111
  */
118
- function setSigner(address _signer, bool _active) external onlyMultiSig {
112
+ function setSigner(address _signer, bool _active) external onlySelfCall {
119
113
  if (_active) {
120
114
  _addSigner(_signer);
121
115
  } else {
@@ -172,22 +166,23 @@ abstract contract MultiSig {
172
166
  */
173
167
  function verifyNSignatures(bytes32 _digest, bytes calldata _signatures, uint256 _threshold) public view {
174
168
  if (_threshold == 0) revert ZeroThreshold();
175
- // Each signature is 65 bytes (r=32, s=32, v=1).
176
- if (_signatures.length != _threshold * 65) revert SignatureError();
169
+ // Each signature is SIGNATURE_LENGTH (65) bytes (r=32, s=32, v=1).
170
+ if ((_signatures.length % SIGNATURE_LENGTH) != 0) revert SignatureError();
171
+ uint256 signaturesCount = _signatures.length / SIGNATURE_LENGTH;
172
+ if (signaturesCount < _threshold) revert SignatureError();
177
173
 
178
174
  // There cannot be a signer with address 0, so we start with address(0) to ensure ascending order.
179
175
  address lastSigner = address(0);
180
176
 
181
- for (uint256 i = 0; i < _threshold; i++) {
182
- // Extract a single signature (65 bytes) at a time.
183
- bytes calldata signature = _signatures[i * 65:(i + 1) * 65];
177
+ for (uint256 i = 0; i < signaturesCount; i++) {
178
+ // Extract a single signature (SIGNATURE_LENGTH (65) bytes) at a time.
179
+ bytes calldata signature = _signatures[i * SIGNATURE_LENGTH:(i + 1) * SIGNATURE_LENGTH];
184
180
  address currentSigner = ECDSA.recover(_digest, signature);
185
181
 
186
182
  // Check ordering to avoid duplicates and ensure strictly increasing addresses.
187
183
  if (currentSigner <= lastSigner) revert UnsortedSigners();
188
184
  // Check if the signer is in our set.
189
185
  if (!isSigner(currentSigner)) revert SignerNotFound(currentSigner);
190
-
191
186
  lastSigner = currentSigner;
192
187
  }
193
188
  }
@@ -1,9 +1,9 @@
1
- // SPDX-License-Identifier: LZBL-1.2
2
- // TODO confirm the license
1
+ // SPDX-License-Identifier: GPL-3.0
3
2
 
4
3
  pragma solidity ^0.8.22;
5
4
 
6
5
  import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
6
+ import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
7
7
  import { MultiSig } from "./MultiSig.sol";
8
8
 
9
9
  /**
@@ -14,7 +14,7 @@ import { MultiSig } from "./MultiSig.sol";
14
14
  * provided the Merkle proof is valid and the threshold of signers is met.
15
15
  * @dev Inherits from MultiSig for signature threshold logic.
16
16
  */
17
- contract OneSig is MultiSig {
17
+ contract OneSig is MultiSig, ReentrancyGuard {
18
18
  /// @notice The version string of the OneSig contract.
19
19
  string public constant VERSION = "0.0.1";
20
20
 
@@ -47,7 +47,7 @@ contract OneSig is MultiSig {
47
47
  abi.encode(
48
48
  EIP712DOMAIN_TYPE_HASH,
49
49
  keccak256(bytes("OneSig")), // this contract name
50
- keccak256(bytes("0.0.1")), // version
50
+ keccak256(bytes(VERSION)), // version
51
51
  1, // Ethereum mainnet chainId
52
52
  address(0xdEaD) // verifyingContract
53
53
  )
@@ -64,7 +64,7 @@ contract OneSig is MultiSig {
64
64
  * @dev Because the oneSigId is part of the leaf, the same signatures can be used on different chains,
65
65
  * while leaving each transaction to be targetted towards one
66
66
  */
67
- uint256 public immutable ONE_SIG_ID;
67
+ uint64 public immutable ONE_SIG_ID;
68
68
 
69
69
  /**
70
70
  * @notice A random seed encoded into the signatures/root.
@@ -75,7 +75,7 @@ contract OneSig is MultiSig {
75
75
  /**
76
76
  * @notice A sequential nonce to prevent replay attacks and enforce transaction ordering.
77
77
  */
78
- uint256 public nonce;
78
+ uint64 public nonce;
79
79
 
80
80
  /// @notice Emitted when the seed is updated.
81
81
  event SeedSet(bytes32 seed);
@@ -134,23 +134,29 @@ contract OneSig is MultiSig {
134
134
  constructor(
135
135
  address[] memory _signers,
136
136
  uint256 _threshold,
137
- uint256 _oneSigId,
137
+ uint64 _oneSigId,
138
138
  bytes32 _seed
139
139
  ) MultiSig(_signers, _threshold) {
140
140
  ONE_SIG_ID = _oneSigId;
141
+ _setSeed(_seed);
142
+ }
141
143
 
144
+ /**
145
+ * @notice Internal method to set the contract's seed.
146
+ * @param _seed The new seed value.
147
+ */
148
+ function _setSeed(bytes32 _seed) internal virtual {
142
149
  seed = _seed;
143
150
  emit SeedSet(_seed);
144
151
  }
145
152
 
146
153
  /**
147
- * @notice Sets the contract's seed.
154
+ * @notice External method to set the contract's seed.
148
155
  * @dev Only callable via MultiSig functionality (i.e., requires threshold signatures from signers).
149
156
  * @param _seed The new seed value.
150
157
  */
151
- function setSeed(bytes32 _seed) external onlyMultiSig {
152
- seed = _seed;
153
- emit SeedSet(_seed);
158
+ function setSeed(bytes32 _seed) public virtual onlySelfCall {
159
+ _setSeed(_seed);
154
160
  }
155
161
 
156
162
  /**
@@ -167,7 +173,7 @@ contract OneSig is MultiSig {
167
173
  bytes32 _merkleRoot,
168
174
  uint256 _expiry,
169
175
  bytes calldata _signatures
170
- ) external payable {
176
+ ) public payable virtual nonReentrant {
171
177
  // Verify the merkle root and signatures
172
178
  verifyMerkleRoot(_merkleRoot, _expiry, _signatures);
173
179
 
@@ -227,28 +233,24 @@ contract OneSig is MultiSig {
227
233
  }
228
234
 
229
235
  /**
230
- * @notice Encodes the transaction leaf for inclusion in the merkle tree.
236
+ * @notice Double encodes the transaction leaf for inclusion in the merkle tree.
231
237
  * @param _nonce The nonce of the transaction.
232
238
  * @param _calls The calls to be made in this transaction.
233
239
  * @return The keccak256 hash of the encoded leaf.
234
240
  */
235
- function encodeLeaf(uint256 _nonce, Call[] calldata _calls) public view returns (bytes32) {
236
- /**
237
- * The leaves here are NOT 64 bytes long, so they do not need to be double-encoded.
238
- *
239
- * The attack relies on being able to pass the preimage of the intermediate node
240
- * (e.g., `a = h(l₁) + h(l₂)`, which is 64 bytes) as the leaf. Since this contract
241
- * does not accept 64-byte leaves, it is impossible to supply a malicious leaf
242
- * that matches the required format (`h(l₁) + h(l₂)`), thereby preventing the attack.
243
- */
241
+ function encodeLeaf(uint64 _nonce, Call[] calldata _calls) public view returns (bytes32) {
244
242
  return
245
243
  keccak256(
246
244
  abi.encodePacked(
247
- LEAF_ENCODING_VERSION,
248
- ONE_SIG_ID,
249
- bytes32(uint256(uint160(address(this)))), // convert address(this) into bytes32
250
- _nonce,
251
- abi.encode(_calls)
245
+ keccak256(
246
+ abi.encodePacked(
247
+ LEAF_ENCODING_VERSION,
248
+ ONE_SIG_ID,
249
+ bytes32(uint256(uint160(address(this)))), // convert address(this) into bytes32
250
+ _nonce,
251
+ abi.encode(_calls)
252
+ )
253
+ )
252
254
  )
253
255
  );
254
256
  }
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: GPL-3.0
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ abstract contract SelfCallable {
6
+ /// @notice Error thrown when attempting to call a function from an invalid address.
7
+ error OnlySelfCall();
8
+
9
+ /**
10
+ * @dev Restricts access to functions so they can only be called via this contract itself.
11
+ */
12
+ modifier onlySelfCall() {
13
+ if (msg.sender != address(this)) revert OnlySelfCall();
14
+ _;
15
+ }
16
+ }
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;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@layerzerolabs/onesig-evm",
3
- "version": "0.0.7",
4
- "license": "MIT",
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
  "contracts/**/*.sol",
16
17
  "artifacts/contracts/**/!(*.dbg).json",
@@ -34,7 +35,7 @@
34
35
  },
35
36
  "dependencies": {
36
37
  "ethers": "^5.7.2",
37
- "@layerzerolabs/onesig-core": "0.0.6"
38
+ "@layerzerolabs/onesig-core": "0.0.8"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@babel/core": "^7.23.9",
@@ -56,7 +57,7 @@
56
57
  "@typechain/hardhat": "^6.1.6",
57
58
  "@types/chai": "^4.3.11",
58
59
  "@types/mocha": "^10.0.6",
59
- "@types/node": "~18.18.14",
60
+ "@types/node": "20.10.0",
60
61
  "chai": "~4.3.10",
61
62
  "chai-ethers": "^0.0.1",
62
63
  "dotenv": "^16.4.1",
@@ -0,0 +1,55 @@
1
+ /* Autogenerated file. Do not edit manually. */
2
+ /* tslint:disable */
3
+ /* eslint-disable */
4
+ import type { BaseContract, Signer, utils } from "ethers";
5
+
6
+ import type { Listener, Provider } from "@ethersproject/providers";
7
+ import type {
8
+ TypedEventFilter,
9
+ TypedEvent,
10
+ TypedListener,
11
+ OnEvent,
12
+ } from "../../../common";
13
+
14
+ export interface ReentrancyGuardInterface extends utils.Interface {
15
+ functions: {};
16
+
17
+ events: {};
18
+ }
19
+
20
+ export interface ReentrancyGuard extends BaseContract {
21
+ connect(signerOrProvider: Signer | Provider | string): this;
22
+ attach(addressOrName: string): this;
23
+ deployed(): Promise<this>;
24
+
25
+ interface: ReentrancyGuardInterface;
26
+
27
+ queryFilter<TEvent extends TypedEvent>(
28
+ event: TypedEventFilter<TEvent>,
29
+ fromBlockOrBlockhash?: string | number | undefined,
30
+ toBlock?: string | number | undefined
31
+ ): Promise<Array<TEvent>>;
32
+
33
+ listeners<TEvent extends TypedEvent>(
34
+ eventFilter?: TypedEventFilter<TEvent>
35
+ ): Array<TypedListener<TEvent>>;
36
+ listeners(eventName?: string): Array<Listener>;
37
+ removeAllListeners<TEvent extends TypedEvent>(
38
+ eventFilter: TypedEventFilter<TEvent>
39
+ ): this;
40
+ removeAllListeners(eventName?: string): this;
41
+ off: OnEvent<this>;
42
+ on: OnEvent<this>;
43
+ once: OnEvent<this>;
44
+ removeListener: OnEvent<this>;
45
+
46
+ functions: {};
47
+
48
+ callStatic: {};
49
+
50
+ filters: {};
51
+
52
+ estimateGas: {};
53
+
54
+ populateTransaction: {};
55
+ }
@@ -3,3 +3,4 @@
3
3
  /* eslint-disable */
4
4
  import type * as cryptography from "./cryptography";
5
5
  export type { cryptography };
6
+ export type { ReentrancyGuard } from "./ReentrancyGuard";
@@ -57,7 +57,7 @@ export interface OneSigInterface extends utils.Interface {
57
57
  "LEAF_ENCODING_VERSION()": FunctionFragment;
58
58
  "ONE_SIG_ID()": FunctionFragment;
59
59
  "VERSION()": FunctionFragment;
60
- "encodeLeaf(uint256,(address,uint256,bytes)[])": FunctionFragment;
60
+ "encodeLeaf(uint64,(address,uint256,bytes)[])": FunctionFragment;
61
61
  "executeTransaction(((address,uint256,bytes)[],bytes32[]),bytes32,uint256,bytes)": FunctionFragment;
62
62
  "getSigners()": FunctionFragment;
63
63
  "isSigner(address)": FunctionFragment;
@@ -1,6 +1,8 @@
1
1
  /* Autogenerated file. Do not edit manually. */
2
2
  /* tslint:disable */
3
3
  /* eslint-disable */
4
+ import type * as lib from "./lib";
5
+ export type { lib };
4
6
  import type * as mocks from "./mocks";
5
7
  export type { mocks };
6
8
  export type { MultiSig } from "./MultiSig";
@@ -0,0 +1,55 @@
1
+ /* Autogenerated file. Do not edit manually. */
2
+ /* tslint:disable */
3
+ /* eslint-disable */
4
+ import type { BaseContract, Signer, utils } from "ethers";
5
+
6
+ import type { Listener, Provider } from "@ethersproject/providers";
7
+ import type {
8
+ TypedEventFilter,
9
+ TypedEvent,
10
+ TypedListener,
11
+ OnEvent,
12
+ } from "../../common";
13
+
14
+ export interface SelfCallableInterface extends utils.Interface {
15
+ functions: {};
16
+
17
+ events: {};
18
+ }
19
+
20
+ export interface SelfCallable extends BaseContract {
21
+ connect(signerOrProvider: Signer | Provider | string): this;
22
+ attach(addressOrName: string): this;
23
+ deployed(): Promise<this>;
24
+
25
+ interface: SelfCallableInterface;
26
+
27
+ queryFilter<TEvent extends TypedEvent>(
28
+ event: TypedEventFilter<TEvent>,
29
+ fromBlockOrBlockhash?: string | number | undefined,
30
+ toBlock?: string | number | undefined
31
+ ): Promise<Array<TEvent>>;
32
+
33
+ listeners<TEvent extends TypedEvent>(
34
+ eventFilter?: TypedEventFilter<TEvent>
35
+ ): Array<TypedListener<TEvent>>;
36
+ listeners(eventName?: string): Array<Listener>;
37
+ removeAllListeners<TEvent extends TypedEvent>(
38
+ eventFilter: TypedEventFilter<TEvent>
39
+ ): this;
40
+ removeAllListeners(eventName?: string): this;
41
+ off: OnEvent<this>;
42
+ on: OnEvent<this>;
43
+ once: OnEvent<this>;
44
+ removeListener: OnEvent<this>;
45
+
46
+ functions: {};
47
+
48
+ callStatic: {};
49
+
50
+ filters: {};
51
+
52
+ estimateGas: {};
53
+
54
+ populateTransaction: {};
55
+ }
@@ -0,0 +1,4 @@
1
+ /* Autogenerated file. Do not edit manually. */
2
+ /* tslint:disable */
3
+ /* eslint-disable */
4
+ export type { SelfCallable } from "./SelfCallable";
@@ -0,0 +1,31 @@
1
+ /* Autogenerated file. Do not edit manually. */
2
+ /* tslint:disable */
3
+ /* eslint-disable */
4
+
5
+ import { Contract, Signer, utils } from "ethers";
6
+ import type { Provider } from "@ethersproject/providers";
7
+ import type {
8
+ ReentrancyGuard,
9
+ ReentrancyGuardInterface,
10
+ } from "../../../../@openzeppelin/contracts/utils/ReentrancyGuard";
11
+
12
+ const _abi = [
13
+ {
14
+ inputs: [],
15
+ name: "ReentrancyGuardReentrantCall",
16
+ type: "error",
17
+ },
18
+ ] as const;
19
+
20
+ export class ReentrancyGuard__factory {
21
+ static readonly abi = _abi;
22
+ static createInterface(): ReentrancyGuardInterface {
23
+ return new utils.Interface(_abi) as ReentrancyGuardInterface;
24
+ }
25
+ static connect(
26
+ address: string,
27
+ signerOrProvider: Signer | Provider
28
+ ): ReentrancyGuard {
29
+ return new Contract(address, _abi, signerOrProvider) as ReentrancyGuard;
30
+ }
31
+ }
@@ -2,3 +2,4 @@
2
2
  /* tslint:disable */
3
3
  /* eslint-disable */
4
4
  export * as cryptography from "./cryptography";
5
+ export { ReentrancyGuard__factory } from "./ReentrancyGuard__factory";
@@ -41,7 +41,7 @@ const _abi = [
41
41
  },
42
42
  {
43
43
  inputs: [],
44
- name: "OnlyMultiSig",
44
+ name: "OnlySelfCall",
45
45
  type: "error",
46
46
  },
47
47
  {