From 8369e1c87e0446aecc8601f56b1a5d6374f2a1eb Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Thu, 2 Oct 2025 12:42:25 +0200 Subject: [PATCH 1/9] chore: boilerplate copypasta --- contracts/src/xYield/xYieldToken.sol | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 contracts/src/xYield/xYieldToken.sol diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol new file mode 100644 index 00000000..27666f33 --- /dev/null +++ b/contracts/src/xYield/xYieldToken.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract xYieldToken is ERC20 { + address public immutable minter; + + constructor(address _minter, string memory name, string memory symbol) ERC20(name, symbol) { + require(_minter != address(0), "Minter address cannot be zero"); + minter = _minter; + } + + modifier onlyMinter() { + require(msg.sender == minter, "Caller is not the minter"); + _; + } + + function mint(address to, uint256 amount) external onlyMinter { + _mint(to, amount); + } + + /// @dev The standard burn function is already public and allows any holder to burn their own tokens, + /// emitting a Transfer event to address(0) as the burn signal. +} \ No newline at end of file From a4e3a6432d493a284b7969085dd46c7212d7e598 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:31:43 +0200 Subject: [PATCH 2/9] feat: allow minter to be changed --- contracts/src/xYield/xYieldToken.sol | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index 27666f33..f72f5521 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -4,7 +4,10 @@ pragma solidity ^0.8.18; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract xYieldToken is ERC20 { - address public immutable minter; + address public minter; + + // Event to log minter address changes + event MinterChanged(address indexed oldMinter, address indexed newMinter); constructor(address _minter, string memory name, string memory symbol) ERC20(name, symbol) { require(_minter != address(0), "Minter address cannot be zero"); @@ -16,10 +19,23 @@ contract xYieldToken is ERC20 { _; } + /// @notice Updates the minter address + /// @param newMinter The new minter address + function updateMinter(address newMinter) external onlyMinter { + require(newMinter != address(0), "New minter address cannot be zero"); + require(newMinter != minter, "New minter address must be different"); + address oldMinter = minter; + minter = newMinter; + emit MinterChanged(oldMinter, newMinter); + } + + /// @notice Mints new tokens to the specified address + /// @param to The address to receive the minted tokens + /// @param amount The amount of tokens to mint function mint(address to, uint256 amount) external onlyMinter { _mint(to, amount); } - /// @dev The standard burn function is already public and allows any holder to burn their own tokens, - /// emitting a Transfer event to address(0) as the burn signal. -} \ No newline at end of file + /// @dev The standard burn function is already public and allows any address to burn their own tokens, + /// emitting a Transfer event to address(0) as the burn signal. Thus, no custom burn event is defined. +} From 0c1fcfea476e92156810bcbbb308b62fffdf6567 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:32:01 +0200 Subject: [PATCH 3/9] fix: redundant comment --- contracts/src/xYield/xYieldToken.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index f72f5521..06061fca 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -6,7 +6,6 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract xYieldToken is ERC20 { address public minter; - // Event to log minter address changes event MinterChanged(address indexed oldMinter, address indexed newMinter); constructor(address _minter, string memory name, string memory symbol) ERC20(name, symbol) { From 1d9730979ad5ecdab78168a1f88c6da7e6113ac8 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:33:01 +0200 Subject: [PATCH 4/9] fix: forge fmt --- contracts/src/xYield/IxYieldVault.sol | 17 +--- contracts/src/xYield/xYieldVault.sol | 109 +++++++------------------- 2 files changed, 33 insertions(+), 93 deletions(-) diff --git a/contracts/src/xYield/IxYieldVault.sol b/contracts/src/xYield/IxYieldVault.sol index 4bc503d1..b1749f1c 100644 --- a/contracts/src/xYield/IxYieldVault.sol +++ b/contracts/src/xYield/IxYieldVault.sol @@ -81,8 +81,7 @@ interface IxYieldVault { uint32 _quoteTimestamp, uint32 _fillDeadline, uint32 _exclusivityParameter - ) - external; + ) external; function finalizeRebalance() external; function guardian() external view returns (address); function handleV3AcrossMessage(address tokenSent, uint256 amount, address relayer, bytes memory message) external; @@ -108,8 +107,7 @@ interface IxYieldVault { uint256 _amountIn, uint256 _amountOut, uint32 _acrossApiQuoteTimestamp - ) - external; + ) external; function rebalanceFillTTL() external view returns (uint256); function redeem(uint256 _shares, address _receiver, address _owner) external returns (uint256); function renounceOwnership() external; @@ -117,12 +115,7 @@ interface IxYieldVault { function setActiveChain(bool _isActive) external; function setGuardian(address _newGuardian) external; function setRebalanceFillTTL(uint256 newTTL) external; - function setSiblingVault( - uint64 _chainId, - address _vault, - address _underlyingErc20, - address _multicallHandler - ) + function setSiblingVault(uint64 _chainId, address _vault, address _underlyingErc20, address _multicallHandler) external; function setYieldProtocol(address _newYieldProtocol) external; function siblingVaults(uint64 chainId) @@ -148,8 +141,6 @@ interface IxYieldVault { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) - external - returns (uint256); + ) external returns (uint256); function yieldProtocol() external view returns (address); } diff --git a/contracts/src/xYield/xYieldVault.sol b/contracts/src/xYield/xYieldVault.sol index cc09eb2f..3712021a 100644 --- a/contracts/src/xYield/xYieldVault.sol +++ b/contracts/src/xYield/xYieldVault.sol @@ -1,20 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -import { V3SpokePoolInterface } from "@across-protocol/contracts/contracts/interfaces/V3SpokePoolInterface.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { ERC4626 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; -import { OnchainCrossChainOrder } from "../interfaces/IERC7683.sol"; -import { OrderData, OrderEncoder } from "../libraries/7683/OrderEncoder.sol"; -import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; -import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; -import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { T1ERC7683 } from "../7683/T1ERC7683.sol"; -import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; +import {V3SpokePoolInterface} from "@across-protocol/contracts/contracts/interfaces/V3SpokePoolInterface.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {OnchainCrossChainOrder} from "../interfaces/IERC7683.sol"; +import {OrderData, OrderEncoder} from "../libraries/7683/OrderEncoder.sol"; +import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {T1ERC7683} from "../7683/T1ERC7683.sol"; +import {TypeCasts} from "@hyperlane-xyz/libs/TypeCasts.sol"; contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { using SafeERC20 for IERC20; @@ -113,10 +113,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { string memory _symbol, address _yieldProtocol, address _acrossSpokePool - ) - ERC4626(_underlying) - ERC20(_name, _symbol) - { + ) ERC4626(_underlying) ERC20(_name, _symbol) { guardian = _guardian; yieldProtocol = IERC4626(_yieldProtocol); acrossSpokePool = V3SpokePoolInterface(_acrossSpokePool); @@ -143,11 +140,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { } // called on behalf of a user who has deposited from a remote chain - function depositFrom( - uint256 _amount, - address _receiver, - uint64 _chainId - ) + function depositFrom(uint256 _amount, address _receiver, uint64 _chainId) external whenNotPaused returns (uint256 shares) @@ -169,11 +162,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 _quoteTimestamp, uint32 _fillDeadline, uint32 _exclusivityParameter - ) - external - whenNotPaused - nonReentrant - { + ) external whenNotPaused nonReentrant { if (_amount == 0) revert ZeroAmount(); if (isActiveChain) revert OnlyRemote(); if (siblingVaults[_targetChainId].vault == address(0)) revert InvalidChain(); @@ -190,10 +179,10 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { abi.encodeCall(this.depositFrom, (_outputAmount, _receiver, uint64(block.chainid))); Call[] memory calls = new Call[](2); - calls[0] = Call({ target: siblingVaults[_targetChainId].underlyingErc20, callData: approveCallData, value: 0 }); - calls[1] = Call({ target: siblingVaults[_targetChainId].vault, callData: depositCallData, value: 0 }); + calls[0] = Call({target: siblingVaults[_targetChainId].underlyingErc20, callData: approveCallData, value: 0}); + calls[1] = Call({target: siblingVaults[_targetChainId].vault, callData: depositCallData, value: 0}); - Instructions memory instructions = Instructions({ calls: calls, fallbackRecipient: _receiver }); + Instructions memory instructions = Instructions({calls: calls, fallbackRecipient: _receiver}); bytes memory message = abi.encode(instructions); @@ -225,11 +214,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { return assets; } - function withdraw( - uint256 _amount, - address _receiver, - address _owner - ) + function withdraw(uint256 _amount, address _receiver, address _owner) public virtual override @@ -244,11 +229,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { return shares; } - function redeem( - uint256 _shares, - address _receiver, - address _owner - ) + function redeem(uint256 _shares, address _receiver, address _owner) public virtual override @@ -272,12 +253,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) - external - nonReentrant - onlyGuardian - returns (uint256 assets) - { + ) external nonReentrant onlyGuardian returns (uint256 assets) { assets = previewRedeem(shares); _withdrawFrom( owner, @@ -301,12 +277,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) - external - nonReentrant - onlyGuardian - returns (uint256 shares) - { + ) external nonReentrant onlyGuardian returns (uint256 shares) { shares = previewWithdraw(assets); _withdrawFrom( owner, @@ -331,9 +302,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) - internal - { + ) internal { virtualTotalSupply -= shares; yieldProtocol.withdraw(assets, address(this), address(this)); @@ -399,13 +368,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { emit XYieldDeposit(_caller, _receiver, _amount, _shares, uint64(block.chainid), false); } - function _depositFrom( - address _caller, - address _receiver, - uint256 _amount, - uint256 _shares, - uint64 _chainId - ) + function _depositFrom(address _caller, address _receiver, uint256 _amount, uint256 _shares, uint64 _chainId) internal { virtualTotalSupply += _shares; @@ -415,13 +378,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { emit XYieldDeposit(_caller, _receiver, _amount, _shares, _chainId, true); } - function _withdraw( - address _caller, - address _receiver, - address _owner, - uint256 _amount, - uint256 _shares - ) + function _withdraw(address _caller, address _receiver, address _owner, uint256 _amount, uint256 _shares) internal virtual override @@ -458,12 +415,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { _setActiveChain(_isActive); } - function setSiblingVault( - uint64 _chainId, - address _vault, - address _underlyingErc20, - address _multicallHandler - ) + function setSiblingVault(uint64 _chainId, address _vault, address _underlyingErc20, address _multicallHandler) external onlyOwner { @@ -503,10 +455,7 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint256 _amountIn, uint256 _amountOut, uint32 _acrossApiQuoteTimestamp - ) - external - onlyGuardian - { + ) external onlyGuardian { if (_amountIn == 0) revert ZeroAmount(); if (!isActiveChain) revert WithdrawOnInactiveChain(); From c3c74a3b97145deb5a6f8fae2027a8da79753e5c Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:38:18 +0200 Subject: [PATCH 5/9] fix: cleanup linting --- contracts/src/xYield/xYieldToken.sol | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index 06061fca..c2ba3631 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -1,28 +1,32 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +pragma solidity ^0.8.30; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -contract xYieldToken is ERC20 { +contract XyieldToken is ERC20 { address public minter; event MinterChanged(address indexed oldMinter, address indexed newMinter); + error ZeroAddress(); + error InvalidMinter(); + error NotAuthorized(); + constructor(address _minter, string memory name, string memory symbol) ERC20(name, symbol) { - require(_minter != address(0), "Minter address cannot be zero"); + if (_minter == address(0)) revert ZeroAddress(); minter = _minter; } modifier onlyMinter() { - require(msg.sender == minter, "Caller is not the minter"); + if (msg.sender != minter) revert NotAuthorized(); _; } /// @notice Updates the minter address /// @param newMinter The new minter address function updateMinter(address newMinter) external onlyMinter { - require(newMinter != address(0), "New minter address cannot be zero"); - require(newMinter != minter, "New minter address must be different"); + if (newMinter == address(0)) revert ZeroAddress(); + if (newMinter == minter) revert InvalidMinter(); address oldMinter = minter; minter = newMinter; emit MinterChanged(oldMinter, newMinter); From b487c805013452962bc8a70fd9460f36927980bc Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:40:09 +0200 Subject: [PATCH 6/9] fix: cleanup comments --- contracts/src/xYield/xYieldToken.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index c2ba3631..eabb6689 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -1,15 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract XyieldToken is ERC20 { address public minter; event MinterChanged(address indexed oldMinter, address indexed newMinter); + /// @dev Thrown if the minter would be set to the zero address error ZeroAddress(); + /// @dev Thrown if the minter cannot be set due to an invalid input error InvalidMinter(); + /// @dev Thrown if the caller is not authorized to change the minter error NotAuthorized(); constructor(address _minter, string memory name, string memory symbol) ERC20(name, symbol) { From 6eed8460e3b2493e02cc7f2b7d45362374930b17 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:44:30 +0200 Subject: [PATCH 7/9] fix: revert forge fmt for files not touched by this branch --- contracts/src/xYield/IxYieldVault.sol | 17 +++- contracts/src/xYield/xYieldVault.sol | 109 +++++++++++++++++++------- 2 files changed, 93 insertions(+), 33 deletions(-) diff --git a/contracts/src/xYield/IxYieldVault.sol b/contracts/src/xYield/IxYieldVault.sol index b1749f1c..4bc503d1 100644 --- a/contracts/src/xYield/IxYieldVault.sol +++ b/contracts/src/xYield/IxYieldVault.sol @@ -81,7 +81,8 @@ interface IxYieldVault { uint32 _quoteTimestamp, uint32 _fillDeadline, uint32 _exclusivityParameter - ) external; + ) + external; function finalizeRebalance() external; function guardian() external view returns (address); function handleV3AcrossMessage(address tokenSent, uint256 amount, address relayer, bytes memory message) external; @@ -107,7 +108,8 @@ interface IxYieldVault { uint256 _amountIn, uint256 _amountOut, uint32 _acrossApiQuoteTimestamp - ) external; + ) + external; function rebalanceFillTTL() external view returns (uint256); function redeem(uint256 _shares, address _receiver, address _owner) external returns (uint256); function renounceOwnership() external; @@ -115,7 +117,12 @@ interface IxYieldVault { function setActiveChain(bool _isActive) external; function setGuardian(address _newGuardian) external; function setRebalanceFillTTL(uint256 newTTL) external; - function setSiblingVault(uint64 _chainId, address _vault, address _underlyingErc20, address _multicallHandler) + function setSiblingVault( + uint64 _chainId, + address _vault, + address _underlyingErc20, + address _multicallHandler + ) external; function setYieldProtocol(address _newYieldProtocol) external; function siblingVaults(uint64 chainId) @@ -141,6 +148,8 @@ interface IxYieldVault { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) external returns (uint256); + ) + external + returns (uint256); function yieldProtocol() external view returns (address); } diff --git a/contracts/src/xYield/xYieldVault.sol b/contracts/src/xYield/xYieldVault.sol index 3712021a..cc09eb2f 100644 --- a/contracts/src/xYield/xYieldVault.sol +++ b/contracts/src/xYield/xYieldVault.sol @@ -1,20 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -import {V3SpokePoolInterface} from "@across-protocol/contracts/contracts/interfaces/V3SpokePoolInterface.sol"; -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -import {OnchainCrossChainOrder} from "../interfaces/IERC7683.sol"; -import {OrderData, OrderEncoder} from "../libraries/7683/OrderEncoder.sol"; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; -import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; -import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {T1ERC7683} from "../7683/T1ERC7683.sol"; -import {TypeCasts} from "@hyperlane-xyz/libs/TypeCasts.sol"; +import { V3SpokePoolInterface } from "@across-protocol/contracts/contracts/interfaces/V3SpokePoolInterface.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC4626 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { OnchainCrossChainOrder } from "../interfaces/IERC7683.sol"; +import { OrderData, OrderEncoder } from "../libraries/7683/OrderEncoder.sol"; +import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; +import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { T1ERC7683 } from "../7683/T1ERC7683.sol"; +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { using SafeERC20 for IERC20; @@ -113,7 +113,10 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { string memory _symbol, address _yieldProtocol, address _acrossSpokePool - ) ERC4626(_underlying) ERC20(_name, _symbol) { + ) + ERC4626(_underlying) + ERC20(_name, _symbol) + { guardian = _guardian; yieldProtocol = IERC4626(_yieldProtocol); acrossSpokePool = V3SpokePoolInterface(_acrossSpokePool); @@ -140,7 +143,11 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { } // called on behalf of a user who has deposited from a remote chain - function depositFrom(uint256 _amount, address _receiver, uint64 _chainId) + function depositFrom( + uint256 _amount, + address _receiver, + uint64 _chainId + ) external whenNotPaused returns (uint256 shares) @@ -162,7 +169,11 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 _quoteTimestamp, uint32 _fillDeadline, uint32 _exclusivityParameter - ) external whenNotPaused nonReentrant { + ) + external + whenNotPaused + nonReentrant + { if (_amount == 0) revert ZeroAmount(); if (isActiveChain) revert OnlyRemote(); if (siblingVaults[_targetChainId].vault == address(0)) revert InvalidChain(); @@ -179,10 +190,10 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { abi.encodeCall(this.depositFrom, (_outputAmount, _receiver, uint64(block.chainid))); Call[] memory calls = new Call[](2); - calls[0] = Call({target: siblingVaults[_targetChainId].underlyingErc20, callData: approveCallData, value: 0}); - calls[1] = Call({target: siblingVaults[_targetChainId].vault, callData: depositCallData, value: 0}); + calls[0] = Call({ target: siblingVaults[_targetChainId].underlyingErc20, callData: approveCallData, value: 0 }); + calls[1] = Call({ target: siblingVaults[_targetChainId].vault, callData: depositCallData, value: 0 }); - Instructions memory instructions = Instructions({calls: calls, fallbackRecipient: _receiver}); + Instructions memory instructions = Instructions({ calls: calls, fallbackRecipient: _receiver }); bytes memory message = abi.encode(instructions); @@ -214,7 +225,11 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { return assets; } - function withdraw(uint256 _amount, address _receiver, address _owner) + function withdraw( + uint256 _amount, + address _receiver, + address _owner + ) public virtual override @@ -229,7 +244,11 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { return shares; } - function redeem(uint256 _shares, address _receiver, address _owner) + function redeem( + uint256 _shares, + address _receiver, + address _owner + ) public virtual override @@ -253,7 +272,12 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) external nonReentrant onlyGuardian returns (uint256 assets) { + ) + external + nonReentrant + onlyGuardian + returns (uint256 assets) + { assets = previewRedeem(shares); _withdrawFrom( owner, @@ -277,7 +301,12 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) external nonReentrant onlyGuardian returns (uint256 shares) { + ) + external + nonReentrant + onlyGuardian + returns (uint256 shares) + { shares = previewWithdraw(assets); _withdrawFrom( owner, @@ -302,7 +331,9 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityParameter - ) internal { + ) + internal + { virtualTotalSupply -= shares; yieldProtocol.withdraw(assets, address(this), address(this)); @@ -368,7 +399,13 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { emit XYieldDeposit(_caller, _receiver, _amount, _shares, uint64(block.chainid), false); } - function _depositFrom(address _caller, address _receiver, uint256 _amount, uint256 _shares, uint64 _chainId) + function _depositFrom( + address _caller, + address _receiver, + uint256 _amount, + uint256 _shares, + uint64 _chainId + ) internal { virtualTotalSupply += _shares; @@ -378,7 +415,13 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { emit XYieldDeposit(_caller, _receiver, _amount, _shares, _chainId, true); } - function _withdraw(address _caller, address _receiver, address _owner, uint256 _amount, uint256 _shares) + function _withdraw( + address _caller, + address _receiver, + address _owner, + uint256 _amount, + uint256 _shares + ) internal virtual override @@ -415,7 +458,12 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { _setActiveChain(_isActive); } - function setSiblingVault(uint64 _chainId, address _vault, address _underlyingErc20, address _multicallHandler) + function setSiblingVault( + uint64 _chainId, + address _vault, + address _underlyingErc20, + address _multicallHandler + ) external onlyOwner { @@ -455,7 +503,10 @@ contract xYieldVault is ERC4626, Ownable2Step, ReentrancyGuard, Pausable { uint256 _amountIn, uint256 _amountOut, uint32 _acrossApiQuoteTimestamp - ) external onlyGuardian { + ) + external + onlyGuardian + { if (_amountIn == 0) revert ZeroAmount(); if (!isActiveChain) revert WithdrawOnInactiveChain(); From 75182073791d89f155370f60b51a836a9899e6ca Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:49:08 +0200 Subject: [PATCH 8/9] feat: extra comments as nice to have --- contracts/src/xYield/xYieldToken.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index eabb6689..39775f6c 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -6,6 +6,9 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract XyieldToken is ERC20 { address public minter; + /// @notice Emitted when the address authorized to mint is updated. + /// @param oldMinter The formerly authrorized minter + /// @param newMinter The address now authorized to mint event MinterChanged(address indexed oldMinter, address indexed newMinter); /// @dev Thrown if the minter would be set to the zero address From 098a3689917568b674df76426e3fa1b56230e174 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Fri, 3 Oct 2025 16:55:47 +0200 Subject: [PATCH 9/9] feat: linter hates me --- contracts/src/xYield/xYieldToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/xYield/xYieldToken.sol b/contracts/src/xYield/xYieldToken.sol index 39775f6c..407bf159 100644 --- a/contracts/src/xYield/xYieldToken.sol +++ b/contracts/src/xYield/xYieldToken.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract XyieldToken is ERC20 { address public minter;