This is a minimal example of a financial template that depends on price requests from the DVM. This contract should be thought of as a "Deposit Box" into which the user deposits some ERC20 collateral. The main feature of this box is that the user can withdraw their ERC20 corresponding to a desired USD amount. When the user wants to make a withdrawal, a price request is enqueued with the UMA DVM. For simplicty, the user is constrained to have one outstanding withdrawal request at any given time. Regular fees are charged on the collateral in the deposit box throughout the lifetime of the deposit box, and final fees are charged on each price request.
This example is intended to accompany a technical tutorial for how to integrate the DVM into a project. The main feature this demo serves to showcase is how to build a financial product on-chain that "pulls" price requests from the DVM on-demand, which is an implementation of the "priceless" oracle framework.
The typical user flow would be:
- User sets up a deposit box for the (wETH - USD) price-identifier. The "collateral currency" in this deposit box is therefore wETH. The user can subsequently make withdrawal requests for USD-denominated amounts of wETH.
- User deposits 10 wETH into their deposit box.
- User later requests to withdraw $100 USD of wETH.
- DepositBox asks DVM for latest wETH/USD exchange rate.
- DVM resolves the exchange rate at: 1 wETH is worth 200 USD.
- DepositBox transfers 0.5 wETH to user.
constructor(address _collateralAddress, address _finderAddress, bytes32 _priceIdentifier, address _timerAddress) (public)
Construct the DepositBox.
- _collateralAddress: ERC20 token to be deposited.
- _finderAddress: UMA protocol Finder used to discover other protocol contracts.
- _priceIdentifier: registered in the DVM, used to price the ERC20 deposited. The price identifier consists of a "base" asset and a "quote" asset. The "base" asset corresponds to the collateral ERC20 currency deposited into this account, and it is denominated in the "quote" asset on withdrawals. An example price identifier would be "ETH-USD" which will resolve and return the USD price of ETH.
- _timerAddress: Contract that stores the current time in a testing environment. Must be set to 0x0 for production environments that use live time.
This should be called after construction of the DepositBox and handles registration with the Registry, which is required to make price requests in production environments.
This contract must hold the
ContractCreator role with the Registry in order to register itself as a financial-template with the DVM.
_registerContract cannot be called from the constructor because this contract first needs to be given the
in order to register with the
Registry. But, its address is not known until after deployment.
deposit(struct FixedPoint.Unsigned collateralAmount) (public)
collateralCurrency into caller's deposit box.
This contract must be approved to spend at least
- collateralAmount: total amount of collateral tokens to be sent to the sponsor's position.
requestWithdrawal(struct FixedPoint.Unsigned denominatedCollateralAmount) (public)
Starts a withdrawal request that allows the sponsor to withdraw
from their position denominated in the quote asset of the price identifier, following a DVM price resolution.
The request will be pending for the duration of the DVM vote and can be cancelled at any time. Only one withdrawal request can exist for the user.
- denominatedCollateralAmount: the quote-asset denominated amount of collateral requested to withdraw.
executeWithdrawal() → struct FixedPoint.Unsigned amountWithdrawn (external)
After a passed withdrawal request (i.e., by a call to
requestWithdrawal and subsequent DVM price resolution),
depositBoxData.withdrawalRequestAmount of collateral currency denominated in the quote asset.
Might not withdraw the full requested amount in order to account for precision loss or if the full requested amount exceeds the collateral in the position (due to paying fees).
Cancels a pending withdrawal request.
remargin are required to be implemented by all financial contracts and exposed to the DVM, but
because this is a minimal demo they will simply exit silently.
Same comment as
emergencyShutdown. For the sake of simplicity, this will simply exit silently.
getCollateral(address user) → struct FixedPoint.Unsigned (external)
Accessor method for a user's collateral.
This is necessary because the struct returned by the depositBoxes() method shows rawCollateral, which isn't a user-readable value.
- user: address whose collateral amount is retrieved.
totalDepositBoxCollateral() → struct FixedPoint.Unsigned (external)
Accessor method for the total collateral stored within the entire contract.
_requestOraclePrice(uint256 requestedTime) (internal)
_incrementCollateralBalances(struct DepositBox.DepositBoxData depositBoxData, struct FixedPoint.Unsigned collateralAmount) → struct FixedPoint.Unsigned (internal)
_decrementCollateralBalances(struct DepositBox.DepositBoxData depositBoxData, struct FixedPoint.Unsigned collateralAmount) → struct FixedPoint.Unsigned (internal)
_resetWithdrawalRequest(struct DepositBox.DepositBoxData depositBoxData) (internal)
_depositBoxHasNoPendingWithdrawal(address user) (internal)
_getIdentifierWhitelist() → contract IdentifierWhitelistInterface (internal)
_getOracle() → contract OracleInterface (internal)
_getOraclePrice(uint256 requestedTime) → struct FixedPoint.Unsigned (internal)
_pfc() → struct FixedPoint.Unsigned (internal)
_requireWhitelistedCollateral(address collateralAddress) (internal)
_registerContract(address parties, address contractToRegister) (internal)
payRegularFees() → struct FixedPoint.Unsigned (public)
Pays UMA DVM regular fees (as a % of the collateral pool) to the Store contract.
These must be paid periodically for the life of the contract. If the contract has not paid its regular fee in a week or more then a late penalty is applied which is sent to the caller. If the amount of fees owed are greater than the pfc, then this will pay as much as possible from the available collateral. An event is only fired if the fees charged are greater than 0.
getOutstandingRegularFees(uint256 time) → struct FixedPoint.Unsigned regularFee, struct FixedPoint.Unsigned latePenalty, struct FixedPoint.Unsigned totalPaid (public)
Fetch any regular fees that the contract has pending but has not yet paid. If the fees to be paid are more than the total collateral within the contract then the totalPaid returned is full contract collateral amount.
This returns 0 and exit early if there is no pfc, fees were already paid during the current block, or the fee rate is 0.
pfc() → struct FixedPoint.Unsigned (external)
Gets the current profit from corruption for this contract in terms of the collateral currency.
This is equivalent to the collateral pool available from which to pay fees. Therefore, derived contracts are expected to implement this so that pay-fee methods can correctly compute the owed fees as a % of PfC.
Removes excess collateral balance not counted in the PfC by distributing it out pro-rata to all sponsors.
cumulativeFeeMultiplier by the ratio of non-PfC-collateral :: PfC-collateral effectively
pays all sponsors a pro-rata portion of the excess collateral.
This will revert if PfC is 0 and this contract's collateral balance > 0.
_payFinalFees(address payer, struct FixedPoint.Unsigned amount) (internal)
_getStore() → contract StoreInterface (internal)
_computeFinalFees() → struct FixedPoint.Unsigned finalFees (internal)
_getFeeAdjustedCollateral(struct FixedPoint.Unsigned rawCollateral) → struct FixedPoint.Unsigned collateral (internal)
_getPendingRegularFeeAdjustedCollateral(struct FixedPoint.Unsigned rawCollateral) → struct FixedPoint.Unsigned (internal)
_convertToRawCollateral(struct FixedPoint.Unsigned collateral) → struct FixedPoint.Unsigned rawCollateral (internal)
_removeCollateral(struct FixedPoint.Unsigned rawCollateral, struct FixedPoint.Unsigned collateralToRemove) → struct FixedPoint.Unsigned removedCollateral (internal)
_addCollateral(struct FixedPoint.Unsigned rawCollateral, struct FixedPoint.Unsigned collateralToAdd) → struct FixedPoint.Unsigned addedCollateral (internal)
_adjustCumulativeFeeMultiplier(struct FixedPoint.Unsigned amount, struct FixedPoint.Unsigned currentPfc) (internal)
setCurrentTime(uint256 time) (external)
Sets the current time.
Will revert if not running in test mode.
- time: timestamp to set current Testable time to.
getCurrentTime() → uint256 (public)
Gets the current time. Will return the last time set in
setCurrentTime if running in test mode.
Otherwise, it will return the block timestamp.
Deposit(address user, uint256 collateralAmount)
RequestWithdrawal(address user, uint256 collateralAmount, uint256 requestPassTimestamp)
RequestWithdrawalExecuted(address user, uint256 collateralAmount, uint256 exchangeRate, uint256 requestPassTimestamp)
RequestWithdrawalCanceled(address user, uint256 collateralAmount, uint256 requestPassTimestamp)
RegularFeesPaid(uint256 regularFee, uint256 lateFee)
Prevents a contract from calling itself, directly or indirectly.
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
function that does the actual state modification.
Designed to prevent a view-only method from being re-entered during a call to a
nonReentrant() state-changing method.
Reverts if not running in test mode.