Skip to content

Instantly share code, notes, and snippets.

@borisd
Created February 4, 2018 16:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save borisd/42d48a9de261d4f8e6112b42835be3cf to your computer and use it in GitHub Desktop.
Save borisd/42d48a9de261d4f8e6112b42835be3cf to your computer and use it in GitHub Desktop.
PoWHCoin
pragma solidity ^0.4.18;
// If you wanna escape this contract REALLY FAST
// 1. open MEW/METAMASK
// 2. Put this as data: 0xb1e35242
// 3. send 150000+ gas
// That calls the getMeOutOfHere() method
// Wacky version, 0-1 tokens takes 10eth (should be avg 200% gains), 1-2 takes another 30eth (avg 100% gains), and beyond that who the fuck knows but it's 50% gains
// 10% fees, price goes up crazy fast
contract PonziTokenV3 {
uint256 constant PRECISION = 0x10000000000000000; // 2^64
// CRR = 80 %
int constant CRRN = 1;
int constant CRRD = 2;
// The price coefficient. Chosen such that at 1 token total supply
// the reserve is 0.8 ether and price 1 ether/token.
int constant LOGC = - 0x296ABF784A358468C;
string constant public name = "ProofOfWeakHands";
string constant public symbol = "POWH";
uint8 constant public decimals = 18;
uint256 public totalSupply;
// amount of shares for each address (scaled number)
mapping (address => uint256) public balanceOfOld;
// allowance map, see erc20
mapping (address => mapping (address => uint256)) public allowance;
// amount payed out for each address (scaled number)
mapping (address => int256) payouts;
// sum of all payouts (scaled number)
int256 totalPayouts;
// amount earned for each share (scaled number)
uint256 earningsPerShare;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
//address owner;
function PonziTokenV3() public {
//owner = msg.sender;
}
// These are functions solely created to appease the frontend
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balanceOfOld[_owner];
}
function withdraw(uint tokenCount) // the parameter is ignored, yes
public
returns (bool)
{
var balance = dividends(msg.sender);
payouts[msg.sender] += (int256) (balance * PRECISION);
totalPayouts += (int256) (balance * PRECISION);
msg.sender.transfer(balance);
return true;
}
function sellMyTokensDaddy() public {
var balance = balanceOf(msg.sender);
transferTokens(msg.sender, address(this), balance);
// this triggers the internal sell function
}
function getMeOutOfHere() public {
sellMyTokensDaddy();
withdraw(1);
// parameter is ignored
}
function fund()
public
payable
returns (bool)
{
if (msg.value > 0.000001 ether)
buy();
else
return false;
return true;
}
function buyPrice() public constant returns (uint) {
return getTokensForEther(1 finney);
}
function sellPrice() public constant returns (uint) {
return getEtherForTokens(1 finney);
}
// End of useless functions
// Invariants
// totalPayout/Supply correct:
// totalPayouts = \sum_{addr:address} payouts(addr)
// totalSupply = \sum_{addr:address} balanceOfOld(addr)
// dividends not negative:
// \forall addr:address. payouts[addr] <= earningsPerShare * balanceOfOld[addr]
// supply/reserve correlation:
// totalSupply ~= exp(LOGC + CRRN/CRRD*log(reserve())
// i.e. totalSupply = C * reserve()**CRR
// reserve equals balance minus payouts
// reserve() = this.balance - \sum_{addr:address} dividends(addr)
function transferTokens(address _from, address _to, uint256 _value) internal {
if (balanceOfOld[_from] < _value)
revert();
if (_to == address(this)) {
sell(_value);
}
else {
int256 payoutDiff = (int256) (earningsPerShare * _value);
balanceOfOld[_from] -= _value;
balanceOfOld[_to] += _value;
payouts[_from] -= payoutDiff;
payouts[_to] += payoutDiff;
}
Transfer(_from, _to, _value);
}
function transfer(address _to, uint256 _value) public {
transferTokens(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public {
var _allowance = allowance[_from][msg.sender];
if (_allowance < _value)
revert();
allowance[_from][msg.sender] = _allowance - _value;
transferTokens(_from, _to, _value);
}
function approve(address _spender, uint256 _value) public {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_value != 0) && (allowance[msg.sender][_spender] != 0)) revert();
allowance[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
function dividends(address _owner) public constant returns (uint256 amount) {
return (uint256) ((int256)(earningsPerShare * balanceOfOld[_owner]) - payouts[_owner]) / PRECISION;
}
function withdrawOld(address to) public {
var balance = dividends(msg.sender);
payouts[msg.sender] += (int256) (balance * PRECISION);
totalPayouts += (int256) (balance * PRECISION);
to.transfer(balance);
}
function balance() internal constant returns (uint256 amount) {
return this.balance - msg.value;
}
function reserve() public constant returns (uint256 amount) {
return balance()
- ((uint256) ((int256) (earningsPerShare * totalSupply) - totalPayouts) / PRECISION) - 1;
}
function buy() internal {
if (msg.value < 0.000001 ether || msg.value > 1000000 ether)
revert();
var sender = msg.sender;
// 5 % of the amount is used to pay holders.
var fee = (uint)(msg.value / 10);
// compute number of bought tokens
var numEther = msg.value - fee;
var numTokens = getTokensForEther(numEther);
var buyerfee = fee * PRECISION;
if (totalSupply > 0) {
// compute how the fee distributed to previous holders and buyer.
// The buyer already gets a part of the fee as if he would buy each token separately.
var holderreward =
(PRECISION - (reserve() + numEther) * numTokens * PRECISION / (totalSupply + numTokens) / numEther)
* (uint)(CRRD) / (uint)(CRRD - CRRN);
var holderfee = fee * holderreward;
buyerfee -= holderfee;
// Fee is distributed to all existing tokens before buying
var feePerShare = holderfee / totalSupply;
earningsPerShare += feePerShare;
}
// add numTokens to total supply
totalSupply += numTokens;
// add numTokens to balance
balanceOfOld[sender] += numTokens;
// fix payouts so that sender doesn't get old earnings for the new tokens.
// also add its buyerfee
var payoutDiff = (int256) ((earningsPerShare * numTokens) - buyerfee);
payouts[sender] += payoutDiff;
totalPayouts += payoutDiff;
}
function sell(uint256 amount) internal {
var numEthers = getEtherForTokens(amount);
// remove tokens
totalSupply -= amount;
balanceOfOld[msg.sender] -= amount;
// fix payouts and put the ethers in payout
var payoutDiff = (int256) (earningsPerShare * amount + (numEthers * PRECISION));
payouts[msg.sender] -= payoutDiff;
totalPayouts -= payoutDiff;
}
function getTokensForEther(uint256 ethervalue) public constant returns (uint256 tokens) {
return fixedExp(fixedLog(reserve() + ethervalue) * CRRN / CRRD + LOGC) - totalSupply;
}
function getEtherForTokens(uint256 tokens) public constant returns (uint256 ethervalue) {
if (tokens == totalSupply)
return reserve();
return reserve() - fixedExp((fixedLog(totalSupply - tokens) - LOGC) * CRRD / CRRN);
}
int256 constant one = 0x10000000000000000;
uint256 constant sqrt2 = 0x16a09e667f3bcc908;
uint256 constant sqrtdot5 = 0x0b504f333f9de6484;
int256 constant ln2 = 0x0b17217f7d1cf79ac;
int256 constant ln2_64dot5 = 0x2cb53f09f05cc627c8;
int256 constant c1 = 0x1ffffffffff9dac9b;
int256 constant c3 = 0x0aaaaaaac16877908;
int256 constant c5 = 0x0666664e5e9fa0c99;
int256 constant c7 = 0x049254026a7630acf;
int256 constant c9 = 0x038bd75ed37753d68;
int256 constant c11 = 0x03284a0c14610924f;
function fixedLog(uint256 a) internal pure returns (int256 log) {
int32 scale = 0;
while (a > sqrt2) {
a /= 2;
scale++;
}
while (a <= sqrtdot5) {
a *= 2;
scale--;
}
int256 s = (((int256)(a) - one) * one) / ((int256)(a) + one);
// The polynomial R = c1*x + c3*x^3 + ... + c11 * x^11
// approximates the function log(1+x)-log(1-x)
// Hence R(s) = log((1+s)/(1-s)) = log(a)
var z = (s * s) / one;
return scale * ln2 +
(s * (c1 + (z * (c3 + (z * (c5 + (z * (c7 + (z * (c9 + (z * c11 / one))
/ one)) / one)) / one)) / one)) / one);
}
int256 constant c2 = 0x02aaaaaaaaa015db0;
int256 constant c4 = - 0x000b60b60808399d1;
int256 constant c6 = 0x0000455956bccdd06;
int256 constant c8 = - 0x000001b893ad04b3a;
function fixedExp(int256 a) internal pure returns (uint256 exp) {
int256 scale = (a + (ln2_64dot5)) / ln2 - 64;
a -= scale * ln2;
// The polynomial R = 2 + c2*x^2 + c4*x^4 + ...
// approximates the function x*(exp(x)+1)/(exp(x)-1)
// Hence exp(x) = (R(x)+x)/(R(x)-x)
int256 z = (a * a) / one;
int256 R = ((int256)(2) * one) +
(z * (c2 + (z * (c4 + (z * (c6 + (z * c8 / one)) / one)) / one)) / one);
exp = (uint256) (((R + a) * one) / (R - a));
if (scale >= 0)
exp <<= scale;
else
exp >>= - scale;
return exp;
}
/*function destroy() external {
selfdestruct(owner);
}*/
function() payable public {
if (msg.value > 0)
buy();
else
withdrawOld(msg.sender);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment