diff --git a/script/dependencies/phase-1d/LsmkrSpkFarmingInit.sol b/script/dependencies/phase-1d/LsmkrSpkFarmingInit.sol
new file mode 100644
index 0000000..a39ec9f
--- /dev/null
+++ b/script/dependencies/phase-1d/LsmkrSpkFarmingInit.sol
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+pragma solidity ^0.8.16;
+
+import {StakingRewardsInit, StakingRewardsInitParams} from "../StakingRewardsInit.sol";
+import {VestedRewardsDistributionInit, VestedRewardsDistributionInitParams} from "../VestedRewardsDistributionInit.sol";
+import {VestInit, VestCreateParams} from "../VestInit.sol";
+
+struct LsmkrSpkFarmingInitParams {
+ address lsmkr;
+ address spk;
+ address rewards;
+ bytes32 rewardsKey; // Chainlog key
+ address dist;
+ bytes32 distKey; // Chainlog key
+ address vest;
+ uint256 vestTot;
+ uint256 vestBgn;
+ uint256 vestTau;
+}
+
+struct LsmkrSpkFarmingInitResult {
+ uint256 vestId;
+}
+
+library LsmkrSpkFarmingInit {
+ ChainlogLike internal constant chainlog = ChainlogLike(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F);
+
+ function init(LsmkrSpkFarmingInitParams memory p) internal returns (LsmkrSpkFarmingInitResult memory r) {
+ require(DssVestWithGemLike(p.vest).gem() == p.spk, "LsmkrSpkFarmingInit/vest-gem-mismatch");
+
+ require(
+ StakingRewardsLike(p.rewards).stakingToken() == p.lsmkr,
+ "LsmkrSpkFarmingInit/rewards-staking-token-mismatch"
+ );
+ require(
+ StakingRewardsLike(p.rewards).rewardsToken() == p.spk,
+ "LsmkrSpkFarmingInit/rewards-rewards-token-mismatch"
+ );
+ require(StakingRewardsLike(p.rewards).rewardRate() == 0, "LsmkrSpkFarmingInit/reward-rate-not-zero");
+ require(
+ StakingRewardsLike(p.rewards).rewardsDistribution() == address(0),
+ "LsmkrSpkFarmingInit/rewards-distribution-already-set"
+ );
+ require(
+ StakingRewardsLike(p.rewards).owner() == chainlog.getAddress("MCD_PAUSE_PROXY"),
+ "LsmkrSpkFarmingInit/invalid-owner"
+ );
+
+ require(VestedRewardsDistributionLike(p.dist).gem() == p.spk, "LsmkrSpkFarmingInit/dist-gem-mismatch");
+ require(
+ VestedRewardsDistributionLike(p.dist).dssVest() == p.vest,
+ "LsmkrSpkFarmingInit/dist-dss-vest-mismatch"
+ );
+ require(
+ VestedRewardsDistributionLike(p.dist).stakingRewards() == p.rewards,
+ "LsmkrSpkFarmingInit/dist-staking-rewards-mismatch"
+ );
+
+ // `vest` is expected to be an instance of `DssVestMintable`.
+ // Check if minting rights on `spk` were granted to `vest`.
+ require(WardsLike(p.spk).wards(p.vest) == 1, "LsmkrSpkFarmingInit/missing-spk-rely-vest");
+ // Set `dist` with `rewardsDistribution` role in `rewards`.
+ StakingRewardsInit.init(p.rewards, StakingRewardsInitParams({dist: p.dist}));
+
+ // Create the proper vesting stream for rewards distribution.
+ uint256 vestId = VestInit.create(
+ p.vest,
+ VestCreateParams({usr: p.dist, tot: p.vestTot, bgn: p.vestBgn, tau: p.vestTau, eta: 0})
+ );
+
+ // Set the `vestId` in `dist`
+ VestedRewardsDistributionInit.init(p.dist, VestedRewardsDistributionInitParams({vestId: vestId}));
+
+ r.vestId = vestId;
+
+ chainlog.setAddress(p.rewardsKey, p.rewards);
+ chainlog.setAddress(p.distKey, p.dist);
+ }
+}
+
+interface WardsLike {
+ function wards(address who) external view returns (uint256);
+}
+
+interface DssVestWithGemLike {
+ function gem() external view returns (address);
+}
+
+interface StakingRewardsLike {
+ function owner() external view returns (address);
+
+ function rewardRate() external view returns (uint256);
+
+ function rewardsDistribution() external view returns (address);
+
+ function rewardsToken() external view returns (address);
+
+ function stakingToken() external view returns (address);
+}
+
+interface VestedRewardsDistributionLike {
+ function dssVest() external view returns (address);
+
+ function gem() external view returns (address);
+
+ function stakingRewards() external view returns (address);
+}
+
+interface ChainlogLike {
+ function getAddress(bytes32 key) external view returns (address);
+
+ function setAddress(bytes32 key, address addr) external;
+}
diff --git a/script/input/1/phase-1d/template-lsmkr-spk-farming-deploy.json b/script/input/1/phase-1d/template-lsmkr-spk-farming-deploy.json
new file mode 100644
index 0000000..05d9fea
--- /dev/null
+++ b/script/input/1/phase-1d/template-lsmkr-spk-farming-deploy.json
@@ -0,0 +1,7 @@
+{
+ "lsmkr": "address: the address of LSMKR",
+ "spk": "address: the address of SPK",
+ "vest": "address: the address of a DssVestMintable contract for SPK",
+ "rewards": "[OPTIONAL] address: the address of the StakingRewards contract",
+ "dist": "[OPTIONAL] address: the address of the VestedRewardsDistrubution contract"
+}
diff --git a/script/input/314310/phase-1d/template-lsmkr-spk-farming-deploy.json b/script/input/314310/phase-1d/template-lsmkr-spk-farming-deploy.json
new file mode 100644
index 0000000..05d9fea
--- /dev/null
+++ b/script/input/314310/phase-1d/template-lsmkr-spk-farming-deploy.json
@@ -0,0 +1,7 @@
+{
+ "lsmkr": "address: the address of LSMKR",
+ "spk": "address: the address of SPK",
+ "vest": "address: the address of a DssVestMintable contract for SPK",
+ "rewards": "[OPTIONAL] address: the address of the StakingRewards contract",
+ "dist": "[OPTIONAL] address: the address of the VestedRewardsDistrubution contract"
+}
diff --git a/script/phase-1d/31-LsmkrSpkFarmingDeploy.s.sol b/script/phase-1d/31-LsmkrSpkFarmingDeploy.s.sol
new file mode 100644
index 0000000..84e3685
--- /dev/null
+++ b/script/phase-1d/31-LsmkrSpkFarmingDeploy.s.sol
@@ -0,0 +1,76 @@
+// SPDX-FileCopyrightText: © 2023 Dai Foundation
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+pragma solidity ^0.8.16;
+
+import {Script} from "forge-std/Script.sol";
+import {ScriptTools} from "dss-test/ScriptTools.sol";
+
+import {Reader} from "../helpers/Reader.sol";
+import {StakingRewardsDeploy, StakingRewardsDeployParams} from "../dependencies/StakingRewardsDeploy.sol";
+import {
+ VestedRewardsDistributionDeploy,
+ VestedRewardsDistributionDeployParams
+} from "../dependencies/VestedRewardsDistributionDeploy.sol";
+
+contract Phase1d_LsmkrSpkFarmingDeployScript is Script {
+ ChainlogLike internal constant chainlog = ChainlogLike(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F);
+
+ string internal constant NAME = "phase-1d/lsmkr-spk-farming-deploy";
+
+ function run() external {
+ Reader reader = new Reader(ScriptTools.loadConfig());
+
+ address admin = chainlog.getAddress("MCD_PAUSE_PROXY");
+
+ address lsmkr = reader.envOrReadAddress("FOUNDRY_LSMKR", ".lsmkr");
+ address spk = reader.envOrReadAddress("FOUNDRY_SPK", ".spk");
+ address vest = reader.envOrReadAddress("FOUNDRY_VEST", ".vest");
+ address dist = reader.readAddressOptional(".dist");
+ address rewards = reader.readAddressOptional(".rewards");
+
+ vm.startBroadcast();
+
+ if (rewards == address(0)) {
+ rewards = StakingRewardsDeploy.deploy(
+ StakingRewardsDeployParams({owner: admin, stakingToken: lsmkr, rewardsToken: spk})
+ );
+ }
+
+ if (dist == address(0)) {
+ dist = VestedRewardsDistributionDeploy.deploy(
+ VestedRewardsDistributionDeployParams({
+ deployer: msg.sender,
+ owner: admin,
+ vest: vest,
+ rewards: rewards
+ })
+ );
+ }
+
+ vm.stopBroadcast();
+
+ ScriptTools.exportContract(NAME, "admin", admin);
+ ScriptTools.exportContract(NAME, "spk", spk);
+ ScriptTools.exportContract(NAME, "lsmkr", lsmkr);
+ ScriptTools.exportContract(NAME, "dist", dist);
+ ScriptTools.exportContract(NAME, "rewards", rewards);
+ ScriptTools.exportContract(NAME, "vest", vest);
+ }
+}
+
+interface ChainlogLike {
+ function getAddress(bytes32 _key) external view returns (address addr);
+}
diff --git a/script/phase-1d/32-LsmkrSpkFarmingInit.s.sol b/script/phase-1d/32-LsmkrSpkFarmingInit.s.sol
new file mode 100644
index 0000000..a5dcb52
--- /dev/null
+++ b/script/phase-1d/32-LsmkrSpkFarmingInit.s.sol
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: © 2023 Dai Foundation
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+pragma solidity ^0.8.16;
+
+import {Script} from "forge-std/Script.sol";
+import {ScriptTools} from "dss-test/ScriptTools.sol";
+
+import {Reader} from "../helpers/Reader.sol";
+import {
+ LsmkrSpkFarmingInit,
+ LsmkrSpkFarmingInitParams,
+ LsmkrSpkFarmingInitResult
+} from "../dependencies/phase-1d/LsmkrSpkFarmingInit.sol";
+
+contract Phase1d_LsmkrSpkFarmingInitScript is Script {
+ using ScriptTools for string;
+
+ ChainlogLike internal constant chainlog = ChainlogLike(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F);
+
+ string internal constant NAME = "phase-1d/lsmkr-spk-farming-init";
+
+ function run() external {
+ Reader config = new Reader(ScriptTools.loadConfig());
+ Reader deps = new Reader(ScriptTools.loadDependencies());
+
+ uint256 vestTot = config.envOrReadUint("FOUNDRY_VEST_TOT", ".vestTot");
+ uint256 vestBgn = config.envOrReadUint("FOUNDRY_VEST_BGN", ".vestBgn");
+ uint256 vestTau = config.envOrReadUint("FOUNDRY_VEST_TAU", ".vestTau");
+
+ address lsmkr = deps.envOrReadAddress("FOUNDRY_LSMKR", ".lsmkr");
+ address spk = deps.envOrReadAddress("FOUNDRY_SPK", ".spk");
+ address dist = deps.envOrReadAddress("FOUNDRY_DIST", ".dist");
+ address rewards = deps.envOrReadAddress("FOUNDRY_FARM", ".rewards");
+ address vest = deps.envOrReadAddress("FOUNDRY_VEST", ".vest");
+
+ LsmkrSpkFarmingInitParams memory farmingCfg = LsmkrSpkFarmingInitParams({
+ spk: spk,
+ lsmkr: lsmkr,
+ dist: dist,
+ distKey: "REWARDS_DISTRIBUTION_LSMKR_SPK",
+ rewards: rewards,
+ rewardsKey: "FARM_LSMKR_SPK",
+ vest: vest,
+ vestTot: vestTot,
+ vestBgn: vestBgn,
+ vestTau: vestTau
+ });
+
+ address pauseProxy = chainlog.getAddress("MCD_PAUSE_PROXY");
+
+ vm.startBroadcast();
+
+ LsmkrSpkFarmingInitSpell spell = new LsmkrSpkFarmingInitSpell();
+ bytes memory out = ProxyLike(pauseProxy).exec(address(spell), abi.encodeCall(spell.cast, (farmingCfg)));
+
+ vm.stopBroadcast();
+
+ LsmkrSpkFarmingInitResult memory res = abi.decode(out, (LsmkrSpkFarmingInitResult));
+
+ ScriptTools.exportContract(NAME, "spk", spk);
+ ScriptTools.exportContract(NAME, "dist", dist);
+ ScriptTools.exportContract(NAME, "rewards", rewards);
+ ScriptTools.exportContract(NAME, "vest", vest);
+ ScriptTools.exportValue(NAME, "vestId", res.vestId);
+ }
+}
+
+contract LsmkrSpkFarmingInitSpell {
+ uint256 internal constant CAP = type(uint256).max;
+
+ function cast(LsmkrSpkFarmingInitParams memory farmingCfg) public returns (LsmkrSpkFarmingInitResult memory) {
+ DssVestLike(farmingCfg.vest).file("cap", CAP);
+ return LsmkrSpkFarmingInit.init(farmingCfg);
+ }
+}
+
+interface ProxyLike {
+ function exec(address usr, bytes memory fax) external returns (bytes memory out);
+}
+
+interface ChainlogLike {
+ function getAddress(bytes32 _key) external view returns (address addr);
+}
+
+interface DssVestLike {
+ function file(bytes32 _what, uint256 _data) external;
+}
diff --git a/script/phase-1d/33-LsmkrSpkFarmingCheck.s.sol b/script/phase-1d/33-LsmkrSpkFarmingCheck.s.sol
new file mode 100644
index 0000000..f76facb
--- /dev/null
+++ b/script/phase-1d/33-LsmkrSpkFarmingCheck.s.sol
@@ -0,0 +1,109 @@
+// SPDX-FileCopyrightText: © 2023 Dai Foundation
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+pragma solidity ^0.8.16;
+
+import {Script} from "forge-std/Script.sol";
+import {ScriptTools} from "dss-test/ScriptTools.sol";
+import {Reader} from "../helpers/Reader.sol";
+
+contract Phase1d_LsmkrSpkFarmingCheckScript is Script {
+ function run() external returns (bool) {
+ Reader config = new Reader(ScriptTools.loadConfig());
+ Reader deps = new Reader(ScriptTools.loadDependencies());
+
+ address admin = deps.envOrReadAddress("FOUNDRY_ADMIN", ".admin");
+ address lsmkr = deps.envOrReadAddress("FOUNDRY_LSMKR", ".lsmkr");
+ address spk = deps.envOrReadAddress("FOUNDRY_SPK", ".spk");
+ address dist = deps.readAddress(".dist");
+ address rewards = deps.readAddress(".rewards");
+ address vest = deps.readAddress(".vest");
+ uint256 vestId = deps.readUint(".vestId");
+ uint256 vestBgn = config.readUint(".vestBgn");
+ uint256 vestTau = config.readUint(".vestTau");
+ uint256 vestTot = config.readUint(".vestTot");
+
+ require(VestedRewardsDistributionLike(dist).dssVest() == vest, "VestedRewardsDistribution/invalid-vest");
+ require(VestedRewardsDistributionLike(dist).vestId() == vestId, "VestedRewardsDistribution/invalid-vest-id");
+ require(VestedRewardsDistributionLike(dist).gem() == spk, "VestedRewardsDistribution/invalid-gem");
+ require(
+ VestedRewardsDistributionLike(dist).stakingRewards() == rewards,
+ "VestedRewardsDistribution/invalid-staking-rewards"
+ );
+
+ require(StakingRewardsLike(rewards).owner() == admin, "StakingRewards/admin-not-owner");
+ require(StakingRewardsLike(rewards).rewardsToken() == spk, "StakingRewards/invalid-rewards-token");
+ require(StakingRewardsLike(rewards).stakingToken() == lsmkr, "StakingRewards/invalid-staking-token");
+ require(
+ StakingRewardsLike(rewards).rewardsDistribution() == dist,
+ "StakingRewards/invalid-rewards-distribution"
+ );
+
+ require(WardsLike(spk).wards(vest) == 1, "Spk/dss-vest-not-ward");
+
+ require(DssVestWithGemLike(vest).gem() == spk, "DssVest/invalid-gem");
+ require(DssVestWithGemLike(vest).valid(vestId), "DssVest/invalid-vest-id");
+ require(DssVestWithGemLike(vest).res(vestId) == 1, "DssVest/invalid-vest-res");
+ require(DssVestWithGemLike(vest).usr(vestId) == dist, "DssVest/wrong-dist");
+ require(DssVestWithGemLike(vest).mgr(vestId) == address(0), "DssVest/mgr-should-not-be-set");
+ require(DssVestWithGemLike(vest).bgn(vestId) == vestBgn, "DssVest/invalid-bgn");
+ require(DssVestWithGemLike(vest).fin(vestId) == vestBgn + vestTau, "DssVest/invalid-tau");
+ require(DssVestWithGemLike(vest).tot(vestId) == vestTot, "DssVest/invalid-tot");
+
+ return true;
+ }
+}
+
+interface WardsLike {
+ function wards(address who) external view returns (uint256);
+}
+
+interface VestedRewardsDistributionLike {
+ function dssVest() external view returns (address);
+
+ function vestId() external view returns (uint256);
+
+ function stakingRewards() external view returns (address);
+
+ function gem() external view returns (address);
+}
+
+interface StakingRewardsLike {
+ function owner() external view returns (address);
+
+ function stakingToken() external view returns (address);
+
+ function rewardsToken() external view returns (address);
+
+ function rewardsDistribution() external view returns (address);
+}
+
+interface DssVestWithGemLike {
+ function bgn(uint256 _id) external view returns (uint256);
+
+ function fin(uint256 _id) external view returns (uint256);
+
+ function gem() external view returns (address);
+
+ function mgr(uint256 _id) external view returns (address);
+
+ function res(uint256 _id) external view returns (uint256);
+
+ function tot(uint256 _id) external view returns (uint256);
+
+ function usr(uint256 _id) external view returns (address);
+
+ function valid(uint256 _id) external view returns (bool);
+}