Skip to content

Commit

Permalink
Merge pull request #34 from xWerk/feat/deploy-payment-module-script
Browse files Browse the repository at this point in the history
Update deployment scripts
  • Loading branch information
gabrielstoica authored Nov 22, 2024
2 parents 64e6af6 + 5526e3e commit c66f8b9
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/openzeppelin-foundry-upgrades"]
path = lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
37 changes: 34 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ tests-coverage :; ./script/coverage.sh
deploy-invoice-collection:
forge script script/DeployInvoiceCollection.s.sol:DeployInvoiceCollection \
$(CREATE2SALT) {RELAYER} {NAME} {SYMBOL} \
--sig "run(address,string,string)" --rpc-url {RPC_URL} --private-key $(PRIVATE_KEY) --etherscan-api-key $(ETHERSCAN_API_KEY)
--sig "run(string,address,string,string)" --rpc-url {RPC_URL} --private-key $(PRIVATE_KEY) --etherscan-api-key $(ETHERSCAN_API_KEY)
--broadcast --verify

# Deploys the {ModuleKeeper} contract deterministically
Expand All @@ -40,12 +40,43 @@ deploy-deterministic-module-keeper:
# Deploys the {StationRegistry} contract deterministically
# Update the following configs before running the script:
# - {INITIAL_OWNER} with the address of the initial owner
# - {ENTRYPOINT} with the address of the {Entrypoiny} contract (currently v6)
# - {ENTRYPOINT} with the address of the {Entrypoint} contract (currently v6)
# - {MODULE_KEEPER} with the address of the {ModuleKeeper} deployment
# - {RPC_URL} with the network RPC used for deployment
deploy-deterministic-dock-registry:
forge script script/DeployDeterministicStationRegistry.s.sol:DeployDeterministicStationRegistry \
$(CREATE2SALT) {INITIAL_OWNER} {ENTRYPOINT} {MODULE_KEEPER} \
--sig "run(string,address,address)" --rpc-url {RPC_URL} \
--private-key $(PRIVATE_KEY) --etherscan-api-key $(ETHERSCAN_API_KEY) \
--broadcast --verify
--broadcast --verify

# Deploys the {PaymentModule} contract deterministically
#
# Update the following configs before running the script:
# - {SABLIER_LOCKUP_LINEAR} with the according {SablierV2LockupLinear} deployment address
# - {SABLIER_LOCKUP_TRANCHED} with the according {SablierV2LockupTranched} deployment address
# - {INITIAL_OWNER} with the address of the initial admin of the {PaymentModule}
# - {BROKER_ACCOUNT} with the address of the account responsible for collecting the broker fees (multisig vault)
# - {RPC_URL} with the network RPC used for deployment
deploy-payment-module:
forge script script/DeployDeterministicPaymentModule.s.sol:DeployDeterministicPaymentModule \
$(CREATE2SALT) {SABLIER_LOCKUP_LINEAR} {SABLIER_LOCKUP_TRANCHED} {INITIAL_OWNER} {BROKER_ACCOUNT} \
--sig "run(string,address,address,address,address)" --rpc-url {RPC_URL} --private-key $(PRIVATE_KEY) --etherscan-api-key $(ETHERSCAN_API_KEY)
--broadcast --verify

# Deploys the {PaymentModule} contract deterministically

# Deploys the core contracts deterministically
#
# Update the following configs before running the script:
# - {SABLIER_LOCKUP_LINEAR} with the according {SablierV2LockupLinear} deployment address
# - {SABLIER_LOCKUP_TRANCHED} with the according {SablierV2LockupTranched} deployment address
# - {INITIAL_OWNER} with the address of the initial admin of the {StationRegistry} and {PaymentModule}
# - {BROKER_ACCOUNT} with the address of the account responsible for collecting the broker fees (multisig vault)
# - {ENTRYPOINT} with the address of the {Entrypoint} contract (currently v6)
# - {RPC_URL} with the network RPC used for deployment
deploy-core:
forge script script/DeployDeterministicCore.s.sol:DeployDeterministicCore \
$(CREATE2SALT) {SABLIER_LOCKUP_LINEAR} {SABLIER_LOCKUP_TRANCHED} {INITIAL_OWNER} {BROKER_ACCOUNT} {ENTRYPOINT}\
--sig "run(string,address,address,address,address,address)" --rpc-url {RPC_URL} --private-key $(PRIVATE_KEY) --etherscan-api-key $(ETHERSCAN_API_KEY)
--broadcast --verify
1 change: 1 addition & 0 deletions lib/openzeppelin-foundry-upgrades
77 changes: 77 additions & 0 deletions script/DeployDeterministicCore.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.26;

import { BaseScript } from "./Base.s.sol";
import { PaymentModule } from "./../src/modules/payment-module/PaymentModule.sol";
import { StationRegistry } from "./../src/StationRegistry.sol";
import { ModuleKeeper } from "./../src/ModuleKeeper.sol";

import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { Options } from "./../lib/openzeppelin-foundry-upgrades/src/Options.sol";
import { Core } from "./../lib/openzeppelin-foundry-upgrades/src/internal/Core.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol";
import { IEntryPoint } from "@thirdweb/contracts/prebuilts/account/interface/IEntrypoint.sol";
import { ud } from "@prb/math/src/UD60x18.sol";

/// @notice Deploys at deterministic addresses across chains the core contracts of the Werk Protocol
/// @dev Reverts if any contract has already been deployed
contract DeployDeterministicCore is BaseScript {
/// @dev By using a salt, Forge will deploy the contract via a deterministic CREATE2 factory
/// https://book.getfoundry.sh/tutorials/create2-tutorial?highlight=deter#deterministic-deployment-using-create2
function run(
string memory create2Salt,
ISablierV2LockupLinear sablierLockupLinear,
ISablierV2LockupTranched sablierLockupTranched,
address initialOwner,
address brokerAccount,
IEntryPoint entrypoint
)
public
virtual
broadcast
returns (ModuleKeeper moduleKeeper, StationRegistry stationRegistry, PaymentModule paymentModule)
{
bytes32 salt = bytes32(abi.encodePacked(create2Salt));

// Deterministically deploy the {ModuleKeeper} contract
moduleKeeper = new ModuleKeeper{ salt: salt }(initialOwner);

// Deterministically deploy the {StationRegistry} contract
stationRegistry = new StationRegistry{ salt: salt }(initialOwner, entrypoint, moduleKeeper);

// Deterministically deploy the {PaymentModule} module
paymentModule = PaymentModule(
deployDetermisticUUPSProxy(
salt,
abi.encode(sablierLockupLinear, sablierLockupTranched),
"PaymentModule.sol",
abi.encodeCall(PaymentModule.initialize, (initialOwner, brokerAccount, ud(0)))
)
);

// Add the {PaymentModule} module to the allowlist of the {ModuleKeeper}
moduleKeeper.addToAllowlist(address(paymentModule));
}

/// @dev Deploys a UUPS proxy at deterministic addresses across chains based on a provided salt
/// @param salt Salt to use for deterministic deployment
/// @param contractName The name of the implementation contract
/// @param initializerData The ABI encoded call to be made to the initialize method
function deployDetermisticUUPSProxy(
bytes32 salt,
bytes memory constructorData,
string memory contractName,
bytes memory initializerData
)
internal
returns (address)
{
Options memory opts;
opts.constructorData = constructorData;

address impl = Core.deployImplementation(contractName, opts);

return address(new ERC1967Proxy{ salt: salt }(impl, initializerData));
}
}
64 changes: 64 additions & 0 deletions script/DeployDeterministicPaymentModule.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.26;

import { BaseScript } from "./Base.s.sol";
import { PaymentModule } from "./../src/modules/payment-module/PaymentModule.sol";

import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { Options } from "./../lib/openzeppelin-foundry-upgrades/src/Options.sol";
import { Core } from "./../lib/openzeppelin-foundry-upgrades/src/internal/Core.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol";
import { ud } from "@prb/math/src/UD60x18.sol";

/// @notice Deploys at deterministic addresses across chains an instance of {PaymentModule}
/// @dev Reverts if any contract has already been deployed
contract DeployDeterministicPaymentModule is BaseScript {
/// @dev By using a salt, Forge will deploy the contract via a deterministic CREATE2 factory
/// https://book.getfoundry.sh/tutorials/create2-tutorial?highlight=deter#deterministic-deployment-using-create2
function run(
string memory create2Salt,
ISablierV2LockupLinear sablierLockupLinear,
ISablierV2LockupTranched sablierLockupTranched,
address initialOwner,
address brokerAccount
)
public
virtual
broadcast
returns (PaymentModule paymentModule)
{
bytes32 salt = bytes32(abi.encodePacked(create2Salt));

// Deterministically deploy the {PaymentModule} module
paymentModule = PaymentModule(
deployDetermisticUUPSProxy(
salt,
abi.encode(sablierLockupLinear, sablierLockupTranched),
"PaymentModule.sol",
abi.encodeCall(PaymentModule.initialize, (initialOwner, brokerAccount, ud(0)))
)
);
}

/// @dev Deploys a UUPS proxy at deterministic addresses across chains based on a provided salt
/// @param salt Salt to use for deterministic deployment
/// @param contractName The name of the implementation contract
/// @param initializerData The ABI encoded call to be made to the initialize method
function deployDetermisticUUPSProxy(
bytes32 salt,
bytes memory constructorData,
string memory contractName,
bytes memory initializerData
)
internal
returns (address)
{
Options memory opts;
opts.constructorData = constructorData;

address impl = Core.deployImplementation(contractName, opts);

return address(new ERC1967Proxy{ salt: salt }(impl, initializerData));
}
}

0 comments on commit c66f8b9

Please sign in to comment.