Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0 ^0.8.19;
// src/core/interfaces/IAggregatorV3Interface.sol
interface IAggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
// src/core/OwnableGuarded.sol
abstract contract OwnableGuarded {
// ----------------------------------------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------------------------------------
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
// ----------------------------------------------------------------------------------------------------
// Errors
// ----------------------------------------------------------------------------------------------------
error OwnerOnly();
error OwnerAddressRequired();
error ReentrancyGuardReentrantCall();
// ----------------------------------------------------------------------------------------------------
// Storage layout
// ----------------------------------------------------------------------------------------------------
uint256 private _status;
address internal _owner;
// ----------------------------------------------------------------------------------------------------
// Events
// ----------------------------------------------------------------------------------------------------
/**
* @notice Triggers when contract ownership changes.
* @param previousOwner The previous owner of the contract.
* @param newOwner The new owner of the contract.
*/
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// ----------------------------------------------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------------------------------------------
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
_;
// By storing the original value once again, a refund is triggered (see https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (msg.sender != _owner) revert OwnerOnly();
_;
}
// ----------------------------------------------------------------------------------------------------
// Functions
// ----------------------------------------------------------------------------------------------------
/**
* @notice Transfers ownership of the contract to the account specified.
* @param newOwner The address of the new owner.
*/
function transferOwnership(address newOwner) external virtual nonReentrant onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
if (newOwner == address(0)) revert OwnerAddressRequired();
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @notice Gets the owner of the contract.
* @return address The address who owns the contract.
*/
function owner() external view virtual returns (address) {
return _owner;
}
}
// src/oracles/OracleUSDTUSDC.sol
/**
* @title USDT/USDC Oracle
* @dev Custom oracle that composes Chainlink USDT/USD and USDC/USD feeds to provide USDT/USDC rate
* @notice This contract follows the Chainlink AggregatorV3Interface
*/
contract OracleUSDTUSDC is IAggregatorV3Interface {
// Errors
error InvalidPriceData();
error StalePrice();
error InvalidOraclePrice();
error InvalidFeedAddress();
error InvalidThreshold();
uint256 public constant override version = 1;
uint8 public constant override decimals = 6;
string public constant override description = "USDT / USDC";
uint256 public stalenessThreshold;
IAggregatorV3Interface private immutable usdtUsdPriceFeed;
IAggregatorV3Interface private immutable usdcUsdPriceFeed;
// Events
event PriceUpdated(int256 price, uint256 timestamp);
/**
* @dev Constructor sets the Chainlink price feed addresses
* @param _usdtUsdPriceFeed Address of the USDT/USD Chainlink price feed
* @param _usdcUsdPriceFeed Address of the USDC/USD Chainlink price feed
* @param newStalenessThreshold The staleness threshold expressed in seconds
*/
constructor(address _usdtUsdPriceFeed, address _usdcUsdPriceFeed, uint256 newStalenessThreshold) {
if ((_usdtUsdPriceFeed == address(0)) || (_usdcUsdPriceFeed == address(0))) revert InvalidFeedAddress();
if (newStalenessThreshold < 1) revert InvalidThreshold();
stalenessThreshold = newStalenessThreshold;
usdtUsdPriceFeed = IAggregatorV3Interface(_usdtUsdPriceFeed);
usdcUsdPriceFeed = IAggregatorV3Interface(_usdcUsdPriceFeed);
}
/**
* @dev Returns the latest round data for USDT/USDC
* @return roundId The round ID (based on USDT feed)
* @return answer The USDT/USDC price with 18 decimals
* @return startedAt Timestamp when the round started (min of both feeds)
* @return updatedAt Timestamp when the round was updated (min of both feeds)
* @return answeredInRound The round ID in which the answer was computed
*/
function latestRoundData()
external
view
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
// Get data from both price feeds
(
uint80 usdtRoundId,
int256 usdtPrice,
uint256 usdtStartedAt,
uint256 usdtUpdatedAt,
uint80 usdtAnsweredInRound
) = usdtUsdPriceFeed.latestRoundData();
(
,
int256 usdcPrice,
uint256 usdcStartedAt,
uint256 usdcUpdatedAt,
) = usdcUsdPriceFeed.latestRoundData();
// Validate prices
if (usdtPrice < 1 || usdcPrice < 1) revert InvalidOraclePrice();
// Check for stale prices
if (
block.timestamp - usdtUpdatedAt > stalenessThreshold ||
block.timestamp - usdcUpdatedAt > stalenessThreshold
) {
revert StalePrice();
}
// Calculate USDT/USDC = (USDT/USD) / (USDC/USD)
int256 usdtUsdcPrice = _normalizePrice(usdtPrice, usdcPrice);
// Return data using USDT feed's metadata with calculated price
return (
usdtRoundId,
usdtUsdcPrice,
usdtStartedAt < usdcStartedAt ? usdtStartedAt : usdcStartedAt, // min startedAt
usdtUpdatedAt < usdcUpdatedAt ? usdtUpdatedAt : usdcUpdatedAt, // min updatedAt
usdtAnsweredInRound
);
}
function _normalizePrice(int256 usdtPrice, int256 usdcPrice) private view returns (int256) {
// Calculate USDT/USDC price with proper decimal handling
uint8 usdtDecimals = usdtUsdPriceFeed.decimals();
uint8 usdcDecimals = usdcUsdPriceFeed.decimals();
// Normalize prices to 18 decimals for calculation
uint256 normalizedUsdtPrice = uint256(usdtPrice) * (10 ** (18 - usdtDecimals));
uint256 normalizedUsdcPrice = uint256(usdcPrice) * (10 ** (18 - usdcDecimals));
// Calculate USDT/USDC = (USDT/USD) / (USDC/USD)
int256 usdtUsdcPrice = int256((normalizedUsdtPrice * 1e18) / normalizedUsdcPrice);
return usdtUsdcPrice / 1e12;
}
/**
* @dev Returns historical round data
* @notice This implementation returns the latest data regardless of roundId
* @param _roundId The round ID to query (ignored in this implementation)
*/
function getRoundData(uint80 _roundId)
external
view
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
// For simplicity, return latest data for any round query
return this.latestRoundData();
}
/**
* @dev Get the current USDT/USDC price
* @return price The current price with 18 decimals
*/
function getPrice() external view returns (int256 price) {
(, price, , , ) = this.latestRoundData();
}
/**
* @dev Get the addresses of the underlying price feeds
* @return usdtFeed Address of USDT/USD price feed
* @return usdcFeed Address of USDC/USD price feed
*/
function getUnderlyingFeeds() external view returns (address usdtFeed, address usdcFeed) {
return (address(usdtUsdPriceFeed), address(usdcUsdPriceFeed));
}
/**
* @dev Check if the price data is fresh
* @return true if both underlying feeds have fresh data
*/
function isFresh() external view returns (bool) {
(, , , uint256 usdtUpdatedAt, ) = usdtUsdPriceFeed.latestRoundData();
(, , , uint256 usdcUpdatedAt, ) = usdcUsdPriceFeed.latestRoundData();
return (
block.timestamp - usdtUpdatedAt <= stalenessThreshold &&
block.timestamp - usdcUpdatedAt <= stalenessThreshold
);
}
}
// src/oracles/OwnableOracle_USDTUSDC.sol
contract OwnableOracle_USDTUSDC is OwnableGuarded, OracleUSDTUSDC {
constructor(
address _usdtUsdPriceFeed,
address _usdcUsdPriceFeed,
uint256 newStalenessThreshold
) OracleUSDTUSDC(_usdtUsdPriceFeed, _usdcUsdPriceFeed, newStalenessThreshold) {
_owner = msg.sender;
}
function updateStalenessThreshold(uint256 newStalenessThreshold) external nonReentrant onlyOwner {
if (newStalenessThreshold < 1) revert InvalidThreshold();
stalenessThreshold = newStalenessThreshold;
}
}
Submitted on: 2025-09-30 10:00:03
Comments
Log in to comment.
No comments yet.