Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions script/DeployL2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {IdGateway} from "../src/IdGateway.sol";
import {KeyRegistry} from "../src/KeyRegistry.sol";
import {KeyGateway} from "../src/KeyGateway.sol";
import {SignedKeyRequestValidator} from "../src/validators/SignedKeyRequestValidator.sol";
import {Bundler, IBundler} from "../src/Bundler.sol";
import {BundlerV1, IBundlerV1} from "../src/BundlerV1.sol";
import {RecoveryProxy} from "../src/RecoveryProxy.sol";
import {IMetadataValidator} from "../src/interfaces/IMetadataValidator.sol";
import {console, ImmutableCreate2Deployer} from "./abstract/ImmutableCreate2Deployer.sol";
Expand Down Expand Up @@ -67,7 +67,7 @@ contract DeployL2 is ImmutableCreate2Deployer {
KeyRegistry keyRegistry;
KeyGateway keyGateway;
SignedKeyRequestValidator signedKeyRequestValidator;
Bundler bundler;
BundlerV1 bundler;
RecoveryProxy recoveryProxy;
}

Expand Down Expand Up @@ -130,7 +130,7 @@ contract DeployL2 is ImmutableCreate2Deployer {
abi.encode(addrs.idRegistry, params.initialValidatorOwner)
);
addrs.bundler = register(
"Bundler", params.salts.bundler, type(Bundler).creationCode, abi.encode(addrs.idGateway, addrs.keyGateway)
"Bundler", params.salts.bundler, type(BundlerV1).creationCode, abi.encode(addrs.idGateway, addrs.keyGateway)
);
addrs.recoveryProxy = register(
"RecoveryProxy",
Expand All @@ -148,7 +148,7 @@ contract DeployL2 is ImmutableCreate2Deployer {
keyRegistry: KeyRegistry(addrs.keyRegistry),
keyGateway: KeyGateway(payable(addrs.keyGateway)),
signedKeyRequestValidator: SignedKeyRequestValidator(addrs.signedKeyRequestValidator),
bundler: Bundler(payable(addrs.bundler)),
bundler: BundlerV1(payable(addrs.bundler)),
recoveryProxy: RecoveryProxy(addrs.recoveryProxy)
});
}
Expand Down
108 changes: 108 additions & 0 deletions script/UpgradeBundler.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {Test} from "forge-std/Test.sol";
import {StorageRegistry} from "../src/StorageRegistry.sol";
import {IdRegistry} from "../src/IdRegistry.sol";
import {IdGateway} from "../src/IdGateway.sol";
import {KeyRegistry, IKeyRegistry} from "../src/KeyRegistry.sol";
import {KeyGateway} from "../src/KeyGateway.sol";
import {SignedKeyRequestValidator} from "../src/validators/SignedKeyRequestValidator.sol";
import {Bundler, IBundler} from "../src/Bundler.sol";
import {RecoveryProxy} from "../src/RecoveryProxy.sol";
import {console, ImmutableCreate2Deployer} from "./abstract/ImmutableCreate2Deployer.sol";

contract UpgradeBundler is ImmutableCreate2Deployer, Test {
struct Salts {
bytes32 bundler;
}

struct DeploymentParams {
Salts salts;
}

struct Addresses {
address storageRegistry;
address idRegistry;
address idGateway;
address keyRegistry;
address keyGateway;
address signedKeyRequestValidator;
address bundler;
address recoveryProxy;
}

struct Contracts {
StorageRegistry storageRegistry;
IdRegistry idRegistry;
IdGateway idGateway;
KeyRegistry keyRegistry;
KeyGateway keyGateway;
SignedKeyRequestValidator signedKeyRequestValidator;
Bundler bundler;
RecoveryProxy recoveryProxy;
}

function run() public {
runSetup(runDeploy(loadDeploymentParams()));
}

function runDeploy(
DeploymentParams memory params
) public returns (Contracts memory) {
return runDeploy(params, true);
}

function runDeploy(DeploymentParams memory params, bool broadcast) public returns (Contracts memory) {
Addresses memory addrs;

// No changes
addrs.storageRegistry = address(0x00000000fcCe7f938e7aE6D3c335bD6a1a7c593D);
addrs.idRegistry = address(0x00000000Fc6c5F01Fc30151999387Bb99A9f489b);
addrs.idGateway = payable(address(0x00000000Fc25870C6eD6b6c7E41Fb078b7656f69));
addrs.keyRegistry = address(0x00000000Fc1237824fb747aBDE0FF18990E59b7e);
addrs.keyGateway = address(0x00000000fC56947c7E7183f8Ca4B62398CaAdf0B);
addrs.signedKeyRequestValidator = address(0x00000000FC700472606ED4fA22623Acf62c60553);
addrs.recoveryProxy = address(0x00000000FcB080a4D6c39a9354dA9EB9bC104cd7);

// Deploy new Bundler
addrs.bundler = register(
"Bundler", params.salts.bundler, type(Bundler).creationCode, abi.encode(addrs.idGateway, addrs.keyGateway)
);
deploy(broadcast);

return Contracts({
storageRegistry: StorageRegistry(addrs.storageRegistry),
idRegistry: IdRegistry(addrs.idRegistry),
idGateway: IdGateway(payable(addrs.idGateway)),
keyRegistry: KeyRegistry(addrs.keyRegistry),
keyGateway: KeyGateway(payable(addrs.keyGateway)),
signedKeyRequestValidator: SignedKeyRequestValidator(addrs.signedKeyRequestValidator),
bundler: Bundler(payable(addrs.bundler)),
recoveryProxy: RecoveryProxy(addrs.recoveryProxy)
});
}

function runSetup(Contracts memory contracts, DeploymentParams memory, bool) public {
if (deploymentChanged()) {
console.log("Running setup");

// Check bundler deploy parameters
assertEq(address(contracts.bundler.idGateway()), address(contracts.idGateway));
assertEq(address(contracts.bundler.keyGateway()), address(contracts.keyGateway));
} else {
console.log("No changes, skipping setup");
}
}

function runSetup(
Contracts memory contracts
) public {
DeploymentParams memory params = loadDeploymentParams();
runSetup(contracts, params, true);
}

function loadDeploymentParams() internal returns (DeploymentParams memory) {
return DeploymentParams({salts: Salts({bundler: vm.envOr("BUNDLER_CREATE2_SALT", bytes32(0))})});
}
}
8 changes: 4 additions & 4 deletions script/UpgradeL2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {IdGateway} from "../src/IdGateway.sol";
import {KeyRegistry, IKeyRegistry} from "../src/KeyRegistry.sol";
import {KeyGateway} from "../src/KeyGateway.sol";
import {SignedKeyRequestValidator} from "../src/validators/SignedKeyRequestValidator.sol";
import {Bundler, IBundler} from "../src/Bundler.sol";
import {BundlerV1, IBundlerV1} from "../src/BundlerV1.sol";
import {RecoveryProxy} from "../src/RecoveryProxy.sol";
import {IMetadataValidator} from "../src/interfaces/IMetadataValidator.sol";
import {console, ImmutableCreate2Deployer} from "./abstract/ImmutableCreate2Deployer.sol";
Expand Down Expand Up @@ -61,7 +61,7 @@ contract UpgradeL2 is ImmutableCreate2Deployer, Test {
KeyRegistry keyRegistry;
KeyGateway keyGateway;
SignedKeyRequestValidator signedKeyRequestValidator;
Bundler bundler;
BundlerV1 bundler;
RecoveryProxy recoveryProxy;
}

Expand Down Expand Up @@ -108,7 +108,7 @@ contract UpgradeL2 is ImmutableCreate2Deployer, Test {
abi.encode(addrs.keyRegistry, params.initialKeyRegistryOwner)
);
addrs.bundler = register(
"Bundler", params.salts.bundler, type(Bundler).creationCode, abi.encode(addrs.idGateway, addrs.keyGateway)
"Bundler", params.salts.bundler, type(BundlerV1).creationCode, abi.encode(addrs.idGateway, addrs.keyGateway)
);
addrs.recoveryProxy = register(
"RecoveryProxy",
Expand All @@ -126,7 +126,7 @@ contract UpgradeL2 is ImmutableCreate2Deployer, Test {
keyRegistry: KeyRegistry(addrs.keyRegistry),
keyGateway: KeyGateway(payable(addrs.keyGateway)),
signedKeyRequestValidator: SignedKeyRequestValidator(addrs.signedKeyRequestValidator),
bundler: Bundler(payable(addrs.bundler)),
bundler: BundlerV1(payable(addrs.bundler)),
recoveryProxy: RecoveryProxy(addrs.recoveryProxy)
});
}
Expand Down
24 changes: 14 additions & 10 deletions src/Bundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract Bundler is IBundler {
/**
* @inheritdoc IBundler
*/
string public constant VERSION = "2023.11.15";
string public constant VERSION = "2025.06.13";

/*//////////////////////////////////////////////////////////////
IMMUTABLES
Expand Down Expand Up @@ -74,27 +74,31 @@ contract Bundler is IBundler {
(uint256 fid, uint256 overpayment) = idGateway.registerFor{value: msg.value}(
registerParams.to, registerParams.recovery, registerParams.deadline, registerParams.sig, extraStorage
);
_addKeys(registerParams.to, signerParams);
if (overpayment > 0) msg.sender.sendNative(overpayment);
return fid;
}

/**
* @inheritdoc IBundler
*/
function addKeys(address fidOwner, SignerParams[] calldata signerParams) external {
_addKeys(fidOwner, signerParams);
}

function _addKeys(address fidOwner, SignerParams[] calldata signerParams) internal {
uint256 signersLen = signerParams.length;
for (uint256 i; i < signersLen;) {
SignerParams calldata signer = signerParams[i];
keyGateway.addFor(
registerParams.to,
signer.keyType,
signer.key,
signer.metadataType,
signer.metadata,
signer.deadline,
signer.sig
fidOwner, signer.keyType, signer.key, signer.metadataType, signer.metadata, signer.deadline, signer.sig
);

// Safety: i can be incremented unchecked since it is bound by signerParams.length.
unchecked {
++i;
}
}
if (overpayment > 0) msg.sender.sendNative(overpayment);
return fid;
}

receive() external payable {
Expand Down
103 changes: 103 additions & 0 deletions src/BundlerV1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {IBundlerV1} from "./interfaces/IBundlerV1.sol";
import {IIdGateway} from "./interfaces/IIdGateway.sol";
import {IKeyGateway} from "./interfaces/IKeyGateway.sol";
import {TransferHelper} from "./libraries/TransferHelper.sol";

/**
* @title Farcaster Bundler
*
* @notice See https://github.com/farcasterxyz/contracts/blob/v3.1.0/docs/docs.md for an overview.
*
* @custom:security-contact security@merklemanufactory.com
*/
contract BundlerV1 is IBundlerV1 {
using TransferHelper for address;

/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/

/**
* @inheritdoc IBundlerV1
*/
string public constant VERSION = "2023.11.15";

/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/

/**
* @inheritdoc IBundlerV1
*/
IIdGateway public immutable idGateway;

/**
* @inheritdoc IBundlerV1
*/
IKeyGateway public immutable keyGateway;

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/

/**
* @notice Configure the addresses of the IdGateway and KeyGateway contracts.
*
* @param _idGateway Address of the IdGateway contract
* @param _keyGateway Address of the KeyGateway contract
*/
constructor(address _idGateway, address _keyGateway) {
idGateway = IIdGateway(payable(_idGateway));
keyGateway = IKeyGateway(payable(_keyGateway));
}

/**
* @inheritdoc IBundlerV1
*/
function price(
uint256 extraStorage
) external view returns (uint256) {
return idGateway.price(extraStorage);
}

/**
* @inheritdoc IBundlerV1
*/
function register(
RegistrationParams calldata registerParams,
SignerParams[] calldata signerParams,
uint256 extraStorage
) external payable returns (uint256) {
(uint256 fid, uint256 overpayment) = idGateway.registerFor{value: msg.value}(
registerParams.to, registerParams.recovery, registerParams.deadline, registerParams.sig, extraStorage
);

uint256 signersLen = signerParams.length;
for (uint256 i; i < signersLen;) {
SignerParams calldata signer = signerParams[i];
keyGateway.addFor(
registerParams.to,
signer.keyType,
signer.key,
signer.metadataType,
signer.metadata,
signer.deadline,
signer.sig
);

// Safety: i can be incremented unchecked since it is bound by signerParams.length.
unchecked {
++i;
}
}
if (overpayment > 0) msg.sender.sendNative(overpayment);
return fid;
}

receive() external payable {
if (msg.sender != address(idGateway)) revert Unauthorized();
}
}
10 changes: 10 additions & 0 deletions src/interfaces/IBundler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,14 @@ interface IBundler {
SignerParams[] calldata signerParams,
uint256 extraStorage
) external payable returns (uint256 fid);

/**
* @notice Add multiple keys in a single transaction.
*
* @param fidOwner The fid owner address.
* @param signerParams Array of structs containing signer parameters: keyType, key, metadataType,
* metadata, deadline, and signature.
*
*/
function addKeys(address fidOwner, SignerParams[] calldata signerParams) external;
}
Loading
Loading