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
15 changes: 15 additions & 0 deletions contracts/contracts/interfaces/hydrex/IHydrexGauge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @title IHydrexGauge
* @notice Minimal interface exposing the staked-token getter used by the
* Hydrex GaugeV2 (>= v2.5). Hydrex renamed `TOKEN()` to `stakeToken()`
* in v2.5; the rest of the gauge surface (deposit / withdraw /
* getReward / emergency / emergencyWithdraw / balanceOf) is
* ABI-compatible with `IAlgebraGauge` and is invoked through that
* interface elsewhere in the strategy.
*/
interface IHydrexGauge {
function stakeToken() external view returns (address);
}
7 changes: 7 additions & 0 deletions contracts/contracts/proxies/Proxies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,10 @@ contract OUSDMorphoV2StrategyProxy is InitializeGovernedUpgradeabilityProxy {
contract OETHSupernovaAMOProxy is InitializeGovernedUpgradeabilityProxy {

}

/**
* @notice OETHbHydrexAMOProxy delegates calls to an OETHbHydrexAMOStrategy implementation
*/
contract OETHbHydrexAMOProxy is InitializeGovernedUpgradeabilityProxy {

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pragma solidity ^0.8.0;
* @author Origin Protocol Inc
*/
import { StableSwapAMMStrategy } from "./StableSwapAMMStrategy.sol";
import { IGauge } from "../../interfaces/algebra/IAlgebraGauge.sol";

contract OETHSupernovaAMOStrategy is StableSwapAMMStrategy {
/**
Expand All @@ -15,6 +16,6 @@ contract OETHSupernovaAMOStrategy is StableSwapAMMStrategy {
* @param _gauge Address of the Supernova gauge for the pool.
*/
constructor(BaseStrategyConfig memory _baseConfig, address _gauge)
StableSwapAMMStrategy(_baseConfig, _gauge)
StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())
{}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,18 @@ contract StableSwapAMMStrategy is InitializableAbstractStrategy {
* @param _baseConfig The `platformAddress` is the address of the Algebra pool.
* The `vaultAddress` is the address of the Origin Vault.
* @param _gauge Address of the Algebra gauge for the pool.
* @param _gaugeStakeToken The pool LP token address as reported by the
* gauge. The inheriting contract is expected to resolve this via
* whichever getter its gauge exposes (e.g. `IGauge.TOKEN()` for
* legacy GaugeV2 ≤ v2.4 or `IHydrexGauge.stakeToken()` for
* Hydrex GaugeV2 ≥ v2.5) and pass the result here. The constructor
* verifies it matches `_baseConfig.platformAddress`.
*/
constructor(BaseStrategyConfig memory _baseConfig, address _gauge)
InitializableAbstractStrategy(_baseConfig)
{
constructor(
BaseStrategyConfig memory _baseConfig,
address _gauge,
address _gaugeStakeToken
) InitializableAbstractStrategy(_baseConfig) {
// Read the oToken address from the Vault
address oTokenMem = IVault(_baseConfig.vaultAddress).oToken();
address assetMem = IVault(_baseConfig.vaultAddress).asset();
Expand All @@ -178,9 +186,11 @@ contract StableSwapAMMStrategy is InitializableAbstractStrategy {
IPair(_baseConfig.platformAddress).isStable() == true,
"Pool not stable"
);
// Check the gauge is for the pool
// Check the gauge is wired to the expected pool LP token. The
// inheriting contract is responsible for fetching `_gaugeStakeToken`
// from whichever getter the underlying gauge variant exposes.
require(
IGauge(_gauge).TOKEN() == _baseConfig.platformAddress,
_gaugeStakeToken == _baseConfig.platformAddress,
"Incorrect gauge"
);
oTokenPoolIndex = IPair(_baseConfig.platformAddress).token0() ==
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

/**
* @title OETHb Hydrex Algorithmic Market Maker (AMO) Strategy
* @notice AMO strategy for the Hydrex superOETHb/WETH stable pool on Base
* @author Origin Protocol Inc
*/
import { StableSwapAMMStrategy } from "../algebra/StableSwapAMMStrategy.sol";
import { IHydrexGauge } from "../../interfaces/hydrex/IHydrexGauge.sol";

contract OETHbHydrexAMOStrategy is StableSwapAMMStrategy {
/**
* @param _baseConfig The `platformAddress` is the address of the Hydrex superOETHb/WETH pool.
* The `vaultAddress` is the address of the OETHBase Vault.
* @param _gauge Address of the Hydrex gauge for the pool. Hydrex GaugeV2
* (>= v2.5) renamed `TOKEN()` to `stakeToken()`, which is what we
* resolve here and forward to the parent.
*/
constructor(BaseStrategyConfig memory _baseConfig, address _gauge)
StableSwapAMMStrategy(
_baseConfig,
_gauge,
IHydrexGauge(_gauge).stakeToken()
)
{}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pragma solidity ^0.8.0;
* @author Origin Protocol Inc
*/
import { StableSwapAMMStrategy } from "../algebra/StableSwapAMMStrategy.sol";
import { IGauge } from "../../interfaces/algebra/IAlgebraGauge.sol";

contract SonicSwapXAMOStrategy is StableSwapAMMStrategy {
/**
Expand All @@ -15,6 +16,6 @@ contract SonicSwapXAMOStrategy is StableSwapAMMStrategy {
* @param _gauge Address of the SwapX gauge for the pool.
*/
constructor(BaseStrategyConfig memory _baseConfig, address _gauge)
StableSwapAMMStrategy(_baseConfig, _gauge)
StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())
{}
}
75 changes: 75 additions & 0 deletions contracts/deploy/base/048_oethb_hydrex_amo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const { deployOnBase } = require("../../utils/deploy-l2");
const addresses = require("../../utils/addresses");
const {
deployOETHbHydrexAMOStrategyImplementation,
} = require("../deployActions");

module.exports = deployOnBase(
{
deployName: "048_oethb_hydrex_amo",
},
async ({ deployWithConfirmation, ethers }) => {
// 1. Deploy the OETHb Hydrex AMO proxy
await deployWithConfirmation("OETHbHydrexAMOProxy");
const cOETHbHydrexAMOProxy = await ethers.getContract(
"OETHbHydrexAMOProxy"
);

// 2. Deploy & initialize the strategy implementation against the live
// Hydrex gauge configured in addresses.base.HydrexOETHb_WETH.gauge.
const cOETHbHydrexAMOStrategy =
await deployOETHbHydrexAMOStrategyImplementation(
addresses.base.HydrexOETHb_WETH.gauge
);

// 3. Connect to the OETHBase Vault as IVault
const cOETHBaseVaultProxy = await ethers.getContract("OETHBaseVaultProxy");
const cVault = await ethers.getContractAt(
"IVault",
cOETHBaseVaultProxy.address
);

// 4. Connect to the OETHBase harvester proxy. Use the same harvester
// that AerodromeAMOStrategy uses (OETHHarvesterSimple via the
// OETHBaseHarvesterProxy) so reward token flows go through the
// standard Origin harvester pipeline.
const cHarvesterProxy = await ethers.getContract("OETHBaseHarvesterProxy");
const cHarvester = await ethers.getContractAt(
"OETHHarvesterSimple",
cHarvesterProxy.address
);

return {
name: "Deploy OETHb Hydrex AMO Strategy on Base",
actions: [
// Approve the strategy on the OETHBase Vault
{
contract: cVault,
signature: "approveStrategy(address)",
args: [cOETHbHydrexAMOProxy.address],
},
// Allow the strategy to mint OETHb via the Vault
{
contract: cVault,
signature: "addStrategyToMintWhitelist(address)",
args: [cOETHbHydrexAMOProxy.address],
},
// Set the harvester address on the strategy. Rewards (oHYDX) flow
// strategy → harvester → strategist via OETHHarvesterSimple's
// harvestAndTransfer.
{
contract: cOETHbHydrexAMOStrategy,
signature: "setHarvesterAddress(address)",
args: [cHarvesterProxy.address],
},
// Mark the strategy as supported on the harvester so
// harvestAndTransfer(strategy) doesn't revert.
{
contract: cHarvester,
signature: "setSupportedStrategy(address,bool)",
args: [cOETHbHydrexAMOProxy.address, true],
},
],
};
}
);
50 changes: 50 additions & 0 deletions contracts/deploy/deployActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,55 @@ const deployOETHSupernovaAMOStrategyImplementation = async () => {
return cOETHSupernovaAMOStrategy;
};

const deployOETHbHydrexAMOStrategyImplementation = async (gaugeAddress) => {
const { deployerAddr } = await getNamedAccounts();
const sDeployer = await ethers.provider.getSigner(deployerAddr);

// Default to the addresses entry so any other caller still works; the
// 048_oethb_hydrex_amo deploy script always passes the live Hydrex gauge
// address explicitly.
const _gauge = gaugeAddress || addresses.base.HydrexOETHb_WETH.gauge;

const cOETHbHydrexAMOStrategyProxy = await ethers.getContract(
"OETHbHydrexAMOProxy"
);
const cOETHBaseVaultProxy = await ethers.getContract("OETHBaseVaultProxy");

// Deploy OETHb Hydrex AMO Strategy implementation
const dHydrexAMOStrategy = await deployWithConfirmation(
"OETHbHydrexAMOStrategy",
[
[addresses.base.HydrexOETHb_WETH.pool, cOETHBaseVaultProxy.address],
_gauge,
]
);

const cOETHbHydrexAMOStrategy = await ethers.getContractAt(
"OETHbHydrexAMOStrategy",
cOETHbHydrexAMOStrategyProxy.address
);

// Initialize OETHb Hydrex AMO Strategy via the proxy.
// Reward token is oHYDX (call option on HYDX). The Hydrex gauge emits oHYDX
// from getReward(); off-chain plumbing exercises/sells it.
const depositPriceRange = parseUnits("0.01", 18); // 1% or 100 basis points
const initData = cOETHbHydrexAMOStrategy.interface.encodeFunctionData(
"initialize(address[],uint256)",
[[addresses.base.oHYDX], depositPriceRange]
);
await withConfirmation(
// prettier-ignore
cOETHbHydrexAMOStrategyProxy
.connect(sDeployer)["initialize(address,address,bytes)"](
dHydrexAMOStrategy.address,
addresses.base.timelock,
initData
)
);

return cOETHbHydrexAMOStrategy;
};

const getCreate2ProxiesFilePath = async () => {
const networkName =
isFork || isForkTest || isCI ? "localhost" : await getNetworkName();
Expand Down Expand Up @@ -1270,6 +1319,7 @@ module.exports = {
deploySonicSwapXAMOStrategyImplementation,
deploySonicSwapXAMOStrategyImplementationAndInitialize,
deployOETHSupernovaAMOStrategyImplementation,
deployOETHbHydrexAMOStrategyImplementation,
deployProxyWithCreateX,
deployCrossChainMasterStrategyImpl,
deployCrossChainRemoteStrategyImpl,
Expand Down
Loading
Loading