GM Index
Brief explanations of all Index functions
The core contract stores the Index's parameters, token data, fee data, and is the router for all deposits and withdrawals. It inherits from Open Zeppelin's ERC-20, Ownable, and Pausable contracts. The protocol and token mechanisms are set according to the following functions:
Constructor
At contract creation, the constructor sets the contract as an ERC20 token and transfers ownership to the msg.sender
. It also stores the deployer-provided _protocolFeeRecipient
address parameter.
Parameters:
_protocolFeeRecipient
address
The address that receives a portion of protocol revenue
Owner Functions
pause
Pauses functions with whenNotPaused
modifier in case of emergency or unforeseen events. Must be called by the current owner. The current functions that are pausable are deposit
and withdraw
. This is the standard implementation of the Open Zeppelin Pausable contract.
unpause
Resumes operation of paused functions with whenNotPaused
modifier to restore the Index to normal operation. Must be called by the current owner. The current functions that are unpausable are deposit
and withdraw
. This is the standard implementation of the Open Zeppelin Pausable contract.
setFeeBase
Sets the nominal base fee for deposits and withdrawals that happen when the particular GM token is at its target Index weighting. Must be called by the current owner. The Fee Base cannot be more than 250 basis points (2.5%). An event with the new fee is emitted.
Parameters:
_feeBase
uint256
The base fee applied to each deposit and withdrawal
setTaxBase
Sets the base tax for deposits and withdrawals that take the particular GM token away from its target Index weighting. Must be called by the current owner. The Tax Base cannot be more than 250 basis points (2.5%). An event with the new tax is emitted.
Parameters:
_taxBase
uint256
The base tax applied depending on if the deposit/withdrawal brings the token bank's amount further away from the targetBalance
than it originally was before the transfer
setMinFee
Sets the minimum fee for deposits and withdrawals. Must be called by the current owner. The Tax Base cannot be more than 100 basis points (1%). An event with the new fee is emitted.
Parameters:
_minFee
uint256
The minimum fee for deposits and withdrawals
updateFeeRecipient
Updates the address to receive a portion of protocol revenue and emits an event with the new address. Must be called by the current owner.
Parameters:
_protocolFeeRecipient
address
The address that receives a portion of protocol revenue
updateProtocolFeeRatio
Sets/updates the ratio of fees to be provided as protocol revenue and emits an event with the new ratio. Must be called by the current owner. The fee ratio must be lower than the FEE_DIVISOR
, immutably set to 100% (10,000) at contract creation.
Parameters:
_protocolFeeRatio
uint256
The ratio (percentage) of each fee that goes to the protocolFeeRecipient
as revenue
addToken
Adds an individual GMX market token to the Index, so that users are able to deposit/withdraw the token. Tokens can only be added by the current owner. After the addition and ensuing deposits, the Index will begin to incorporate the asset’s value, amount changes, and fees generated from the inflows and outflows.
Each token’s data is stored in the Vault
struct, which is accessed via the vaults
mapping. If a token has an active vault, the token cannot be added again to the Index. This is checked by requiring that the token vault’s active
boolean is not set to true.
The token is also added to the treasuryVaults
bytes32 array, which enables the retrieval by name of each individual token currently in the Index.
The token _weight
function parameter is added to the totalTokenWeights
storage variable.
Lastly, this function stores the token’s already deployed Bank contract (see the Bank Contract section for details) in the token’s Vault
data struct. The Index then approves the bank contract to spend up to the uint256
max allowed value of tokens via the deposit
and withdraw
functions.
Parameters:
name
bytes32
Name of the asset to be added
_token
IERC20
The IERC20 interface type of the token
_weight
uint256
The weight that the token will be assigned in relation to the total Index’s token weight
oracle
ITokenOracle
The ITokenOracle interface type of the token’s oracle
bank
IBank
The IBank interface type of the token’s bank
updateOracle
Updates the oracle variable for a given token inside its vaults
struct and emits an event with the token name and address of the new oracle. Oracles can only be updated by the current owner. If the token’s vault is not active, the function reverts.
Parameters:
name
bytes32
Identifier of the token
oracle
ITokenOracle
The ITokenOracle interface type of the token’s oracle
setTokenWeight
Sets or updates the weight of the given token and emits an event with the new weight. Weights can only be set or updated by the current owner. The function call updates the totalTokenWeights
variable with the new weight. The given token’s vault must be active.
Parameters:
name
bytes32
Identifier of the token
_weight
uint256
The weight that the token will be assigned in relation to the total Index’s token weight
removeTreasuryVault
Removes the token's position in the treasuryVaults
bytes32 array, sets the token vault’s active Boolean to false, and emits an event. Vaults can only be removed by the current owner. Being able to delete deprecated tokens is a safety measure if the list ever becomes too large.
This function call will revert if the token’s bank still has funds, if the token still has a non-zero weight in the Index, or if the token cannot be found in the treasuryVaults
array.
Parameters:
name
uint256
The name of the asset to be removed from the treasury’s vaults
recoverUnsupported
It is added in case of airdrops or tokens accidentally sent to the Index. Only the current owner can call this function. The owner inputs the IERC20-wrapped token that has been airdropped or sent into the contract. The function loops through the treasuryVaults
array, and if any position matches the input token, then the function reverts. If the entire array has been searched and no match has been found, the tokens are transferred to the _to
address that was also entered as an argument.
Parameters:
_token
IERC20
The IERC20 interface type of the given token
_amount
uint256
The amount of tokens to be removed and sent to _to
_to
address
The address that unsupported tokens will be sent to
Public Functions
deposit
Deposits an amount of eligible GM tokens to the Index, which mints a calculated amount of GMI tokens, subtracts a deposit fee, and sends the rest of the GMI to the depositor. Anyone can call this function. If the amount of deposited tokens is zero or the token is not assigned a weight in the Index, then this function will revert. This function is pausable.
In order to determine the amount of GMI to mint, the following values are calculated/retrieved: totalControlledValue
of the Index, the depositTokenValue
of the user’s deposit, the current totalSupply
of GMI tokens, the deposited token’s present _bankBalance
, and the token’s _targetBalance
.
The very first deposit mints an amount of GMI tokens equal to the deposit’s current value. After the first deposit, the mintAmount
is in proportion to the value of the GM tokens deposited versus the total value of the Index.
The fee percentage is calculated by using the FeeUtils.sol library (see Fees section for further info), which compares the token’s before and after bank balances to the targetBalance
.
The feeAmount
, amountOut
, and protocolFeePayment
are calculated as follows:
If the amountOut
is less than the _minAmountOut
, the function will revert.
The GM asset tokens are now finally deposited into the token bank. The protocolFeePayment
in GMI tokens is minted and sent to the protocolFeeRecipient
, and the amountOut
in GMI tokens is minted and sent to the _recipient
address (generally, this is the caller of the function). An event with the token recipient address, token’s name, and amount is emitted.
Parameters:
name
bytes32
Identifier of the token
_recipient
address
The address to send newly minted GMI tokens to
_amount
uint256
The amount of deposit tokens
_minAmountOut
uint256
The minimum amount of GMI tokens to be received
Returns:
amountOut
uint256
The amount of GMI tokens sent to _recipient
, usually the caller
withdraw
Withdraws an amount of GM tokens from the Index by burning GMI tokens of the user. Anyone can call this function. If the amount of deposited tokens is zero or the _recipient
address is the zero address, then this function will revert. As previously mentioned, this function is pausable.
In order to determine the amount of GM tokens that can be withdrawn, the following values are calculated/retrieved: totalControlledValue
of the Index, the current price of the token, the withdrawValue
equivalent to the value of the user’s GMI tokens, the current totalSupply
of GMI tokens, the to-be-withdrawn token’s present _bankBalance
, and the token’s _targetBalance
.
The withdrawal value is calculated by multiplying the amount of GMI tokens to be burned by the total current value of the Index, then dividing by the total GMI supply. From this, the withdrawAmount
of the token can be derived.
The fee percentage is calculated by using the FeeUtils.sol library (see Fees section for further info), which compares the token’s before and after bank balances to the targetBalance
.
The feeAmount
, amountOut
, and protocolFeePayment
are calculated as follows:
If the amountOut
is less than the _minAmountOut
, the function will revert.
The user’s _amount
of GMI tokens are then burned, and the amountOut
of GM tokens are sent to the _recipient
. If feeAmount
is non-zero, then it is transferred to the protocolFeeRecipient
from the GM token’s bank.
Parameters:
name
bytes32
Identifier of the token
_amount
uint256
The amount of deposit tokens
_recipient
address
The address to send newly minted GMI tokens to
_minAmountOut
uint256
The amount of GMI tokens sent to _recipient
, usually the caller
Returns:
amountOut
uint256
The amount of GM tokens calculated and sent to _recipient
Public View Functions
calculateFee
Calculates the fee basis points or percentage for a hypothetical transaction of a certain amount of a given token. The fee percentage is calculated by using the FeeUtils.sol library (see Fees section for further info), which compares the token’s before and after transaction bank balances to the targetBalance
.
In order to calculate the total feeAmount
, the return value of getFeeBasisPoints
needs to be multipled by a mintAmount
or withdrawAmount
, then divided by the FEE_DIVISOR
.
Parameters:
name
bytes32
Identifier of the token
_amount
uint256
The amount of the token to be transferred that the caller wants to calculate the fee for
isWithdraw
Boolean
Set to true if the caller wants to calculate the fee for a withdrawal of the input amount of specific tokens. Set to false for deposits.
getTargetAmount
Gets the current target amount of a given Index token, based on the Index’s current weighting of the token. If the total supply of GMI is zero, this function returns zero.
The weight is retrieved from the token’s vault data struct, multiplied by the total supply of GMI tokens, then divided by the total token weight of the Index.
Parameters:
name
bytes32
Identifier of the token
Returns:
unnamed
uint256
The target amount of the Index token
totalControlledValue
Loops through the treasuryVaults
bytes32 array and calls the controlledValue
helper function for each token (while passing the rounding Boolean through to the helper function) and adds the returned answer to the totalValue
variable.
Parameters:
roundUp
Boolean
This argument is passed through to the controlledValue
function
Returns:
totalValue
uint256
The total value of supported tokens that are in the Index (e.g. the total value deposited across all active token banks)
controlledValue
Calculates the value of a given Index token by multiplying the current bank Balance by the current price (rounded up, converted to 18 decimals), which is retrieved from the token’s oracle in the getPrice()
helper function (passing the rounding Boolean one final time through to the oracle helper function).
Parameters:
name
bytes32
Identifier of the token
roundUp
Boolean
This argument is passed through to the getPrice()
function
Returns:
totalValue
uint256
The total value of the given GM token that are in the Index (e.g. deposited in the token's bank)
getPrice
Calls getPrice()
on the token’s stored oracle contract and retrieves the price, which is then rounded up if the roundUp
parameter is true and down if the roundUp
parameter is false.
Parameters:
name
bytes32
Identifier of the token
roundUp
Boolean
Rounds price
up if true, down if false.
Returns:
price
uint256
The rounded price from the token’s oracle
bankBalance
Returns the amount of tokens deposited in the token’s bank for a given Index asset.
Parameters:
name
bytes32
Identifier of the token
Returns:
balance
uint256
The current token balance of the given token’s bank
targetBalance
Calculates and returns the ideal balance of the given token by dividing the token’s targetValue
(with token decimals factor) by the current price returned by the token’s oracle. The targetValue
is obtained by multiplying the total Index value (after a potential deposit or withdrawal, rounded in a direction determined upstream if called by deposit()
or withdraw()
) by the ratio of the token’s weight to the totalTokenWeights
of the Index.
Parameters:
name
bytes32
Identifier of the token
withdrawal
Boolean
This argument is normally passed in from the controlledValue()
function and controls whether the tokenValue
will be subtracted from or added to the totalControlledValue
tokenValue
uint256
The value of the token to be deposited or withdrawn
roundUp
Boolean
This argument is passed through to the totalControlledValue
function
Returns:
balance
uint256
The given token’s target balance that puts it in equilibrium with its set weight in the Index
Internal Functions
_isDepositToken
Returns true if the asset passed in has a non-zero token weight, which, under normal conditions, means it is a deposit token.
Parameters:
name
bytes32
Identifier of the token
Returns:
unnamed
Boolean
Resolves to true if the token has non-zero weight, false otherwise
_depositToBank
Deposits tokens into their respective token bank contract.
Parameters:
name
bytes32
Identifier of the token
amount
uint256
The amount of tokens to deposit
Last updated