Created
October 13, 2019 09:04
-
-
Save RossPfeiffer/e727e4fb7eb4fc0f949a35ea7443debe to your computer and use it in GitHub Desktop.
ColorToken
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^ 0.5.1; | |
contract ColorToken{ | |
BondContract public bondContract; | |
ResolveContract public resolveContract; | |
address lastGateway; | |
address communityResolve; | |
address THIS = address(this); | |
string public name = "Color Token"; | |
string public symbol = "RGB"; | |
uint8 constant public decimals = 18; | |
uint _totalSupply; | |
uint masternodeFee = 10; // 10% | |
mapping(address => PyramidProxy) proxy; | |
mapping(address => address) proxyOwner; | |
mapping(address => uint256) public redBonds; | |
mapping(address => uint256) public greenBonds; | |
mapping(address => uint256) public blueBonds; | |
mapping(address => uint256) public redResolves; | |
mapping(address => uint256) public greenResolves; | |
mapping(address => uint256) public blueResolves; | |
mapping(address => mapping(address => uint)) approvals; | |
mapping(address => address) gateway; | |
mapping(address => uint256) public pocket; | |
mapping(address => uint256) public upline; | |
mapping(address => address) public minecart; | |
mapping(address => address) public votingFor; | |
mapping(address => uint256) public votesFor; | |
constructor(address _bondContract) public{ | |
bondContract = BondContract(_bondContract); | |
resolveContract = ResolveContract( bondContract.getResolveContract() ); | |
communityResolve = msg.sender; | |
lastGateway = THIS; | |
} | |
function totalSupply() public view returns (uint256) { | |
return _totalSupply; | |
} | |
function balanceOf(address _owner) public view returns (uint balance) { | |
return proxy[_owner].getBalance(); | |
} | |
function max1(uint x) internal pure returns (uint){ | |
if(x>1e18) | |
return 1e18; | |
else | |
return x; | |
} | |
function ensureProxy(address addr) internal returns(address proxyAddr){ | |
if( proxyAddress(addr) == 0x0000000000000000000000000000000000000000){ | |
proxy[addr] = new PyramidProxy( this, bondContract ); | |
proxyOwner[ proxyAddress( addr ) ] = addr; | |
} | |
return proxyAddress( addr ); | |
} | |
event Buy( address indexed addr, uint256 spent, uint256 bonds, uint red, uint green, uint blue); | |
function buy(uint _red, uint _green, uint _blue) payable public { | |
buy( msg.value, _red, _green, _blue, true); | |
} | |
function buy(uint ETH, uint _red, uint _green, uint _blue, bool EMIT) payable public returns(uint bondsCreated){ | |
address sender = msg.sender; | |
ensureProxy(sender); | |
_red = max1(_red); | |
_green = max1(_green); | |
_blue = max1(_blue); | |
uint fee = ETH / masternodeFee; | |
uint eth4Bonds = ETH - fee; | |
address payable proxyAddr = proxyAddress(sender); | |
proxyAddr.transfer(eth4Bonds); | |
uint createdBonds = proxy[sender].buy(); | |
bondsAddColor(sender,createdBonds, _red, _green, _blue); | |
pocket[ gateway[sender] ] += fee/2; | |
upline[ gateway[sender] ] += fee/2; | |
pushMinecart(); | |
if( EMIT ){ | |
emit Buy( sender, ETH, createdBonds, _red, _green, _blue); | |
} | |
if( bondBalance(sender) > 10000*1e12 ){ | |
lastGateway = sender; | |
} | |
return createdBonds; | |
} | |
function pushMinecart() internal{ | |
pushMinecart(msg.sender); | |
} | |
function pushMinecart(address addr) internal{ | |
if(gateway[addr] == 0x0000000000000000000000000000000000000000 || bondBalance( gateway[addr] ) < 10000*1e12){ | |
gateway[addr] = lastGateway; | |
} | |
if( minecart[addr] == THIS || minecart[addr] == 0x0000000000000000000000000000000000000000){ | |
minecart[addr] = addr; | |
}else{ | |
minecart[addr] = gateway[ minecart[addr] ]; | |
} | |
address dropOff = minecart[addr]; | |
pocket[ dropOff ] += upline[ dropOff ] / 2; | |
upline[ gateway[dropOff] ] += upline[ dropOff ] / 2; | |
upline[ dropOff ] = 0; | |
} | |
event Sell( address indexed addr, uint256 bondsSold, uint256 resolves, uint red, uint green, uint blue); | |
function sell(uint amountToSell) public{ | |
address sender = sender; | |
uint bondsBefore = bondBalance(sender); | |
(uint _red, uint _green, uint _blue) = RGB_ratio(); | |
uint mintedResolves = proxy[sender].sell(amountToSell); | |
/*uint _red = redBonds[sender] / bondsBefore; | |
uint _green = greenBonds[sender] / bondsBefore; | |
uint _blue = blueBonds[sender] / bondsBefore;*/ | |
resolvesAddColor(sender, mintedResolves, _red, _green, _blue); | |
votesFor[ votingFor[sender] ] += mintedResolves; | |
_totalSupply += mintedResolves; | |
emit Sell(sender, amountToSell, mintedResolves, _red, _green, _blue ); | |
bondsThinColor(msg.sender, bondsBefore - amountToSell, bondsBefore); | |
pushMinecart(); | |
} | |
function stake(uint amountToStake) public{ | |
address sender = msg.sender; | |
proxy[sender].stake( amountToStake ); | |
colorShift(sender, address(bondContract), amountToStake ); | |
pushMinecart(); | |
} | |
function unstake(uint amountToUnstake) public{ | |
address sender = msg.sender; | |
proxy[sender].unstake( amountToUnstake ); | |
colorShift(address(bondContract), sender, amountToUnstake ); | |
pushMinecart(); | |
} | |
function reinvest() public{ | |
address sender = msg.sender; | |
//address proxyAddr = proxyAddress( sender ); | |
//uint bal = bondContract.balanceOf( proxyAddr ); | |
/*uint red = redBonds[sender] / bal; | |
uint green = greenBonds[sender] / bal; | |
uint blue = blueBonds[sender] / bal;*/ | |
(uint red, uint green, uint blue) = RGB_ratio(); | |
uint createdBonds; | |
uint dissolvedResolves; | |
(createdBonds, dissolvedResolves) = proxy[sender].reinvest(); | |
createdBonds += buy( pocket[sender], red, green, blue, false); | |
pocket[sender] = 0; | |
bondsAddColor(sender, createdBonds, red, green, blue); | |
// update core contract's Resolve color | |
address pyrAddr = address(bondContract); | |
uint currentResolves = resolveContract.balanceOf( pyrAddr ); | |
resolvesThinColor(pyrAddr, currentResolves, currentResolves + dissolvedResolves); | |
pushMinecart(); | |
} | |
function withdraw() public{ | |
address payable sender = msg.sender; | |
uint dissolvedResolves = proxy[sender].withdraw(); | |
uint earned = pocket[sender]; | |
pocket[sender] = 0; | |
sender.transfer( earned ); | |
// update core contract's Resolve color | |
address pyrAddr = address(bondContract); | |
uint currentResolves = resolveContract.balanceOf( pyrAddr ); | |
resolvesThinColor(pyrAddr, currentResolves, currentResolves + dissolvedResolves); | |
pushMinecart(); | |
} | |
function proxyAddress(address addr) public view returns(address payable addressOfProxxy){ | |
return address( proxy[addr] ); | |
} | |
function getProxyOwner(address proxyAddr) public view returns(address ownerAddress){ | |
return proxyOwner[proxyAddr]; | |
} | |
function unbindResolves(uint amount) public { | |
address sender = msg.sender; | |
uint totalResolves = resolveContract.balanceOf( proxyAddress(sender) ); | |
resolvesThinColor( sender, totalResolves - amount, totalResolves); | |
proxy[sender].transfer(sender, amount); | |
} | |
function setVotingFor(address candidate) public { | |
address sender = msg.sender; | |
//Contracts can't vote for anyone. Because then people would just evenly split the pool fund most of the time | |
require( !isContract(sender) );//This could be enhanced, but this is a barebones demonstration of the powhr of resolve tokens | |
uint voteWeight = balanceOf(sender); | |
votesFor[ votingFor[ sender ] ] -= voteWeight; | |
votingFor[ sender ] = candidate; | |
votesFor[ candidate ] += voteWeight; | |
} | |
function assertNewCommunityResolve(address candidate) public { | |
if( votesFor[candidate] > votesFor[communityResolve] ){ | |
communityResolve = candidate; | |
} | |
} | |
function GET_FUNDED() public{ | |
if(msg.sender == communityResolve){ | |
uint money_gotten = pocket[ THIS ]; | |
pocket[ THIS ] = 0; | |
msg.sender.transfer(money_gotten); | |
pushMinecart(); | |
} | |
} | |
// Function that is called when a user or another contract wants to transfer funds . | |
function transfer(address _to, uint _value, bytes memory _data) public returns (bool success) { | |
if( balanceOf(msg.sender) < _value ) revert(); | |
if( isContract(_to) ){ | |
return transferToContract(_to, _value, _data); | |
}else{ | |
return transferToAddress(_to, _value, _data); | |
} | |
} | |
// Standard function transfer similar to ERC20 transfer with no _data . | |
// Added due to backwards compatibility reasons . | |
function transfer(address _to, uint _value) public returns (bool success) { | |
if (balanceOf(msg.sender) < _value) revert(); | |
//standard function transfer similar to ERC20 transfer with no _data | |
//added due to backwards compatibility reasons | |
bytes memory empty; | |
if(isContract(_to)){ | |
return transferToContract(_to, _value, empty); | |
}else{ | |
return transferToAddress(_to, _value, empty); | |
} | |
} | |
//assemble the given address bytecode. If bytecode exists then the _addr is a contract. | |
function isContract(address _addr) public view returns (bool is_contract) { | |
uint length = 0; | |
assembly { | |
//retrieve the size of the code on target address, this needs assembly | |
length := extcodesize(_addr) | |
} | |
if(length>0) { | |
return true; | |
}else { | |
return false; | |
} | |
} | |
//function that is called when transaction target is an address | |
function transferToAddress(address _to, uint _value, bytes memory _data) private returns (bool success) { | |
moveTokens(msg.sender,_to,_value); | |
return true; | |
} | |
//function that is called when transaction target is a contract | |
function transferToContract(address _to, uint _value, bytes memory _data) private returns (bool success) { | |
moveTokens(msg.sender,_to,_value); | |
ERC223ReceivingContract reciever = ERC223ReceivingContract(_to); | |
reciever.tokenFallback(msg.sender, _value, _data); | |
return true; | |
} | |
function moveTokens(address _from, address _to, uint _amount) internal{ | |
colorShift(_from, _to, _amount); | |
ensureProxy(_to); | |
votesFor[ votingFor[_from] ] -= _amount; | |
votesFor[ votingFor[_to] ] += _amount; | |
proxy[_from].transfer( proxyAddress(_to), _amount ); | |
} | |
function RGB_scale(uint r, uint g, uint b, uint numerator, uint denominator) internal pure returns(uint,uint,uint){ | |
return (r * numerator / denominator, g * numerator / denominator, b * numerator / denominator ); | |
} | |
function colorShift(address _from, address _to, uint _amount) internal{ | |
//uint bal = proxy[_from].getBalance(); | |
/*uint red_ratio = redResolves[_from] * _amount / bal; | |
uint green_ratio = greenResolves[_from] * _amount / bal; | |
uint blue_ratio = blueResolves[_from] * _amount / bal;*/ | |
(uint red_ratio, uint green_ratio, uint blue_ratio) = RGB_scale(redResolves[_from], greenResolves[_from], blueResolves[_from], _amount, proxy[_from].getBalance() ); | |
redResolves[_from] -= red_ratio; | |
greenResolves[_from] -= green_ratio; | |
blueResolves[_from] -= blue_ratio; | |
redResolves[_to] += red_ratio; | |
greenResolves[_to] += green_ratio; | |
blueResolves[_to] += blue_ratio; | |
} | |
function allowance(address src, address guy) public view returns (uint) { | |
return approvals[src][guy]; | |
} | |
function transferFrom(address src, address dst, uint wad) public returns (bool){ | |
address sender = msg.sender; | |
require(approvals[src][sender] >= wad); | |
require(proxy[src].getBalance() >= wad); | |
if (src != sender) { | |
approvals[src][sender] -= wad; | |
} | |
moveTokens(src,dst,wad); | |
return true; | |
} | |
event Approval(address indexed src, address indexed guy, uint wad); | |
address sender = msg.sender; | |
function approve(address guy, uint wad) public returns (bool) { | |
approvals[sender][guy] = wad; | |
emit Approval(sender, guy, wad); | |
return true; | |
} | |
function resolvesAddColor(address addr, uint amount , uint red, uint green, uint blue) internal{ | |
redResolves[addr] += red * amount; | |
greenResolves[addr] += green * amount; | |
blueResolves[addr] += blue * amount; | |
} | |
function bondsAddColor(address addr, uint amount , uint red, uint green, uint blue) internal{ | |
redBonds[addr] += red * amount; | |
greenBonds[addr] += green * amount; | |
blueBonds[addr] += blue * amount; | |
} | |
function resolvesThinColor(address addr, uint newWeight, uint oldWeight) internal{ | |
(redResolves[addr], greenResolves[addr], blueResolves[addr]) = RGB_scale(redResolves[addr], greenResolves[addr], blueResolves[addr], newWeight, oldWeight); | |
/*redResolves[addr] = redResolves[addr] * newWeight / oldWeight; | |
greenResolves[addr] = greenResolves[addr] * newWeight / oldWeight; | |
blueResolves[addr] = blueResolves[addr] * newWeight / oldWeight; */ | |
} | |
function bondsThinColor(address addr, uint newWeight, uint oldWeight) internal{ | |
(redBonds[addr], greenBonds[addr], blueBonds[addr]) = RGB_scale(redBonds[addr], greenBonds[addr], blueBonds[addr], newWeight, oldWeight); | |
/*redBonds[addr] = redBonds[addr] * newWeight / oldWeight; | |
greenBonds[addr] = greenBonds[addr] * newWeight / oldWeight; | |
blueBonds[addr] = blueBonds[addr] * newWeight / oldWeight; */ | |
} | |
function RGB_ratio() public view returns(uint,uint,uint){ | |
//uint bonds = bondBalance(msg.sender); | |
return RGB_ratio(msg.sender);//(redBonds[sender]/bonds, greenBonds[sender]/bonds, blueBonds[sender]/bonds); | |
} | |
function RGB_ratio(address addr) public view returns(uint,uint,uint){ | |
uint bonds = bondBalance(addr); | |
return (redBonds[sender]/bonds, greenBonds[sender]/bonds, blueBonds[sender]/bonds); | |
} | |
function () payable external { | |
if (msg.value > 0) { | |
//address sender = msg.sender; | |
//uint totalHoldings = bondBalance(msg.sender); | |
(uint _red , uint _green, uint _blue) = RGB_ratio(); | |
/*redBonds[sender]/totalHoldings; | |
= greenBonds[sender]/totalHoldings; | |
= blueBonds[sender]/totalHoldings;*/ | |
buy(_red, _green, _blue); | |
} else { | |
withdraw(); | |
} | |
} | |
function bondBalance(address addr) public view returns(uint){ | |
return bondContract.balanceOf( proxyAddress(addr) ); | |
} | |
event BondTransfer(address from, address to, uint amount, uint red, uint green, uint blue); | |
function bondTransfer(address to, uint amount) public{ | |
address sender = msg.sender; | |
uint sendersFormerTotalBonds = bondBalance(sender); | |
bondsThinColor( sender, sendersFormerTotalBonds - amount, sendersFormerTotalBonds); | |
(uint r, uint g, uint b) = RGB_ratio(sender); | |
bondsAddColor( to, amount, r, g, b ); | |
proxy[sender].bondTransfer( proxyAddress(to) , amount); | |
emit BondTransfer(sender, to, amount, r, g, b); | |
} | |
} | |
contract BondContract{ | |
function balanceOf(address _owner) public view returns (uint256 balance); | |
function sellBonds(uint amount) public returns(uint,uint); | |
function getResolveContract() public view returns(address); | |
function pullResolves(uint amount) public; | |
function reinvestEarnings(uint amountFromEarnings) public returns(uint,uint); | |
function withdraw(uint amount) public returns(uint); | |
function fund() payable public returns(uint); | |
function resolveEarnings(address _owner) public view returns (uint256 amount); | |
} | |
contract ResolveContract{ | |
function balanceOf(address _owner) public view returns (uint256 balance); | |
function transfer(address _to, uint _value) public returns (bool success); | |
} | |
contract PyramidProxy{ | |
ColorToken router; | |
BondContract public bondContract; | |
ResolveContract public resolveContract; | |
uint ETH; | |
address THIS = address(this); | |
constructor(ColorToken _router, BondContract _BondContract) public{ | |
router = _router; | |
bondContract = _BondContract; | |
resolveContract = ResolveContract( _BondContract.getResolveContract() ); | |
} | |
modifier routerOnly{ | |
require(msg.sender == address(router)); | |
_; | |
} | |
function () payable external routerOnly(){ | |
ETH += msg.value; | |
} | |
function buy() public routerOnly() returns(uint){ | |
uint _ETH = ETH; | |
ETH = 0; | |
return bondContract.fund.value( _ETH )(); | |
} | |
function cash2Owner() internal{ | |
address payable owner = address(uint160( router.getProxyOwner( THIS ) ) ); | |
uint _ETH = ETH; | |
ETH = 0; | |
owner.transfer( _ETH ); | |
} | |
function getBalance() public view returns (uint balance) { | |
address bC = address(bondContract); | |
if( THIS == bC ){ | |
return resolveContract.balanceOf( bC ); | |
}else{ | |
return resolveContract.balanceOf( THIS ); | |
} | |
} | |
function resolveEarnings() internal view returns(uint){ | |
return bondContract.resolveEarnings( THIS ); | |
} | |
function reinvest() public routerOnly() returns(uint,uint){ | |
return bondContract.reinvestEarnings( resolveEarnings() ); | |
} | |
function withdraw() public routerOnly() returns(uint){ | |
uint dissolvedResolves = bondContract.withdraw( resolveEarnings() ); | |
cash2Owner(); | |
return dissolvedResolves; | |
} | |
function sell(uint amount) public routerOnly() returns (uint){ | |
uint resolves; | |
(,resolves) = bondContract.sellBonds(amount); | |
cash2Owner(); | |
return resolves; | |
} | |
function stake(uint amount) public routerOnly(){ | |
resolveContract.transfer( address(bondContract), amount ); | |
} | |
function transfer(address addr, uint amount) public routerOnly(){ | |
resolveContract.transfer( addr, amount ); | |
} | |
function bondTransfer(address to, uint amount) public routerOnly(){ | |
bondContract.bondTransfer( to, amount ); | |
} | |
function unstake(uint amount) public routerOnly(){ | |
bondContract.pullResolves( amount ); | |
} | |
} | |
contract ERC223ReceivingContract{ | |
function tokenFallback(address _from, uint _value, bytes calldata _data) external; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment