Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make signing eip 712 compliant #916

Merged
merged 29 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bcd6663
feat: first version
NicolasRampoldi Aug 29, 2024
206cabf
feat: working implementation
NicolasRampoldi Sep 3, 2024
d333b62
docs: comment
NicolasRampoldi Sep 3, 2024
d48a42e
Merge branch 'main' into feat-make-signing-eip-712-compliant
NicolasRampoldi Sep 3, 2024
b2b512a
chore: anvil state
NicolasRampoldi Sep 3, 2024
88d0248
fix: linter
NicolasRampoldi Sep 3, 2024
3e671e9
forge install: openzeppelin-contracts
NicolasRampoldi Sep 3, 2024
a96d73e
chore: install openzepellin and bump solidity version
NicolasRampoldi Sep 3, 2024
9db71b0
fix: lower gap
NicolasRampoldi Sep 3, 2024
f259a96
refactor: hasher update
NicolasRampoldi Sep 3, 2024
801f690
Merge branch 'main' into feat-make-signing-eip-712-compliant
NicolasRampoldi Sep 4, 2024
b82987e
chore: merge
NicolasRampoldi Sep 4, 2024
83d8d77
chore: bump up protocol version
NicolasRampoldi Sep 5, 2024
aab9476
feat: add chain param to submit and submit_multiple
NicolasRampoldi Sep 5, 2024
e8be0d7
refactor: add errors
NicolasRampoldi Sep 5, 2024
76ed477
forge install: openzeppelin-contracts-upgradeable
NicolasRampoldi Sep 6, 2024
7772e3b
Merge branch 'main' into feat-make-signing-eip-712-compliant
NicolasRampoldi Sep 6, 2024
2d9e71f
chore: anvil state
NicolasRampoldi Sep 6, 2024
4ffd79c
feat: add setHashType in contract
NicolasRampoldi Sep 6, 2024
ab2b391
Merge branch 'main' into feat-make-signing-eip-712-compliant
NicolasRampoldi Sep 6, 2024
6610aca
fix: deployment script
NicolasRampoldi Sep 6, 2024
516c00d
feat: spearate BatcherPaymentServiceStorage
uri-99 Sep 6, 2024
71f8359
feat: include the storage in the contract
uri-99 Sep 6, 2024
a679cdd
fix: deploy batche
uri-99 Sep 6, 2024
ae1f63e
refactor: change make target to upgrade_batcher_payments_add_type_hash
uri-99 Sep 6, 2024
1bf323d
fix: remove 0x from nonced verification data type hash
NicolasRampoldi Sep 9, 2024
1bd4352
chore: new line
NicolasRampoldi Sep 9, 2024
7672899
refactor: nonce from bytes32 to uint256
NicolasRampoldi Sep 9, 2024
8d619bb
chore: anvil state
NicolasRampoldi Sep 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
[submodule "examples/validating-public-input/contracts/lib/forge-std"]
path = examples/validating-public-input/contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/lib/openzeppelin-contracts"]
path = contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
3 changes: 2 additions & 1 deletion batcher/aligned-batcher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,8 @@ impl Batcher {
let client_msg = ClientMessage::new(
nonced_verification_data.clone(),
non_paying_config.replacement.clone(),
);
)
.await;

self.clone()
.add_to_batch(
Expand Down
2 changes: 1 addition & 1 deletion batcher/aligned-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
ethers = { tag = "v2.0.15-fix-reconnections", features = ["ws", "rustls"], git = "https://github.com/yetanotherco/ethers-rs.git" }
ethers = { tag = "v2.0.15-fix-reconnections", features = ["ws", "rustls", "eip712"], git = "https://github.com/yetanotherco/ethers-rs.git" }
log = { version = "0.4.21"}
serde_json = "1.0.117"
tokio-tungstenite = { version = "0.23.1", features = ["native-tls"] }
Expand Down
2 changes: 1 addition & 1 deletion batcher/aligned-sdk/src/communication/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub async fn send_messages(

nonce += U256::one();

let msg = ClientMessage::new(verification_data.clone(), wallet.clone());
let msg = ClientMessage::new(verification_data.clone(), wallet.clone()).await;
let msg_bin = cbor_serialize(&msg).map_err(SubmitError::SerializationError)?;
ws_write
.send(Message::Binary(msg_bin.clone()))
Expand Down
110 changes: 88 additions & 22 deletions batcher/aligned-sdk/src/core/types.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
use std::str::FromStr;

use ethers::core::k256::ecdsa::SigningKey;
use ethers::signers::Signer;
use ethers::signers::Wallet;
use ethers::types::transaction::eip712::EIP712Domain;
use ethers::types::transaction::eip712::Eip712;
use ethers::types::transaction::eip712::Eip712Error;
use ethers::types::Address;
use ethers::types::Signature;
use ethers::types::SignatureError;
use ethers::types::H160;
use ethers::types::U256;
use lambdaworks_crypto::merkle_tree::{
merkle::MerkleTree, proof::Proof, traits::IsMerkleTreeBackend,
};
use serde::{Deserialize, Serialize};
use sha3::{Digest, Keccak256};

const ANVIL_CHAIN_ID: u64 = 31337;
const HOLESKY_CHAIN_ID: u64 = 17000;
const MAINNET_CHAIN_ID: u64 = 1;
// VerificationData is a bytes32 instead of a VerificationData struct because in the BatcherPaymentService contract
// we don't have the fields of VerificationData, we only have the hash of the VerificationData.
// chain_id is not included in the type because it is now part of the domain.
const NONCED_VERIFICATION_DATA_TYPE: &[u8] =
b"NoncedVerificationData(bytes32 verification_data_hash,bytes32 nonce)";

#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum ProvingSystemId {
Expand Down Expand Up @@ -170,14 +186,62 @@ pub struct ClientMessage {
pub signature: Signature,
}

impl Eip712 for NoncedVerificationData {
type Error = Eip712Error;

fn domain(&self) -> Result<EIP712Domain, Self::Error> {
let payment_service_addr = get_payment_service_addr(self.chain_id);

Ok(EIP712Domain {
name: Some("Aligned".into()),
version: Some("1".into()),
chain_id: Some(self.chain_id),
verifying_contract: payment_service_addr,
salt: None,
})
}

fn type_hash() -> Result<[u8; 32], Self::Error> {
let mut hasher = Keccak256::new();
hasher.update(NONCED_VERIFICATION_DATA_TYPE);
Ok(hasher.finalize().into())
}

fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
let verification_data_hash =
VerificationCommitmentBatch::hash_data(&self.verification_data.clone().into());

let mut hasher = Keccak256::new();

hasher.update(NONCED_VERIFICATION_DATA_TYPE);
let nonced_verification_data_type_hash = hasher.finalize_reset();

hasher.update(self.nonce);
let nonce_hash = hasher.finalize_reset();

hasher.update(
[
nonced_verification_data_type_hash.as_slice(),
verification_data_hash.as_slice(),
nonce_hash.as_slice(),
]
.concat(),
);

Ok(hasher.finalize().into())
}
}

impl ClientMessage {
/// Client message is a wrap around verification data and its signature.
/// The signature is obtained by calculating the commitments and then hashing them.
pub fn new(verification_data: NoncedVerificationData, wallet: Wallet<SigningKey>) -> Self {
let hashed_data = ClientMessage::hash_with_nonce_and_chain_id(&verification_data);

pub async fn new(
verification_data: NoncedVerificationData,
wallet: Wallet<SigningKey>,
) -> Self {
let signature = wallet
.sign_hash(hashed_data.into())
.sign_typed_data(&verification_data)
.await
.expect("Failed to sign the verification data");

ClientMessage {
Expand All @@ -189,28 +253,18 @@ impl ClientMessage {
/// The signature of the message is verified, and when it correct, the
/// recovered address from the signature is returned.
pub fn verify_signature(&self) -> Result<Address, SignatureError> {
let hashed_data: [u8; 32] =
ClientMessage::hash_with_nonce_and_chain_id(&self.verification_data);
let recovered = self.signature.recover_typed_data(&self.verification_data)?;

// We can expect here because encode_eip712 can only error if
// struct_hash or domain_separator return an error, which is not possible
let hashed_data = self
.verification_data
.encode_eip712()
.expect("Failed to encode verification data for signature verification");

let recovered = self.signature.recover(hashed_data)?;
self.signature.verify(hashed_data, recovered)?;
Ok(recovered)
}

fn hash_with_nonce_and_chain_id(verification_data: &NoncedVerificationData) -> [u8; 32] {
let hashed_leaf = VerificationCommitmentBatch::hash_data(&verification_data.into());

let mut chain_id_bytes = [0u8; 32];
verification_data
.chain_id
.to_big_endian(&mut chain_id_bytes);

let mut hasher = Keccak256::new();
hasher.update(hashed_leaf);
hasher.update(verification_data.nonce);
hasher.update(chain_id_bytes);
hasher.finalize().into()
}
}

#[derive(Serialize, Deserialize, Clone)]
Expand Down Expand Up @@ -265,3 +319,15 @@ pub enum Chain {
Holesky,
HoleskyStage,
}

fn get_payment_service_addr(chain_id: U256) -> Option<H160> {
match chain_id.as_u64() {
ANVIL_CHAIN_ID => H160::from_str("0x7969c5eD335650692Bc04293B07F5BF2e7A673C0").ok(),
HOLESKY_CHAIN_ID => H160::from_str("0x815aeCA64a974297942D2Bbf034ABEe22a38A003").ok(),
MAINNET_CHAIN_ID => {
//FIXME: Add the payment service address for mainnet
None
}
_ => None,
}
}
1 change: 1 addition & 0 deletions contracts/lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at dbb610
4 changes: 3 additions & 1 deletion contracts/remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ eigenlayer-middleware/=lib/eigenlayer-middleware/src/
eigenlayer-core/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/
eigenlayer-core-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/core
eigenlayer-scripts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/script/
forge-std/=lib/forge-std/src/
forge-std/=lib/forge-std/src/
@openzeppelin/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/
@openzeppelin-upgrades/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/
2 changes: 1 addition & 1 deletion contracts/script/deploy/AlignedLayerDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

/*
This script is a modified version of the Mainnet_Deploy.s.sol script used by EigenDA:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {BatcherPaymentService} from "../../src/core/BatcherPaymentService.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/deploy/EigenLayerDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

// The original script used as the base of this one is:
// https://github.com/Layr-Labs/eigenlayer-contracts/blob/7229f2b426b6f2a24c7795b1a4687a010eac8ef2/script/deploy/devnet/M2_Deploy_From_Scratch.s.sol
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/upgrade/AlignedLayerUpgrader.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Script} from "forge-std/Script.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/upgrade/BLSApkRegistryUpgrader.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Script} from "forge-std/Script.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;
import {BatcherPaymentService} from "../../src/core/BatcherPaymentService.sol";

import "forge-std/Script.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/upgrade/IndexRegistryUpgrader.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Script} from "forge-std/Script.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/upgrade/RegistryCoordinatorUpgrader.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Script} from "forge-std/Script.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/upgrade/StakeRegistryUpgrader.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Script} from "forge-std/Script.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/src/core/AlignedLayerServiceManager.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {ServiceManagerBase, IAVSDirectory} from "eigenlayer-middleware/ServiceManagerBase.sol";
import {BLSSignatureChecker} from "eigenlayer-middleware/BLSSignatureChecker.sol";
Expand Down
29 changes: 21 additions & 8 deletions contracts/src/core/BatcherPaymentService.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin-upgrades/contracts/security/PausableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin-upgrades/contracts/proxy/utils/UUPSUpgradeable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "../../lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol";
import {IAlignedLayerServiceManager} from "./IAlignedLayerServiceManager.sol";

contract BatcherPaymentService is
Initializable,
OwnableUpgradeable,
PausableUpgradeable,
UUPSUpgradeable
UUPSUpgradeable,
EIP712
{
using ECDSA for bytes32;

Expand Down Expand Up @@ -66,12 +68,17 @@ contract BatcherPaymentService is
// map to user data
mapping(address => UserInfo) public userData;

bytes32 private constant NONCED_VERIFICATION_DATA_TYPEHASH =
keccak256(
"NoncedVerificationData(bytes32 verification_data_hash,bytes32 nonce)"
);

// storage gap for upgradeability
// solhint-disable-next-line var-name-mixedcase
uint256[24] private __GAP;
uint256[23] private __GAP;

// CONSTRUCTOR & INITIALIZER
constructor() {
constructor() EIP712("Aligned", "1") {
_disableInitializers();
}

Expand Down Expand Up @@ -281,15 +288,21 @@ contract BatcherPaymentService is
}

function _verifySignatureAndDecreaseBalance(
bytes32 hash,
bytes32 leaf,
SignatureData calldata signatureData,
uint256 feePerProof
) private {
bytes32 noncedHash = keccak256(
abi.encodePacked(hash, signatureData.nonce, block.chainid)
bytes32 structHash = keccak256(
abi.encode(
NONCED_VERIFICATION_DATA_TYPEHASH,
leaf,
keccak256(abi.encodePacked(signatureData.nonce))
)
);

address signer = noncedHash.recover(signatureData.signature);
bytes32 hash = _hashTypedDataV4(structHash);

address signer = ECDSA.recover(hash, signatureData.signature);

if (signer == address(0)) {
revert InvalidSignature();
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/core/ERC20Mock.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)

pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/core/IAlignedLayerServiceManager.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.12;
pragma solidity ^0.8.12;

import {IBLSSignatureChecker} from "eigenlayer-middleware/interfaces/IBLSSignatureChecker.sol";

Expand Down
Loading