Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// File: @openzeppelin/contracts/utils/Context.sol
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: contracts/DIAParallelOracle.sol
pragma solidity 0.8.29;
//import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IERC20Metadata {
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
interface IRedeemer {
function quoteRedemptionCurve(uint256 amount)
external
view
returns (address[] memory tokens, uint256[] memory amounts);
}
interface IGetters {
function getOracleValues(address collateral)
external
view
returns (uint256 mint, uint256 burn, uint256 ratio, uint256 minRatio, uint256 redemption);
function getTotalIssued()
external
view
returns (uint256 stablecoinsIssued);
}
interface IERC4626 {
function convertToAssets(uint256 shares) external view returns (uint256 assets);
}
contract DIAParallelOracle is Ownable(msg.sender) {
address public getterAddress;
address public redeemerAddress;
address public susdpVaultAddress;
uint256 public outputDecimals;
uint256 public constant QUERY_DECIMALS = 18;
string public USDP_QUERY_STRING;
mapping (string => uint256) public values;
event OracleUpdate(string key, uint128 value, uint128 timestamp);
constructor(address _getterAddress, address _redeemerAddress, address _susdpVaultAddress, uint256 _outputDecimals) {
require(_outputDecimals <= QUERY_DECIMALS, "Output decimals must be less or equal QUERY_DECIMALS.");
getterAddress = _getterAddress;
redeemerAddress = _redeemerAddress;
susdpVaultAddress = _susdpVaultAddress;
outputDecimals = _outputDecimals;
USDP_QUERY_STRING = "USDp/USD";
}
function setGetterAddress(address _newGetterAddress) onlyOwner external {
getterAddress = _newGetterAddress;
}
function setRedeemerAddress(address _newRedeemerAddress) onlyOwner external {
redeemerAddress = _newRedeemerAddress;
}
function setSusdpVaultAddress(address _newSusdpVaultAddress) onlyOwner external {
susdpVaultAddress = _newSusdpVaultAddress;
}
function setOutputDecimals(uint256 _newDecimals) onlyOwner external {
require(outputDecimals <= QUERY_DECIMALS, "Output decimals must be less or equal QUERY_DECIMALS.");
outputDecimals = _newDecimals;
}
function setUsdpQueryString(string memory newUsdpQueryString) onlyOwner external {
USDP_QUERY_STRING = newUsdpQueryString;
}
function getChainSpecificUsdpPrice() external view returns (uint256) {
IRedeemer redeemerInstance = IRedeemer(redeemerAddress);
IGetters getterInstance = IGetters(getterAddress);
(address[] memory collateralTokens, uint256[] memory redemptionValues) =
redeemerInstance.quoteRedemptionCurve(10 ** QUERY_DECIMALS);
uint256 usdpPrice = 0;
for (uint256 i = 0; i < collateralTokens.length; ++i) {
address currToken = collateralTokens[i];
uint256 currRedemptionValue = redemptionValues[i];
uint8 currTokenDecimals = IERC20Metadata(currToken).decimals();
if (currTokenDecimals < QUERY_DECIMALS) {
uint256 currDecimalDelta = QUERY_DECIMALS - currTokenDecimals;
currRedemptionValue = currRedemptionValue * (10 ** currDecimalDelta);
} else if (currTokenDecimals > QUERY_DECIMALS) {
uint256 currDecimalDelta = currTokenDecimals - QUERY_DECIMALS;
currRedemptionValue = currRedemptionValue / (10 ** currDecimalDelta);
}
(, , , , uint256 currOracleRedemptionPrice) = getterInstance.getOracleValues(currToken);
uint256 redemptionValueUsd = currOracleRedemptionPrice * currRedemptionValue;
usdpPrice += redemptionValueUsd;
}
uint256 decimalDelta = (QUERY_DECIMALS + 18) - outputDecimals;
return usdpPrice / (10 ** decimalDelta);
}
function getChainSpecificUsdpIssued() external view returns (uint256) {
IGetters getterInstance = IGetters(getterAddress);
return getterInstance.getTotalIssued();
}
function getSusdpPrice() public view returns (uint256) {
IERC4626 susdpVaultInstance = IERC4626(susdpVaultAddress);
(uint128 usdpPrice,) = getValue(USDP_QUERY_STRING);
uint256 susdpRate = susdpVaultInstance.convertToAssets(10 ** QUERY_DECIMALS);
return (susdpRate * usdpPrice) / (10 ** QUERY_DECIMALS);
}
function setValue(string memory key, uint128 value, uint128 timestamp) onlyOwner external {
uint256 cValue = (((uint256)(value)) << 128) + timestamp;
values[key] = cValue;
emit OracleUpdate(key, value, timestamp);
}
function setMultipleValues(string[] memory keys, uint256[] memory compressedValues) onlyOwner external {
require(keys.length == compressedValues.length);
for (uint128 i = 0; i < keys.length; i++) {
string memory currentKey = keys[i];
uint256 currentCvalue = compressedValues[i];
uint128 value = (uint128)(currentCvalue >> 128);
uint128 timestamp = (uint128)(currentCvalue % 2**128);
values[currentKey] = currentCvalue;
emit OracleUpdate(currentKey, value, timestamp);
}
}
function getValue(string memory key) public view returns (uint128, uint128) {
if (compareStrings(key, "sUSDp/USD")) {
return (uint128(getSusdpPrice()), uint128(block.timestamp));
} else {
uint256 cValue = values[key];
uint128 timestamp = (uint128)(cValue % 2**128);
uint128 value = (uint128)(cValue >> 128);
return (value, timestamp);
}
}
function compareStrings(string memory _a, string memory _b) internal pure returns(bool) {
return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
}
}
Submitted on: 2025-10-12 21:34:36
Comments
Log in to comment.
No comments yet.