-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathScenarioBondingCurve.sol
More file actions
179 lines (156 loc) · 5.67 KB
/
ScenarioBondingCurve.sol
File metadata and controls
179 lines (156 loc) · 5.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
pragma solidity ^0.6.1;
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
contract ScenarioBondingCurve is DSMath {
address payable public beneficiary;
uint public currentSupply;
uint public totalContributed;
mapping (address => uint) public ledger;
mapping (address => uint) public contributions;
mapping (address => uint) public asks;
uint public exponent;
uint public coefficient;
uint public reserveRatio;
uint public constant precision = 1000000000000000000;
string internal constant INSUFFICIENT_ETH = 'Insufficient Ether';
string internal constant INSUFFICIENT_TOKENS = 'Request exceeds token balance';
string internal constant INVALID_ADDRESS = 'Wallet does not exist';
constructor()
public {
beneficiary = 0x4aB6A3307AEfcC05b9de8Dbf3B0a6DEcEBa320E6;
exponent = 2;
coefficient = 10000000000;
reserveRatio = wdiv(4, 5);
currentSupply = 1;
}
function buy(uint amount)
external payable {
uint price = calcMintPrice(amount);
require(msg.value >= price, INSUFFICIENT_ETH);
uint reserveValue = wmul(msg.value, reserveRatio);
uint contributionValue = sub(msg.value, reserveValue);
uint refund = msg.value - reserveValue - contributionValue;
if (refund > 0) {
msg.sender.transfer(refund);
}
ledger[msg.sender] = add(ledger[msg.sender], amount);
currentSupply = add(currentSupply, amount);
contribute(contributionValue, msg.sender);
}
function sell(uint amount)
external {
require(amount <= ledger[msg.sender], INSUFFICIENT_TOKENS);
uint exitValue = calcBurnReward(amount);
msg.sender.transfer(exitValue);
ledger[msg.sender] = sub(ledger[msg.sender], amount);
currentSupply = sub(currentSupply, amount);
}
function lovequit()
external {
require(ledger[msg.sender] > 0, INVALID_ADDRESS);
uint holdings = ledger[msg.sender];
uint exitValue = calcBurnReward(holdings);
currentSupply = sub(currentSupply, holdings);
contribute(exitValue, msg.sender);
ledger[msg.sender] = 0;
}
function contribute(uint amount, address sender)
internal {
beneficiary.transfer(amount);
contributions[sender] = add(contributions[sender], amount);
totalContributed = add(totalContributed, amount);
}
function setBuyPrice(uint amount)
public {
uint price = calcMintPrice(amount);
asks[msg.sender] = price;
}
function getPrice()
public view returns (uint) {
return asks[msg.sender];
}
function setSellPrice(uint amount)
public {
uint price = calcBurnReward(amount);
asks[msg.sender] = price;
}
function integrate(uint limitA, uint limitB, uint multiplier)
internal returns (uint) {
uint raiseExp = exponent + 1;
uint _coefficient = wmul(coefficient, multiplier);
uint upper = wdiv((limitB ** raiseExp), raiseExp);
uint lower = wdiv((limitA ** raiseExp), raiseExp);
return wmul(_coefficient, (sub(upper, lower)));
}
function calcMintPrice(uint amount)
internal returns (uint) {
uint newSupply = add(currentSupply, amount);
uint result = integrate(currentSupply, newSupply, precision);
return result;
}
function calcBurnReward(uint amount)
internal returns (uint) {
uint newSupply = sub(currentSupply, amount);
uint result = integrate(newSupply, currentSupply, reserveRatio);
return result;
}
}