文件 1 的 16:Address.sol
pragma solidity 0.6.6;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 16:IClientRecord.sol
pragma solidity ^0.6.6;
import "./IClientRecordShema.sol";
pragma experimental ABIEncoderV2;
interface IClientRecord is IClientRecordSchema {
function doesClientRecordExist(address depositor)
external
view
returns (bool);
function getRecordIndex(address depositor) external view returns (uint256);
function createClientRecord(
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
) external;
function updateClientRecord(
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
) external;
function getLengthOfClientRecords() external view returns (uint256);
function getClientRecordByIndex(uint256 index)
external
view
returns (
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
);
function getClientRecordByAddress(address depositor)
external
view
returns (
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
);
function activateStorageOracle(address oracle) external;
function deactivateStorageOracle(address oracle) external;
function reAssignStorageOracle(address newOracle) external;
function GetRecordIndexFromDepositor(address member) external view returns(uint);
function GetRecordIdFromRecordIndexAndDepositorRecord(uint recordIndex, address depositor) external view returns(uint);
function CreateDepositRecordMapping(uint amount, uint lockPeriodInSeconds,uint depositDateInSeconds, address payable depositor, bool hasWithdrawn) external returns (uint);
function UpdateDepositRecordMapping(uint DepositRecordId, uint amount, uint lockPeriodInSeconds,uint depositDateInSeconds, address payable depositor, bool hasWithdrawn) external;
function GetRecordById(uint depositRecordId) external view returns(uint recordId, address payable depositorId, uint amount, uint depositDateInSeconds, uint lockPeriodInSeconds, bool hasWithdrawn);
function GetRecords() external view returns (FixedDepositRecord [] memory);
function CreateDepositorToDepositRecordIndexToRecordIDMapping(address payable depositor, uint recordId) external;
function CreateDepositorAddressToDepositRecordMapping (address payable depositor, uint recordId, uint amountDeposited, uint lockPeriodInSeconds, uint depositDateInSeconds, bool hasWithdrawn) external;
}
文件 3 的 16:IClientRecordShema.sol
pragma solidity 0.6.6;
interface IClientRecordSchema {
struct ClientRecord {
bool exists;
address payable _address;
uint256 underlyingTotalDeposits;
uint256 underlyingTotalWithdrawn;
uint256 derivativeBalance;
uint256 derivativeTotalDeposits;
uint256 derivativeTotalWithdrawn;
}
struct FixedDepositRecord{
uint256 recordId;
address payable depositorId;
bool hasWithdrawn;
uint256 amount;
uint256 depositDateInSeconds;
uint256 lockPeriodInSeconds;
}
struct RecordIndex {
bool exists;
uint256 index;
}
}
文件 4 的 16:IDaiLendingService.sol
pragma solidity 0.6.6;
interface IDaiLendingService {
function getPricePerFullShare() external view returns (uint256);
function save(uint256 amount) external;
function userShares() external view returns (uint256);
function userDaiBalance() external view returns (uint256);
function GetUserGrossRevenue() external view returns (uint256);
function GetNetRevenue() external view returns (uint256);
function GetUserDepositedDaiBalance() external view returns (uint256);
function Withdraw(uint256 amount) external;
function WithdrawByShares(uint amount, uint sharesAmount) external;
function GetDaiLendingAdapterAddress() external view returns (address);
function WithdrawBySharesOnly(uint sharesAmount) external;
}
文件 5 的 16:IERC20.sol
pragma solidity 0.6.6;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
文件 6 的 16:IGroupSchema.sol
pragma solidity 0.6.6;
interface IGroupSchema {
struct Group {
uint256 id;
string name;
string symbol;
bool exists;
address payable creatorAddress;
}
struct Cycle {
uint256 id;
uint256 groupId;
uint256 numberOfDepositors;
uint256 cycleStartTimeStamp;
uint256 cycleDuration;
uint256 maximumSlots;
uint256 cycleStakeAmount;
uint256 totalStakes;
uint256 stakesClaimed;
bool hasMaximumSlots;
bool exists;
CycleStatus cycleStatus;
uint256 stakesClaimedBeforeMaturity;
}
struct CycleFinancial {
bool exists;
uint256 cycleId;
uint256 underlyingTotalDeposits;
uint256 underlyingTotalWithdrawn;
uint256 underlyingBalance;
uint256 derivativeBalance;
uint256 underylingBalanceClaimedBeforeMaturity;
uint256 derivativeBalanceClaimedBeforeMaturity;
}
struct CycleMember {
uint256 cycleId;
uint256 groupId;
uint256 totalLiquidityAsPenalty;
uint256 numberOfCycleStakes;
uint256 stakesClaimed;
bool exist;
address payable _address;
bool hasWithdrawn;
}
struct Member {
bool exists;
address payable _address;
}
struct GroupMember {
bool exists;
address payable _address;
uint256 groupId;
}
struct RecordIndex {
bool exists;
uint256 index;
}
enum CycleStatus {NOT_STARTED, ONGOING, ENDED}
}
文件 7 的 16:IRewardConfig.sol
pragma solidity 0.6.6;
interface IRewardConfig{
function CalculateIndividualSavingsReward(uint totalCycleTimeInSeconds, uint amountDeposited) external view returns(uint);
function CalculateCooperativeSavingsReward(uint totalCycleTimeInSeconds, uint amountDeposited) external view returns(uint);
function CalculateEsusuReward(uint totalCycleTimeInSeconds, uint amountDeposited) external view returns(uint);
}
文件 8 的 16:ISavingsConfig.sol
pragma solidity ^0.6.6;
import './ISavingsConfigSchema.sol';
interface ISavingsConfig is ISavingsConfigSchema {
function getRuleSet(string calldata ruleKey) external returns (uint ,uint , uint , bool ,RuleDefinition );
function getRuleManager(string calldata ruleKey) external returns (address);
function changeRuleCreator(string calldata ruleKey, address newRuleManager) external;
function createRule(string calldata ruleKey, uint minimum, uint maximum, uint exact, RuleDefinition ruleDefinition) external;
function modifyRule(string calldata ruleKey, uint minimum, uint maximum, uint exact, RuleDefinition ruleDefinition ) external;
function disableRule(string calldata ruleKey) external;
function enableRule(string calldata ruleKey) external;
}
文件 9 的 16:ISavingsConfigSchema.sol
pragma solidity 0.6.6;
interface ISavingsConfigSchema {
struct RuleSet {
uint256 minimum;
uint256 maximum;
uint256 exact;
bool applies;
RuleDefinition ruleDefinition;
bool exists;
}
enum RuleDefinition {RANGE, VALUE}
}
文件 10 的 16:ITreasury.sol
pragma solidity ^0.6.6;
import "./SafeMath.sol";
import "./Ownable.sol";
import "./IERC20.sol";
interface ITreasury {
function depositToken(address token) external;
function getEtherBalance() external view returns (uint256);
function getTokenBalance(address token) external view returns (uint256);
function withdrawEthers(uint256 amount) external;
function withdrawTokens(address tokenAddress, uint256 amount) external;
}
文件 11 的 16:IXendToken.sol
pragma solidity 0.6.6;
interface IXendToken {
function mint(address payable recipient, uint256 amount) external;
}
文件 12 的 16:Ownable.sol
pragma solidity 0.6.6;
contract Ownable {
address payable public owner;
constructor() internal {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Unauthorized access to contract");
_;
}
function transferOwnership(address payable newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
文件 13 的 16:ReentrancyGuard.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 14 的 16:SafeERC20.sol
pragma solidity >=0.6.6;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 15 的 16:SafeMath.sol
pragma solidity 0.6.6;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 16 的 16:XendFinanceIndividual_Yearn_V1.sol
pragma solidity 0.6.6;
import "./IClientRecordShema.sol";
import "./IGroupSchema.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
import "./IDaiLendingService.sol";
import "./IRewardConfig.sol";
import "./IClientRecord.sol";
import "./IERC20.sol";
import "./Address.sol";
import "./ISavingsConfig.sol";
import "./ISavingsConfigSchema.sol";
import "./ITreasury.sol";
import "./IXendToken.sol";
contract XendFinanceIndividual_Yearn_V1 is
Ownable,
IClientRecordSchema,
ISavingsConfigSchema,
ReentrancyGuard
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
using Address for address payable;
event UnderlyingAssetDeposited(
address payable user,
uint256 underlyingAmount,
uint256 derivativeAmount,
uint256 balance
);
event DerivativeAssetWithdrawn(
address payable user,
uint256 underlyingAmount,
uint256 derivativeAmount,
uint256 balance
);
event XendTokenReward(
uint256 date,
address payable recipient,
uint256 amount
);
IDaiLendingService lendingService;
IERC20 daiToken;
IClientRecord clientRecordStorage;
IRewardConfig rewardConfig;
ISavingsConfig savingsConfig;
IERC20 derivativeToken;
ITreasury treasury;
IXendToken xendToken;
bool isDeprecated;
uint256 minLockPeriod = 7890000;
mapping(address => uint256) MemberToXendTokenRewardMapping;
uint256 _totalTokenReward;
address LendingAdapterAddress;
string constant XEND_FINANCE_COMMISION_DIVISOR =
"XEND_FINANCE_COMMISION_DIVISOR";
string constant XEND_FINANCE_COMMISION_DIVIDEND =
"XEND_FINANCE_COMMISION_DIVIDEND";
constructor(
address lendingServiceAddress,
address tokenAddress,
address clientRecordStorageAddress,
address savingsConfigAddress,
address derivativeTokenAddress,
address rewardConfigAddress,
address xendTokenAddress,
address treasuryAddress
) public {
lendingService = IDaiLendingService(lendingServiceAddress);
daiToken = IERC20(tokenAddress);
clientRecordStorage = IClientRecord(clientRecordStorageAddress);
savingsConfig = ISavingsConfig(savingsConfigAddress);
rewardConfig = IRewardConfig(rewardConfigAddress);
derivativeToken = IERC20(derivativeTokenAddress);
treasury = ITreasury(treasuryAddress);
xendToken = IXendToken(xendTokenAddress);
}
function setAdapterAddress() external onlyOwner {
LendingAdapterAddress = lendingService.GetDaiLendingAdapterAddress();
}
function setMinimumLockPeriod (uint256 minimumLockPeriod) external onlyNonDeprecatedCalls onlyOwner {
minLockPeriod = minimumLockPeriod;
}
function GetTotalTokenRewardDistributed() external view returns(uint256){
return _totalTokenReward;
}
function deprecateContract(address newServiceAddress)
external
onlyOwner
onlyNonDeprecatedCalls
{
isDeprecated = true;
clientRecordStorage.reAssignStorageOracle(newServiceAddress);
uint256 derivativeTokenBalance =
derivativeToken.balanceOf(address(this));
derivativeToken.safeTransfer(newServiceAddress, derivativeTokenBalance);
}
function _UpdateMemberToXendTokeRewardMapping(
address member,
uint256 rewardAmount
) internal onlyNonDeprecatedCalls {
MemberToXendTokenRewardMapping[member] = MemberToXendTokenRewardMapping[
member
]
.add(rewardAmount);
}
function GetMemberXendTokenReward(address member)
external
view
returns (uint256)
{
return MemberToXendTokenRewardMapping[member];
}
function doesClientRecordExist(address depositor)
external
view
onlyNonDeprecatedCalls
returns (bool)
{
return clientRecordStorage.doesClientRecordExist(depositor);
}
function getClientRecord(address depositor)
external
onlyNonDeprecatedCalls
returns (
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
)
{
ClientRecord memory clientRecord = _getClientRecordByAddress(depositor);
return (
clientRecord._address,
clientRecord.underlyingTotalDeposits,
clientRecord.underlyingTotalWithdrawn,
clientRecord.derivativeBalance,
clientRecord.derivativeTotalDeposits,
clientRecord.derivativeTotalWithdrawn
);
}
function getClientRecord()
external
onlyNonDeprecatedCalls
returns (
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
)
{
ClientRecord memory clientRecord =
_getClientRecordByAddress(msg.sender);
return (
clientRecord._address,
clientRecord.underlyingTotalDeposits,
clientRecord.underlyingTotalWithdrawn,
clientRecord.derivativeBalance,
clientRecord.derivativeTotalDeposits,
clientRecord.derivativeTotalWithdrawn
);
}
function getClientRecordByIndex(uint256 index)
external
onlyNonDeprecatedCalls
returns (
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
)
{
ClientRecord memory clientRecord = _getClientRecordByIndex(index);
return (
clientRecord._address,
clientRecord.underlyingTotalDeposits,
clientRecord.underlyingTotalWithdrawn,
clientRecord.derivativeBalance,
clientRecord.derivativeTotalDeposits,
clientRecord.derivativeTotalWithdrawn
);
}
function _getClientRecordByIndex(uint256 index)
internal
returns (ClientRecord memory)
{
(
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
) = clientRecordStorage.getClientRecordByIndex(index);
return
ClientRecord(
true,
_address,
underlyingTotalDeposits,
underlyingTotalWithdrawn,
derivativeBalance,
derivativeTotalDeposits,
derivativeTotalWithdrawn
);
}
function _getClientRecordByAddress(address member)
internal
view
returns (ClientRecord memory)
{
(
address payable _address,
uint256 underlyingTotalDeposits,
uint256 underlyingTotalWithdrawn,
uint256 derivativeBalance,
uint256 derivativeTotalDeposits,
uint256 derivativeTotalWithdrawn
) = clientRecordStorage.getClientRecordByAddress(member);
return
ClientRecord(
true,
_address,
underlyingTotalDeposits,
underlyingTotalWithdrawn,
derivativeBalance,
derivativeTotalDeposits,
derivativeTotalWithdrawn
);
}
function withdraw(uint256 derivativeAmount)
external
onlyNonDeprecatedCalls
{
address payable recipient = msg.sender;
_withdraw(recipient, derivativeAmount);
}
function withdrawDelegate(
address payable recipient,
uint256 derivativeAmount
) external onlyNonDeprecatedCalls onlyOwner {
_withdraw(recipient, derivativeAmount);
}
function WithdrawFromFixedDeposit(
uint256 recordId,
uint256 derivativeAmount
) external onlyNonDeprecatedCalls {
address payable recipient = msg.sender;
FixedDepositRecord memory depositRecord =
_getFixedDepositRecordById(recordId);
uint256 depositDate = depositRecord.depositDateInSeconds;
uint256 lockPeriod = depositRecord.lockPeriodInSeconds;
_validateLockTimeHasElapsedAndHasNotWithdrawn(recordId);
uint256 balanceBeforeWithdraw = lendingService.userDaiBalance();
lendingService.WithdrawBySharesOnly(derivativeAmount);
uint256 balanceAfterWithdraw = lendingService.userDaiBalance();
uint256 amountOfUnderlyingAssetWithdrawn =
balanceBeforeWithdraw.sub(balanceAfterWithdraw);
uint256 commissionFees =
_computeXendFinanceCommisions(amountOfUnderlyingAssetWithdrawn);
uint256 amountToSendToDepositor =
amountOfUnderlyingAssetWithdrawn.sub(commissionFees);
daiToken.safeTransfer(recipient, amountToSendToDepositor);
if (commissionFees > 0) {
daiToken.approve(address(treasury), commissionFees);
treasury.depositToken(address(daiToken));
}
clientRecordStorage.UpdateDepositRecordMapping(
recordId,
derivativeAmount,
lockPeriod,
depositDate,
msg.sender,
true
);
clientRecordStorage.CreateDepositorAddressToDepositRecordMapping(
recipient,
depositRecord.recordId,
depositRecord.amount,
lockPeriod,
depositDate,
true
);
_rewardUserWithTokens(lockPeriod, derivativeAmount, recipient);
emit DerivativeAssetWithdrawn(
recipient,
amountOfUnderlyingAssetWithdrawn,
derivativeAmount,
derivativeAmount
);
}
function _withdraw(address payable recipient, uint256 derivativeAmount)
internal
nonReentrant
{
_validateUserBalanceIsSufficient(recipient, derivativeAmount);
uint256 balanceBeforeWithdraw = lendingService.userDaiBalance();
lendingService.WithdrawBySharesOnly(derivativeAmount);
uint256 balanceAfterWithdraw = lendingService.userDaiBalance();
uint256 amountOfUnderlyingAssetWithdrawn =
balanceBeforeWithdraw.sub(balanceAfterWithdraw);
uint256 commissionFees =
_computeXendFinanceCommisions(amountOfUnderlyingAssetWithdrawn);
uint256 amountToSendToDepositor =
amountOfUnderlyingAssetWithdrawn.sub(commissionFees);
daiToken.safeTransfer(recipient, amountToSendToDepositor);
if (commissionFees > 0) {
daiToken.approve(address(treasury), commissionFees);
treasury.depositToken(address(daiToken));
}
ClientRecord memory clientRecord =
_updateClientRecordAfterWithdrawal(
recipient,
amountOfUnderlyingAssetWithdrawn,
derivativeAmount
);
_updateClientRecord(clientRecord);
emit DerivativeAssetWithdrawn(
recipient,
amountOfUnderlyingAssetWithdrawn,
derivativeAmount,
clientRecord.derivativeBalance
);
}
function _validateUserBalanceIsSufficient(
address payable recipient,
uint256 derivativeAmount
) internal {
ClientRecord memory clientRecord = _getClientRecordByAddress(recipient);
uint256 derivativeBalance = clientRecord.derivativeBalance;
require(
derivativeBalance >= derivativeAmount,
"Withdrawal cannot be processes, reason: Insufficient Balance"
);
}
function _computeXendFinanceCommisions(uint256 worthOfMemberDepositNow)
internal
returns (uint256)
{
uint256 dividend = _getDividend();
uint256 divisor = _getDivisor();
require(
worthOfMemberDepositNow > 0,
"member deposit really isn't worth much"
);
return worthOfMemberDepositNow.mul(dividend).div(divisor).div(100);
}
function _validateLockTimeHasElapsedAndHasNotWithdrawn(uint256 recordId)
internal
{
FixedDepositRecord memory depositRecord =
_getFixedDepositRecordById(recordId);
uint256 lockPeriod = depositRecord.lockPeriodInSeconds;
bool hasWithdrawn = depositRecord.hasWithdrawn;
require(!hasWithdrawn, "Individual has already withdrawn");
uint256 currentTimeStamp = now;
require(
currentTimeStamp >= lockPeriod,
"Funds are still locked, wait until lock period expires"
);
}
function _getDivisor() internal returns (uint256) {
(
uint256 minimumDivisor,
uint256 maximumDivisor,
uint256 exactDivisor,
bool appliesDivisor,
RuleDefinition ruleDefinitionDivisor
) = savingsConfig.getRuleSet(XEND_FINANCE_COMMISION_DIVISOR);
require(appliesDivisor, "unsupported rule defintion for rule set");
require(
ruleDefinitionDivisor == RuleDefinition.VALUE,
"unsupported rule defintion for penalty percentage rule set"
);
return exactDivisor;
}
function _getDividend() internal returns (uint256) {
(
uint256 minimumDividend,
uint256 maximumDividend,
uint256 exactDividend,
bool appliesDividend,
RuleDefinition ruleDefinitionDividend
) = savingsConfig.getRuleSet(XEND_FINANCE_COMMISION_DIVIDEND);
require(appliesDividend, "unsupported rule defintion for rule set");
require(
ruleDefinitionDividend == RuleDefinition.VALUE,
"unsupported rule defintion for penalty percentage rule set"
);
return exactDividend;
}
function deposit() external onlyNonDeprecatedCalls {
_deposit(msg.sender);
}
function depositDelegate(address payable depositorAddress)
external
onlyNonDeprecatedCalls
onlyOwner
{
_deposit(depositorAddress);
}
function _getFixedDepositRecordById(uint256 recordId)
internal
returns (FixedDepositRecord memory)
{
(
uint256 recordId,
address payable depositorId,
uint256 amount,
uint256 depositDateInSeconds,
uint256 lockPeriodInSeconds,
bool hasWithdrawn
) = clientRecordStorage.GetRecordById(recordId);
}
function FixedDeposit(
uint256 depositDateInSeconds,
uint256 lockPeriodInSeconds
) external onlyNonDeprecatedCalls {
address payable depositorAddress = msg.sender;
address recipient = address(this);
uint256 amountTransferrable =
daiToken.allowance(depositorAddress, recipient);
require(lockPeriodInSeconds >= minLockPeriod, "Minimum lock period must be 3 months");
require(
amountTransferrable > 0,
"Approve an amount > 0 for token before proceeding"
);
bool isSuccessful =
daiToken.transferFrom(
depositorAddress,
recipient,
amountTransferrable
);
require(
isSuccessful,
"Could not complete deposit process from token contract"
);
LendingAdapterAddress = lendingService.GetDaiLendingAdapterAddress();
daiToken.approve(LendingAdapterAddress, amountTransferrable);
uint256 balanceBeforeDeposit = lendingService.userShares();
lendingService.save(amountTransferrable);
uint256 balanceAfterDeposit = lendingService.userShares();
uint256 amountOfyDai = balanceAfterDeposit.sub(balanceBeforeDeposit);
uint recordId = clientRecordStorage.CreateDepositRecordMapping(
amountTransferrable,
lockPeriodInSeconds,
depositDateInSeconds,
depositorAddress,
false
);
clientRecordStorage
.CreateDepositorToDepositRecordIndexToRecordIDMapping(
depositorAddress,
recordId
);
clientRecordStorage.CreateDepositorAddressToDepositRecordMapping(
depositorAddress,
recordId,
amountTransferrable,
lockPeriodInSeconds,
depositDateInSeconds,
false
);
emit UnderlyingAssetDeposited(
depositorAddress,
amountTransferrable,
amountOfyDai,
amountTransferrable
);
}
function _deposit(address payable depositorAddress) internal {
address recipient = address(this);
uint256 amountTransferrable =
daiToken.allowance(depositorAddress, recipient);
require(
amountTransferrable > 0,
"Approve an amount > 0 for token before proceeding"
);
bool isSuccessful =
daiToken.transferFrom(
depositorAddress,
recipient,
amountTransferrable
);
require(
isSuccessful,
"Could not complete deposit process from token contract"
);
LendingAdapterAddress = lendingService.GetDaiLendingAdapterAddress();
daiToken.approve(LendingAdapterAddress, amountTransferrable);
uint256 balanceBeforeDeposit = lendingService.userShares();
lendingService.save(amountTransferrable);
uint256 balanceAfterDeposit = lendingService.userShares();
uint256 amountOfyDai = balanceAfterDeposit.sub(balanceBeforeDeposit);
ClientRecord memory clientRecord =
_updateClientRecordAfterDeposit(
depositorAddress,
amountTransferrable,
amountOfyDai
);
bool exists =
clientRecordStorage.doesClientRecordExist(depositorAddress);
if (exists) _updateClientRecord(clientRecord);
else {
clientRecordStorage.createClientRecord(
clientRecord._address,
clientRecord.underlyingTotalDeposits,
clientRecord.underlyingTotalWithdrawn,
clientRecord.derivativeBalance,
clientRecord.derivativeTotalDeposits,
clientRecord.derivativeTotalWithdrawn
);
}
emit UnderlyingAssetDeposited(
depositorAddress,
amountTransferrable,
amountOfyDai,
clientRecord.derivativeBalance
);
}
function _updateClientRecordAfterDeposit(
address payable client,
uint256 underlyingAmountDeposited,
uint256 derivativeAmountDeposited
) internal returns (ClientRecord memory) {
bool exists = clientRecordStorage.doesClientRecordExist(client);
if (!exists) {
ClientRecord memory record =
ClientRecord(
true,
client,
underlyingAmountDeposited,
0,
derivativeAmountDeposited,
derivativeAmountDeposited,
0
);
return record;
} else {
ClientRecord memory record = _getClientRecordByAddress(client);
record.underlyingTotalDeposits = record.underlyingTotalDeposits.add(
underlyingAmountDeposited
);
record.derivativeTotalDeposits = record.derivativeTotalDeposits.add(
derivativeAmountDeposited
);
record.derivativeBalance = record.derivativeBalance.add(
derivativeAmountDeposited
);
return record;
}
}
function _updateClientRecordAfterWithdrawal(
address payable client,
uint256 underlyingAmountWithdrawn,
uint256 derivativeAmountWithdrawn
) internal returns (ClientRecord memory) {
ClientRecord memory record = _getClientRecordByAddress(client);
record.underlyingTotalWithdrawn = record.underlyingTotalWithdrawn.add(
underlyingAmountWithdrawn
);
record.derivativeTotalWithdrawn = record.derivativeTotalWithdrawn.add(
derivativeAmountWithdrawn
);
record.derivativeBalance = record.derivativeBalance.sub(
derivativeAmountWithdrawn
);
return record;
}
function _updateClientRecord(ClientRecord memory clientRecord) internal {
clientRecordStorage.updateClientRecord(
clientRecord._address,
clientRecord.underlyingTotalDeposits,
clientRecord.underlyingTotalWithdrawn,
clientRecord.derivativeBalance,
clientRecord.derivativeTotalDeposits,
clientRecord.derivativeTotalWithdrawn
);
}
function _emitXendTokenReward(address payable member, uint256 amount)
internal
{
emit XendTokenReward(now, member, amount);
}
function _rewardUserWithTokens(
uint256 totalLockPeriod,
uint256 amountDeposited,
address payable recipient
) internal {
uint256 numberOfRewardTokens =
rewardConfig.CalculateIndividualSavingsReward(
totalLockPeriod,
amountDeposited
);
if (numberOfRewardTokens > 0) {
xendToken.mint(recipient, numberOfRewardTokens);
_UpdateMemberToXendTokeRewardMapping(
recipient,
numberOfRewardTokens
);
_totalTokenReward = _totalTokenReward.add(numberOfRewardTokens);
_emitXendTokenReward(recipient, numberOfRewardTokens);
}
}
modifier onlyNonDeprecatedCalls() {
require(!isDeprecated, "Service contract has been deprecated");
_;
}
}
{
"compilationTarget": {
"browser/XendFinanceIndividual_Yearn_V1.sol": "XendFinanceIndividual_Yearn_V1"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"lendingServiceAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"clientRecordStorageAddress","type":"address"},{"internalType":"address","name":"savingsConfigAddress","type":"address"},{"internalType":"address","name":"derivativeTokenAddress","type":"address"},{"internalType":"address","name":"rewardConfigAddress","type":"address"},{"internalType":"address","name":"xendTokenAddress","type":"address"},{"internalType":"address","name":"treasuryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address payable","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"derivativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"DerivativeAssetWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address payable","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"derivativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"UnderlyingAssetDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"date","type":"uint256"},{"indexed":false,"internalType":"address payable","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"XendTokenReward","type":"event"},{"inputs":[{"internalType":"uint256","name":"depositDateInSeconds","type":"uint256"},{"internalType":"uint256","name":"lockPeriodInSeconds","type":"uint256"}],"name":"FixedDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"GetMemberXendTokenReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GetTotalTokenRewardDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"recordId","type":"uint256"},{"internalType":"uint256","name":"derivativeAmount","type":"uint256"}],"name":"WithdrawFromFixedDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"depositorAddress","type":"address"}],"name":"depositDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newServiceAddress","type":"address"}],"name":"deprecateContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"}],"name":"doesClientRecordExist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"}],"name":"getClientRecord","outputs":[{"internalType":"address payable","name":"_address","type":"address"},{"internalType":"uint256","name":"underlyingTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"underlyingTotalWithdrawn","type":"uint256"},{"internalType":"uint256","name":"derivativeBalance","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getClientRecord","outputs":[{"internalType":"address payable","name":"_address","type":"address"},{"internalType":"uint256","name":"underlyingTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"underlyingTotalWithdrawn","type":"uint256"},{"internalType":"uint256","name":"derivativeBalance","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getClientRecordByIndex","outputs":[{"internalType":"address payable","name":"_address","type":"address"},{"internalType":"uint256","name":"underlyingTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"underlyingTotalWithdrawn","type":"uint256"},{"internalType":"uint256","name":"derivativeBalance","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalDeposits","type":"uint256"},{"internalType":"uint256","name":"derivativeTotalWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setAdapterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumLockPeriod","type":"uint256"}],"name":"setMinimumLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"derivativeAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"derivativeAmount","type":"uint256"}],"name":"withdrawDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"}]