Address
0xaecc09f173eba3b3cc2f486e10d8182be0eb335aCurrent Holdings
$0.00
TXs sent
not counted
First Active
2026-06-19
block 26,825,329
Last Active
88 days ago
block 26,825,329
Funded By
not identified
Net worth historyi
No net-worth snapshots recorded yet
exact matchSynergyPositionVaultFactorysolc 0.8.20+commit.a1b79de6runtime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
interface IPositionVaultERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
interface ISynergizeVaultAccounting {
function recordVaultDeposit(address owner, address pool, uint256 amount) external;
function recordVaultWithdraw(address owner, address pool, uint256 amount) external;
function recordVaultEmergencyWithdraw(address owner, address pool, uint256 amount) external;
}
interface IPositionVaultFactory {
function computeVault(address owner, address pool, address farm) external view returns (address);
}
library PositionVaultSafeToken {
function safeTransfer(address token, address to, uint256 amount) internal {
(bool ok, bytes memory ret) = token.call(abi.encodeCall(IPositionVaultERC20.transfer, (to, amount)));
require(ok && (ret.length == 0 || abi.decode(ret, (bool))), "token transfer failed");
}
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
(bool ok, bytes memory ret) = token.call(
abi.encodeCall(IPositionVaultERC20.transferFrom, (from, to, amount))
);
require(ok && (ret.length == 0 || abi.decode(ret, (bool))), "token transferFrom failed");
}
}
abstract contract PositionVaultReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status = _NOT_ENTERED;
modifier nonReentrant() {
require(_status != _ENTERED, "Reentrant");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
/// @notice Non-upgradeable owner+pool LP custody vault. The vault owns custody;
/// Synergize owns reward accounting. The farm has no LP withdrawal path.
contract SynergyPositionVault is PositionVaultReentrancyGuard {
uint256 public constant BPS = 10_000;
uint256 public constant LP_WITHDRAWAL_FEE_BPS = 200;
uint256 public constant LP_WITHDRAWAL_LOCK_BPS = 100;
uint256 public constant LP_WITHDRAWAL_TREASURY_BPS = 70;
uint256 public constant LP_WITHDRAWAL_SCADA_CREATOR_BPS = 30;
uint256 public constant MIN_WITHDRAWABLE_LP = 334;
address public constant PULSECHAIN_LP_SINK = 0x0000000000000000000000000000000000000369;
address public immutable OWNER;
address public immutable POOL;
address public immutable FARM;
address public immutable PERMANENT_LP_SINK;
address public immutable TREASURY_RECIPIENT;
address public immutable SCADA_CREATOR_RECIPIENT;
uint256 public accountedLP;
event Deposited(uint256 amount);
event Withdrawn(uint256 amount, uint256 returnedLP, uint256 lockedLP, uint256 treasuryLP, uint256 scadaCreatorLP);
event EmergencyWithdrawn(uint256 amount, uint256 returnedLP, uint256 lockedLP, uint256 treasuryLP, uint256 scadaCreatorLP, bool farmNotified);
event FarmWithdrawWithFee(
address indexed user,
address indexed pool,
address indexed lpToken,
uint256 amountRequested,
uint256 amountToUser,
uint256 permanentLpLocked,
uint256 treasuryFee,
uint256 scadaCreatorFee
);
event EmergencyAccountingCallbackFailed(uint256 amount);
constructor(
address owner_,
address pool_,
address farm_,
address permanentLpSink_,
address treasuryRecipient_,
address scadaCreatorRecipient_
) {
require(owner_ != address(0), "owner=0");
require(pool_.code.length > 0, "pool not contract");
require(farm_.code.length > 0, "farm not contract");
require(permanentLpSink_ == PULSECHAIN_LP_SINK, "bad sink");
require(treasuryRecipient_ != address(0), "treasury=0");
require(scadaCreatorRecipient_ != address(0), "scada creator=0");
OWNER = owner_;
POOL = pool_;
FARM = farm_;
PERMANENT_LP_SINK = permanentLpSink_;
TREASURY_RECIPIENT = treasuryRecipient_;
SCADA_CREATOR_RECIPIENT = scadaCreatorRecipient_;
}
modifier onlyOwner() {
require(msg.sender == OWNER, "owner only");
_;
}
function deposit(uint256 amount) external onlyOwner nonReentrant {
require(amount > 0, "amount=0");
uint256 beforeBal = IPositionVaultERC20(POOL).balanceOf(address(this));
PositionVaultSafeToken.safeTransferFrom(POOL, OWNER, address(this), amount);
uint256 received = IPositionVaultERC20(POOL).balanceOf(address(this)) - beforeBal;
require(received > 0, "no lp received");
require(received >= MIN_WITHDRAWABLE_LP, "deposit too small");
accountedLP += received;
ISynergizeVaultAccounting(FARM).recordVaultDeposit(OWNER, POOL, received);
emit Deposited(received);
}
function withdraw(uint256 amount) external onlyOwner nonReentrant {
_validateExitAmount(amount);
ISynergizeVaultAccounting(FARM).recordVaultWithdraw(OWNER, POOL, amount);
accountedLP -= amount;
(uint256 returnedLP, uint256 lockedLP, uint256 treasuryLP, uint256 scadaCreatorLP) = _payFootprint(amount);
emit Withdrawn(amount, returnedLP, lockedLP, treasuryLP, scadaCreatorLP);
}
/// @notice Owner-only LP escape hatch. It attempts to notify farm accounting,
/// but LP return is not blocked by farm/policy/oracle failure.
function emergencyWithdraw(uint256 amount) external onlyOwner nonReentrant {
_validateExitAmount(amount);
bool farmNotified;
try ISynergizeVaultAccounting(FARM).recordVaultEmergencyWithdraw(OWNER, POOL, amount) {
farmNotified = true;
} catch {
emit EmergencyAccountingCallbackFailed(amount);
}
accountedLP -= amount;
(uint256 returnedLP, uint256 lockedLP, uint256 treasuryLP, uint256 scadaCreatorLP) = _payFootprint(amount);
emit EmergencyWithdrawn(amount, returnedLP, lockedLP, treasuryLP, scadaCreatorLP, farmNotified);
}
function _validateExitAmount(uint256 amount) private view {
require(amount > 0 && amount <= accountedLP, "bad amount");
uint256 remaining = accountedLP - amount;
require(remaining == 0 || remaining >= MIN_WITHDRAWABLE_LP, "remaining lp too small");
}
function _payFootprint(uint256 amount)
private
returns (uint256 returnedLP, uint256 lockedLP, uint256 treasuryLP, uint256 scadaCreatorLP)
{
lockedLP = amount * LP_WITHDRAWAL_LOCK_BPS / BPS;
treasuryLP = amount * LP_WITHDRAWAL_TREASURY_BPS / BPS;
scadaCreatorLP = amount * LP_WITHDRAWAL_SCADA_CREATOR_BPS / BPS;
uint256 targetFee = amount * LP_WITHDRAWAL_FEE_BPS / BPS;
uint256 allocatedFee = lockedLP + treasuryLP + scadaCreatorLP;
if (targetFee > allocatedFee) lockedLP += targetFee - allocatedFee;
returnedLP = amount - lockedLP - treasuryLP - scadaCreatorLP;
if (lockedLP > 0) PositionVaultSafeToken.safeTransfer(POOL, PERMANENT_LP_SINK, lockedLP);
if (treasuryLP > 0) PositionVaultSafeToken.safeTransfer(POOL, TREASURY_RECIPIENT, treasuryLP);
if (scadaCreatorLP > 0) PositionVaultSafeToken.safeTransfer(POOL, SCADA_CREATOR_RECIPIENT, scadaCreatorLP);
if (returnedLP > 0) PositionVaultSafeToken.safeTransfer(POOL, OWNER, returnedLP);
emit FarmWithdrawWithFee(OWNER, POOL, POOL, amount, returnedLP, lockedLP, treasuryLP, scadaCreatorLP);
}
function custodyInvariantHolds() external view returns (bool) {
return IPositionVaultERC20(POOL).balanceOf(address(this)) >= accountedLP;
}
}
/// @notice Stateless deterministic factory. The farm address is part of the
/// salt, so the same owner+pool can have distinct vaults per farm.
contract SynergyPositionVaultFactory {
address public constant PULSECHAIN_LP_SINK = 0x0000000000000000000000000000000000000369;
address public immutable PERMANENT_LP_SINK;
address public immutable TREASURY_RECIPIENT;
address public immutable SCADA_CREATOR_RECIPIENT;
event VaultCreated(address indexed owner, address indexed pool, address indexed farm, address vault);
event WithdrawFeeRecipientsConfigured(address permanentLpSink, address treasuryRecipient, address scadaCreatorRecipient);
constructor(address permanentLpSink_, address treasuryRecipient_, address scadaCreatorRecipient_) {
require(permanentLpSink_ == PULSECHAIN_LP_SINK, "bad sink");
require(treasuryRecipient_ != address(0), "treasury=0");
require(scadaCreatorRecipient_ != address(0), "scada creator=0");
PERMANENT_LP_SINK = permanentLpSink_;
TREASURY_RECIPIENT = treasuryRecipient_;
SCADA_CREATOR_RECIPIENT = scadaCreatorRecipient_;
emit WithdrawFeeRecipientsConfigured(permanentLpSink_, treasuryRecipient_, scadaCreatorRecipient_);
}
function createVault(address owner, address pool, address farm) external returns (address vault) {
vault = computeVault(owner, pool, farm);
if (vault.code.length != 0) return vault;
bytes32 salt = _salt(owner, pool, farm);
vault = address(new SynergyPositionVault{salt: salt}(
owner,
pool,
farm,
PERMANENT_LP_SINK,
TREASURY_RECIPIENT,
SCADA_CREATOR_RECIPIENT
));
emit VaultCreated(owner, pool, farm, vault);
}
function computeVault(address owner, address pool, address farm) public view returns (address) {
bytes32 salt = vaultSalt(owner, pool, farm);
bytes32 initCodeHash = vaultInitCodeHash(owner, pool, farm);
return address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
initCodeHash
)))));
}
function vaultSalt(address owner, address pool, address farm) public pure returns (bytes32) {
return _salt(owner, pool, farm);
}
function vaultInitCodeHash(address owner, address pool, address farm) public view returns (bytes32) {
return keccak256(abi.encodePacked(
type(SynergyPositionVault).creationCode,
abi.encode(owner, pool, farm, PERMANENT_LP_SINK, TREASURY_RECIPIENT, SCADA_CREATOR_RECIPIENT)
));
}
function _salt(address owner, address pool, address farm) private pure returns (bytes32) {
return keccak256(abi.encode(owner, pool, farm));
}
}