Skip to content

Commit

Permalink
Integrate sphinx for deployment (#840)
Browse files Browse the repository at this point in the history
* build: integrate sphinx for deployment

* build: bump sphinx

* build: add runSphinx and runBroadcast in scripts

* docs: use dev natspec tag

* build: add sphinxProjectName

* chore: add SPHINX_PROJECT_NAME in .env.example

* docs: include SPHINX_PROJECT_NAME in constructor natspec

---------

Co-authored-by: andreivladbrg <andreivladbrg@gmail.com>
  • Loading branch information
smol-ninja and andreivladbrg committed Jul 3, 2024
1 parent bb65f9f commit 3bb0dc2
Show file tree
Hide file tree
Showing 18 changed files with 339 additions and 21 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export API_KEY_INFURA="YOUR_API_KEY_INFURA"
export EOA="YOUR_EOA_ADDRESS"
export FOUNDRY_PROFILE="lite"
export MNEMONIC="YOUR_MNEMONIC"
export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET"
export SPHINX_API_KEY="YOUR_API_KEY"
export SPHINX_ORG_ID="YOUR_ORG_ID"
export SPHINX_PROJECT_NAME="YOUR_PROJECT_NAME"
Binary file modified bun.lockb
Binary file not shown.
12 changes: 9 additions & 3 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
auto_detect_solc = false
bytecode_hash = "none"
emv_version = "paris"
extra_output = ['storageLayout']
ffi = true
fs_permissions = [{ access = "read", path = "out-optimized" }]
fs_permissions = [
{ access = "read", path = "out-optimized" },
{ access = "read", path = "./out" },
{ access = "read-write", path = "./cache" }
]
gas_reports = [
"SablierV2LockupDynamic",
"SablierV2LockupLinear",
Expand Down Expand Up @@ -94,9 +99,10 @@
[rpc_endpoints]
arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}"
bnb_smart_chain = "https://bsc-dataseed.binance.org"
gnosis_chain = "https://rpc.gnosischain.com"
bnb = "https://bsc-dataseed.binance.org"
gnosis = "https://rpc.gnosischain.com"
localhost = "http://localhost:8545"
ethereum = "${RPC_URL_MAINNET}"
mainnet = "${RPC_URL_MAINNET}"
optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}"
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"devDependencies": {
"@prb/test": "0.6.4",
"@sphinx-labs/plugins": "^0.30.6",
"forge-std": "github:foundry-rs/forge-std#v1.5.6",
"prettier": "^2.8.8",
"solady": "0.0.129",
Expand Down
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
@prb/math/=node_modules/@prb/math/
@prb/test/=node_modules/@prb/test/
@sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
forge-std/=node_modules/forge-std/
solady/=node_modules/solady/
solarray/=node_modules/solarray/
solarray/=node_modules/solarray/
32 changes: 27 additions & 5 deletions script/Base.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
pragma solidity >=0.8.22 <0.9.0;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { Sphinx } from "@sphinx-labs/contracts/SphinxPlugin.sol";

import { console2 } from "forge-std/src/console2.sol";
import { Script } from "forge-std/src/Script.sol";

contract BaseScript is Script {
contract BaseScript is Script, Sphinx {
using Strings for uint256;

/// @dev The Avalanche chain ID.
uint256 internal constant AVALANCHE_CHAIN_ID = 43_114;

/// @dev The project name for the Sphinx plugin.
string internal constant SPHINX_PROJECT_NAME = "test-test";

/// @dev Included to enable compilation of the script without a $MNEMONIC environment variable.
string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk";

Expand All @@ -26,24 +30,29 @@ contract BaseScript is Script {
/// block gas limit.
uint256 internal maxCount;

/// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined.
/// @dev Used to derive the broadcaster's address if $EOA is not defined.
string internal mnemonic;

/// @dev The project name for the Sphinx plugin.
string internal sphinxProjectName;

/// @dev Initializes the transaction broadcaster like this:
///
/// - If $ETH_FROM is defined, use it.
/// - If $EOA is defined, use it.
/// - Otherwise, derive the broadcaster address from $MNEMONIC.
/// - If $MNEMONIC is not defined, default to a test mnemonic.
/// - If $SPHINX_PROJECT_NAME is not defined, default to a test project name.
///
/// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line.
/// The use case for $EOA is to specify the broadcaster key and its address via the command line.
constructor() {
address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) });
address from = vm.envOr({ name: "EOA", defaultValue: address(0) });
if (from != address(0)) {
broadcaster = from;
} else {
mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC });
(broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 });
}
sphinxProjectName = vm.envOr({ name: "SPHINX_PROJECT_NAME", defaultValue: SPHINX_PROJECT_NAME });

// Sets `maxCount` to 300 for Avalanche, and 500 for all other chains.
if (block.chainid == AVALANCHE_CHAIN_ID) {
Expand All @@ -59,6 +68,19 @@ contract BaseScript is Script {
vm.stopBroadcast();
}

/// @dev Configures the Sphinx plugin to use Sphinx managed deployment for smart contracts.
/// Refer to https://github.com/sphinx-labs/sphinx/tree/main/docs.
/// CLI example:
/// - bun sphinx propose script/DeployCore.s.sol --networks testnets --sig "runSphinx(address)" $ADMIN
function configureSphinx() public override {
sphinxConfig.mainnets = ["arbitrum", "avalanche", "bnb", "gnosis", "ethereum", "optimism", "polygon"];
sphinxConfig.orgId = vm.envOr({ name: "SPHINX_ORG_ID", defaultValue: TEST_MNEMONIC });
sphinxConfig.owners = [broadcaster];
sphinxConfig.projectName = sphinxProjectName;
sphinxConfig.testnets = ["sepolia"];
sphinxConfig.threshold = 1;
}

/// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory:
/// https://github.com/Arachnid/deterministic-deployment-proxy
///
Expand Down
30 changes: 29 additions & 1 deletion script/DeployCore.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { BaseScript } from "./Base.s.sol";
/// 3. {SablierV2LockupLinear}
/// 4. {SablierV2LockupTranched}
contract DeployCore is BaseScript {
function run(address initialAdmin)
/// @dev Deploy using Forge CLI.
function runBroadcast(address initialAdmin)
public
virtual
broadcast
Expand All @@ -25,6 +26,33 @@ contract DeployCore is BaseScript {
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
(lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin);
}

/// @dev Deploy using Sphinx CLI.
function runSphinx(address initialAdmin)
public
virtual
sphinx
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
(lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin);
}

function _run(address initialAdmin)
internal
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
nftDescriptor = new SablierV2NFTDescriptor();
lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount);
Expand Down
34 changes: 33 additions & 1 deletion script/DeployCore2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { BaseScript } from "./Base.s.sol";
/// 2. {SablierV2LockupLinear}
/// 3. {SablierV2LockupTranched}
contract DeployCore2 is BaseScript {
function run(
/// @dev Deploy using Forge CLI.
function runBroadcast(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
Expand All @@ -26,6 +27,37 @@ contract DeployCore2 is BaseScript {
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
(lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor);
}

/// @dev Deploy using Sphinx CLI.
function runSphinx(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
public
virtual
sphinx
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
(lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor);
}

function _run(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
internal
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor);
Expand Down
30 changes: 29 additions & 1 deletion script/DeployDeterministicCore.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { BaseScript } from "./Base.s.sol";
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicCore is BaseScript {
function run(address initialAdmin)
/// @dev Deploy using Forge.
function runBroadcast(address initialAdmin)
public
virtual
broadcast
Expand All @@ -27,6 +28,33 @@ contract DeployDeterministicCore is BaseScript {
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
(lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin);
}

/// @dev Deploy using Sphinx.
function runSphinx(address initialAdmin)
public
virtual
sphinx
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
(lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin);
}

function _run(address initialAdmin)
internal
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
bytes32 salt = constructCreate2Salt();
nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }();
Expand Down
34 changes: 33 additions & 1 deletion script/DeployDeterministicCore2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { BaseScript } from "./Base.s.sol";
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicCore2 is BaseScript {
function run(
/// @dev Deploy using Forge CLI.
function runBroadcast(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
Expand All @@ -28,6 +29,37 @@ contract DeployDeterministicCore2 is BaseScript {
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
(lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor);
}

/// @dev Deploy using Sphinx CLI.
function runSphinx(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
public
virtual
sphinx
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
(lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor);
}

function _run(
address initialAdmin,
ISablierV2NFTDescriptor nftDescriptor
)
internal
returns (
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
bytes32 salt = constructCreate2Salt();
lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount);
Expand Down
26 changes: 25 additions & 1 deletion script/DeployDeterministicLockupDynamic.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,38 @@ import { BaseScript } from "./Base.s.sol";
/// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains.
/// @dev Reverts if the contract has already been deployed.
contract DeployDeterministicLockupDynamic is BaseScript {
function run(
/// @dev Deploy using Forge CLI.
function runBroadcast(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
broadcast
returns (SablierV2LockupDynamic lockupDynamic)
{
lockupDynamic = _run(initialAdmin, initialNFTDescriptor);
}

/// @dev Deploy using Sphinx CLI.
function runSphinx(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
sphinx
returns (SablierV2LockupDynamic lockupDynamic)
{
lockupDynamic = _run(initialAdmin, initialNFTDescriptor);
}

function _run(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
internal
returns (SablierV2LockupDynamic lockupDynamic)
{
bytes32 salt = constructCreate2Salt();
lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount);
Expand Down
26 changes: 25 additions & 1 deletion script/DeployDeterministicLockupLinear.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,38 @@ import { BaseScript } from "./Base.s.sol";
/// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains.
/// @dev Reverts if the contract has already been deployed.
contract DeployDeterministicLockupLinear is BaseScript {
function run(
/// @dev Deploy using Forge CLI.
function runBroadcast(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
broadcast
returns (SablierV2LockupLinear lockupLinear)
{
lockupLinear = _run(initialAdmin, initialNFTDescriptor);
}

/// @dev Deploy using Sphinx CLI.
function runSphinx(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
sphinx
returns (SablierV2LockupLinear lockupLinear)
{
lockupLinear = _run(initialAdmin, initialNFTDescriptor);
}

function _run(
address initialAdmin,
ISablierV2NFTDescriptor initialNFTDescriptor
)
internal
returns (SablierV2LockupLinear lockupLinear)
{
bytes32 salt = constructCreate2Salt();
lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor);
Expand Down
Loading

0 comments on commit 3bb0dc2

Please sign in to comment.