Clones a given FNFT config into a new instance of that object with the same values.
State-Changing Functions
createFNFT
function createFNFT(uint fnftId, IRevest.FNFTConfig memory fnftConfig, uint quantity, address from) external override {
mapFNFTToToken(fnftId, fnftConfig); // Costs 72K gas
depositToken(fnftId, fnftConfig.depositAmount, quantity); //Costs 100K gas
emit CreateFNFT(fnftId, from);
}
This method receives the deposited tokens from IRevest, maps the FNFT to the token amounts, initializes interest trackers, and emits a “CreateFNFT” event
fnftId - the FNFT id to map to
fnftConfig - the config to map to this id
Quantity - the number of FNFTs being created within this series
From - the address who initiated the fnft creation process (and by extension, the deposit of tokens)
Updates internal trackers to the current balance of tokens within the contract, calls update methods of IInterestHandler methods on this fnftId if they exist.
depositToken
function depositToken(
uint fnftId,
uint transferAmount,
uint quantity
) public override onlyRevestController {
//Updates in advance, to handle rebasing tokens
updateBalance(fnftId, quantity * transferAmount);
IRevest.FNFTConfig storage fnft = fnfts[fnftId];
//If there is no interest handler, use TokenTracker
fnft.depositMul = tokenTrackers[fnft.asset].lastMul;
}
Receives deposited tokens and initializes trackers, updates staking information if relevant.
withdrawToken
function withdrawToken(
uint fnftId,
uint quantity,
address user
) external override onlyRevestController {
IRevest.FNFTConfig storage fnft = fnfts[fnftId];
IRevest.TokenTracker storage tracker = tokenTrackers[fnft.asset];
address asset = fnft.asset;
// Modify balances first, then send
// Will do nothing special to interest-bearing assets
//Will take care of things for both IInterestHandler and TokenTracker
updateBalance(fnftId, 0);
uint withdrawAmount = fnft.depositAmount * quantity * tracker.lastMul / fnft.depositMul;
tracker.lastBalance -= withdrawAmount;
address pipeTo = fnft.pipeToContract;
if (pipeTo == address(0)) {
if(asset != address(0)) {
IERC20(asset).safeTransfer(user, withdrawAmount);
}
}
else {
if(fnft.depositAmount > 0 && asset != address(0)) {
//Only transfer value if there is value to transfer
IERC20(asset).safeTransfer(fnft.pipeToContract, withdrawAmount);
}
if(pipeTo.supportsInterface(OUTPUT_RECEIVER_INTERFACE_ID)) {
IOutputReceiver(pipeTo).receiveRevestOutput(fnftId, asset, payable(user), quantity);
}
}
if(getFNFTHandler().getSupply(fnftId) == 0) {
removeFNFT(fnftId);
}
emit RedeemFNFT(fnftId, _msgSender());
}
Withdraws tokens from the token vault, updates their trackers, and updates the staking system.
function splitFNFT(
uint fnftId,
uint[] memory newFNFTIds,
uint[] memory proportions,
uint quantity
) external override {
IRevest.FNFTConfig storage fnft = fnfts[fnftId];
updateBalance(fnftId, 0);
// Burn the original FNFT but keep its lock
// Create new FNFTs with the same config, only thing changed is the depositAmount
uint denominator = 1000; // proportions should add up to this
uint runningTotal = 0;
for(uint i = 0; i < proportions.length; i++) {
runningTotal += proportions[i];
uint amount = fnft.depositAmount * proportions[i] / denominator;
IRevest.FNFTConfig memory newFNFT = cloneFNFTConfig(fnft);
newFNFT.depositAmount = amount;
newFNFT.split -= 1;
mapFNFTToToken(newFNFTIds[i], newFNFT);
emit CreateFNFT(newFNFTIds[i], _msgSender());
}
require(runningTotal == denominator, 'E054'); // This is really a precondition but more efficient to place here
if(quantity == getFNFTHandler().getSupply(fnftId)) {
removeFNFT(fnftId); // We should also burn it, send ownership to 0x0000 - but should that happen here?
}
emit RedeemFNFT(fnftId, _msgSender());
}
Helper function for the split method in IRevest instances
fnftId - the original FNFT id
newFNFTIds - an array of the new IDs that need mappings
Proportions - the previously mentioned array describing split amounts
Quantity - how many FNFTs in the original series to effect
Emit RedeemFNFT event.
removeFNFT
function removeFNFT(uint fnftId) internal {
delete fnfts[fnftId];
}