Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions contracts/gift-lib/.solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "solhint:default"
}
361 changes: 361 additions & 0 deletions contracts/gift-lib/giftcontract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
//generated by www.structuredeth.com/gift

// to-do: Update to 0.5.x;
pragma solidity ^0.4.26;

interface CompoundERC20 {
function approve(address spender, uint256 amount) external returns(bool);

function mint(uint256 mintAmount) external returns(uint256);

function redeem(uint redeemTokens) external returns(uint);

function totalSupply() public view returns(uint supply);

function balanceOf(address _owner) public view returns(uint256 balance);

function transfer(address _to, uint _value) public returns(bool success);

function transferFrom(address _from, address _to, uint _value) public returns(bool success);

function exchangeRateStored() public view returns(uint256 exchangeRate);
}

interface GiftRegistry {
function addGift(address contractAddress, uint256 initialAmount);
}

interface IKyberNetworkProxy {
function maxGasPrice() external view returns(uint);

function getUserCapInWei(address user) external view returns(uint);

function getUserCapInTokenWei(address user, ERC20 token) external view returns(uint);

function enabled() external view returns(bool);

function info(bytes32 id) external view returns(uint);

function getExpectedRate(
ERC20 src,
ERC20 dest,
uint srcQty
) external view returns(uint expectedRate, uint slippageRate);

function tradeWithHint(
ERC20 src,
uint srcAmount,
ERC20 dest,
address destAddress,
uint maxDestAmount,
uint minConversionRate,
address walletId,
bytes hint
) external payable returns(uint);

function swapEtherToToken(ERC20 token, uint minRate) external payable returns(uint);

function swapTokenToEther(ERC20 token, uint tokenQty, uint minRate) external returns(uint);
}


library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns(uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}

function div(uint256 a, uint256 b) internal constant returns(uint256) {
assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}

function sub(uint256 a, uint256 b) internal constant returns(uint256) {
assert(b <= a);
return a - b;
}

function add(uint256 a, uint256 b) internal constant returns(uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}


interface ERC20 {
function totalSupply() public view returns(uint supply);

function balanceOf(address _owner) public view returns(uint balance);

function transfer(address _to, uint _value) public returns(bool success);

function transferFrom(address _from, address _to, uint _value) public returns(bool success);

function approve(address _spender, uint _value) public returns(bool success);

function allowance(address _owner, address _spender) public view returns(uint remaining);

function decimals() public view returns(uint digits);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}


contract GiftOfCompound {


// to-do: Fix scoping of variables;
// to-do: Clean up flow on entry functions
// to-do: re-compose functions for better compartmentalization
// to-do: write abstract interface for GiftOf contracts

using SafeMath
for uint256;
address theRecipient;
address theSender;
bytes PERM_HINT;
uint256 initialCDaiAmount;
uint256 theInterestRecipient;
uint256 theInterestSender;
uint256 initialDaiAmount;
uint256 initialcDaiDaiRate;
uint256 startedWithGiftAmount;
uint256 internal PRECISION;
uint256 valueChange2Result;
address cOffRamp;
CompoundERC20 cdai;
GiftRegistry giftRegistration;

modifier onlyGiftGroup() {
if (msg.sender != theSender && msg.sender != theRecipient) {
throw;
}
_;
}

modifier onlyCOffRamp() {
if (msg.sender != cOffRamp) {
throw;
}
_;
}


//if smeone sends eth to this contract, throw it because it will just end up getting locked forever
function() payable {
throw;
}

constructor(address recipient, uint256 interestRecipient, uint256 interestSender) public payable {

if (msg.value <= 0) {
throw;
}

theSender = msg.sender;
theRecipient = recipient;
PRECISION = 10 ** 27;
theInterestSender = interestSender;
theInterestRecipient = interestRecipient;

//sum of the interest percentage must be 100 so everyone can get their funds
if (theInterestRecipient.add(theInterestSender) != 100) {
throw;
}

startedWithGiftAmount = 0;
initialCDaiAmount = giftWrap();
cOffRamp = 0x4C8A4aEbB3F28F9e50BDF16eD8491A1FF2CFB6fe;
address regContractAddr = 0xb83353ddea4995c3c330cf1803fc1b9f07c0de88;
giftRegistration = GiftRegistry(regContractAddr);
giftRegistration.addGift(this, initialCDaiAmount);

}

function redeemAll(address _to) returns(bool) {
uint256 canSendAmount = amountEntitledTo(msg.sender);
transfer(_to, canSendAmount);
return true;

}

function redeemAllToCentral(address _to) returns(bool) {
uint256 canSendAmount = amountEntitledTo(msg.sender);
transferKeepCDai(cOffRamp, canSendAmount);
return true;
}

function transferKeepCDai(address _to, uint256 _value) onlyGiftGroup returns(bool) {

uint256 userHasAccessTo = amountEntitledTo(msg.sender);
ERC20 dai = ERC20(0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359);

// you do not enough entitlement to the interest

if (_value > userHasAccessTo) {
throw;
} else {
uint256 currentCDai = cdai.balanceOf(this);
require(dai.transfer(_to, currentCDai));
}

/**
* set initial amount to current amount so that people can keep
* withdrawing and we can know if they are entiteld to the interest amount
*/
initialCDaiAmount = cdai.balanceOf(this);
return true;
}

function transfer(address _to, uint256 _value) onlyGiftGroup returns(bool) {

uint256 userHasAccessTo = amountEntitledTo(msg.sender);
ERC20 dai = ERC20(0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359);

//you do not enough entitlement to the interest
if (_value > userHasAccessTo) {
revert();
} else {
cdai.redeem(_value);
uint256 currentDai = dai.balanceOf(this);
require(dai.transfer(_to, currentDai));
}

/**
* set initial amount to current amount so that people can keep
* withdrawing and we can know if they are entiteld to the interest amount
*/
initialCDaiAmount = cdai.balanceOf(this);

return true;
}

function giftWrap() internal returns(uint256) {
ERC20 dai = ERC20(0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359);
address kyberProxyAddress = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
IKyberNetworkProxy kyberProxy = IKyberNetworkProxy(kyberProxyAddress);
cdai = CompoundERC20(0xf5dce57282a584d2746faf1593d3121fcac444dc);
theRecipient.send(1500000000000000);
uint256 ethAmount1 = msg.value.sub(1500000000000000);
PERM_HINT = "PERM";
ERC20 eth = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
uint daiAmount = kyberProxy.tradeWithHint.value(ethAmount1)(
eth,
ethAmount1,
dai,
this,
8000000000000000000000000000000000000000000000000000000000000000,
0,
0x0000000000000000000000000000000000000004,
PERM_HINT
);
dai.approve(address(cdai), 8000000000000000000000000000000000000000000000000000000);
cdai.mint(daiAmount);
uint256 cdaiAmount = cdai.balanceOf(this);
startedWithGiftAmount = cdaiAmount;
initialDaiAmount = daiAmount;
initialcDaiDaiRate = cdai.exchangeRateStored();

return cdaiAmount;
}

function changeCOffRamp(address newCOffRamp) onlyCOffRamp returns(bool) {
cOffRamp = newCOffRamp;
}

function amountEntitledTo(address qAddress) constant returns(uint256) {
uint256 initialExchangeRate = initialcDaiDaiRate;
uint multiplier = 10000000;
uint256 currentExchangeRate = cdai.exchangeRateStored().mul(multiplier);
uint256 valueChange = currentExchangeRate.div(initialExchangeRate);
uint256 valueChange2 = initialCDaiAmount.mul(valueChange).div(multiplier);
uint256 totalInterestEarned = valueChange2.sub(initialCDaiAmount);
uint256 usersPercentage;

valueChange2Result = valueChange2;

if (qAddress == theRecipient) {
usersPercentage = theInterestSender;
} else if (qAddress == theSender) {
usersPercentage = theInterestSender;
} else {
return 0;
}

uint256 tInterestEntitledTo = totalInterestEarned.mul(usersPercentage).div(100);
uint256 amountITo;


// to-do: compartmentalize this if-web into internal function

if (qAddress == theRecipient) {
amountITo = initialCDaiAmount.sub(tInterestEntitledTo);
}

if (qAddress == theSender) {
if (initialCDaiAmount == startedWithGiftAmount) {
//nothing has been redeemed, so sender can refund
amountITo = initialCDaiAmount;
} else {
amountITo = tInterestEntitledTo;
}
}

return amountITo;

}

function getStartedWithGiftAmount() constant external returns(uint256) {
return startedWithGiftAmount;
}

function getStartedWithDaiValueAmount() constant external returns(uint256) {
return initialDaiAmount;
}

function getStartedWithCDaiDaiRate() constant external returns(uint256) {
return initialcDaiDaiRate;
}

function getRecipient() constant external returns(address) {
return theRecipient;
}

function getSender() constant external returns(address) {
return theSender;
}

function percentageInterestEntitledTo(address qAddress) constant external returns(uint256) {
uint256 usersPercentage;

if (qAddress == theRecipient) {
usersPercentage = theInterestRecipient;
} else if (qAddress == theSender) {
usersPercentage = theInterestSender;
} else {
usersPercentage = 0;
}

return usersPercentage;
}

function valueChangeVal() constant external returns(uint256) {

uint256 initialExchangeRate = initialcDaiDaiRate;
uint multiplier = 10000000;
uint256 currentExchangeRate = cdai.exchangeRateStored().mul(multiplier);
uint256 valueChange = currentExchangeRate.div(initialExchangeRate);
uint256 valueChange2 = initialCDaiAmount.mul(valueChange).div(multiplier);
uint256 totalInterestEarned = valueChange2.sub(initialCDaiAmount);

return totalInterestEarned;
}

function currentGiftAmount() constant external returns(uint256) {
uint256 cDaiMinted = cdai.balanceOf(this);
return cDaiMinted;
}
}