forked from crytic/not-so-smart-contracts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
KingOfTheEtherThrone.sol
170 lines (140 loc) · 6.39 KB
/
KingOfTheEtherThrone.sol
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
// A chain-game contract that maintains a 'throne' which agents may pay to rule.
// See www.kingoftheether.com & https://github.com/kieranelby/KingOfTheEtherThrone .
// (c) Kieran Elby 2016. All rights reserved.
// v0.4.0.
// Inspired by ethereumpyramid.com and the (now-gone?) "magnificent bitcoin gem".
// This contract lives on the blockchain at 0xb336a86e2feb1e87a328fcb7dd4d04de3df254d0
// and was compiled (using optimization) with:
// Solidity version: 0.2.1-fad2d4df/.-Emscripten/clang/int linked to libethereum
// For future versions it would be nice to ...
// TODO - enforce time-limit on reign (can contracts do that without external action)?
// TODO - add a random reset?
// TODO - add bitcoin bridge so agents can pay in bitcoin?
// TODO - maybe allow different return payment address?
pragma solidity ^0.4.19;
contract KingOfTheEtherThrone {
struct Monarch {
// Address to which their compensation will be sent.
address etherAddress;
// A name by which they wish to be known.
// NB: Unfortunately "string" seems to expose some bugs in web3.
string name;
// How much did they pay to become monarch?
uint claimPrice;
// When did their rule start (based on block.timestamp)?
uint coronationTimestamp;
}
// The wizard is the hidden power behind the throne; they
// occupy the throne during gaps in succession and collect fees.
address wizardAddress;
// Used to ensure only the wizard can do some things.
modifier onlywizard { if (msg.sender == wizardAddress) _; }
// How much must the first monarch pay?
uint constant startingClaimPrice = 100 finney;
// The next claimPrice is calculated from the previous claimFee
// by multiplying by claimFeeAdjustNum and dividing by claimFeeAdjustDen -
// for example, num=3 and den=2 would cause a 50% increase.
uint constant claimPriceAdjustNum = 3;
uint constant claimPriceAdjustDen = 2;
// How much of each claimFee goes to the wizard (expressed as a fraction)?
// e.g. num=1 and den=100 would deduct 1% for the wizard, leaving 99% as
// the compensation fee for the usurped monarch.
uint constant wizardCommissionFractionNum = 1;
uint constant wizardCommissionFractionDen = 100;
// How much must an agent pay now to become the monarch?
uint public currentClaimPrice;
// The King (or Queen) of the Ether.
Monarch public currentMonarch;
// Earliest-first list of previous throne holders.
Monarch[] public pastMonarchs;
// Create a new throne, with the creator as wizard and first ruler.
// Sets up some hopefully sensible defaults.
function KingOfTheEtherThrone() {
wizardAddress = msg.sender;
currentClaimPrice = startingClaimPrice;
currentMonarch = Monarch(
wizardAddress,
"[Vacant]",
0,
block.timestamp
);
}
function numberOfMonarchs() constant returns (uint n) {
return pastMonarchs.length;
}
// Fired when the throne is claimed.
// In theory can be used to help build a front-end.
event ThroneClaimed(
address usurperEtherAddress,
string usurperName,
uint newClaimPrice
);
// Fallback function - simple transactions trigger this.
// Assume the message data is their desired name.
function() {
claimThrone(string(msg.data));
}
// Claim the throne for the given name by paying the currentClaimFee.
function claimThrone(string name) {
uint valuePaid = msg.value;
// If they paid too little, reject claim and refund their money.
if (valuePaid < currentClaimPrice) {
msg.sender.send(valuePaid);
return;
}
// If they paid too much, continue with claim but refund the excess.
if (valuePaid > currentClaimPrice) {
uint excessPaid = valuePaid - currentClaimPrice;
msg.sender.send(excessPaid);
valuePaid = valuePaid - excessPaid;
}
// The claim price payment goes to the current monarch as compensation
// (with a commission held back for the wizard). We let the wizard's
// payments accumulate to avoid wasting gas sending small fees.
uint wizardCommission = (valuePaid * wizardCommissionFractionNum) / wizardCommissionFractionDen;
uint compensation = valuePaid - wizardCommission;
if (currentMonarch.etherAddress != wizardAddress) {
currentMonarch.etherAddress.send(compensation);
} else {
// When the throne is vacant, the fee accumulates for the wizard.
}
// Usurp the current monarch, replacing them with the new one.
pastMonarchs.push(currentMonarch);
currentMonarch = Monarch(
msg.sender,
name,
valuePaid,
block.timestamp
);
// Increase the claim fee for next time.
// Stop number of trailing decimals getting silly - we round it a bit.
uint rawNewClaimPrice = currentClaimPrice * claimPriceAdjustNum / claimPriceAdjustDen;
if (rawNewClaimPrice < 10 finney) {
currentClaimPrice = rawNewClaimPrice;
} else if (rawNewClaimPrice < 100 finney) {
currentClaimPrice = 100 szabo * (rawNewClaimPrice / 100 szabo);
} else if (rawNewClaimPrice < 1 ether) {
currentClaimPrice = 1 finney * (rawNewClaimPrice / 1 finney);
} else if (rawNewClaimPrice < 10 ether) {
currentClaimPrice = 10 finney * (rawNewClaimPrice / 10 finney);
} else if (rawNewClaimPrice < 100 ether) {
currentClaimPrice = 100 finney * (rawNewClaimPrice / 100 finney);
} else if (rawNewClaimPrice < 1000 ether) {
currentClaimPrice = 1 ether * (rawNewClaimPrice / 1 ether);
} else if (rawNewClaimPrice < 10000 ether) {
currentClaimPrice = 10 ether * (rawNewClaimPrice / 10 ether);
} else {
currentClaimPrice = rawNewClaimPrice;
}
// Hail the new monarch!
ThroneClaimed(currentMonarch.etherAddress, currentMonarch.name, currentClaimPrice);
}
// Used only by the wizard to collect his commission.
function sweepCommission(uint amount) onlywizard {
wizardAddress.send(amount);
}
// Used only by the wizard to collect his commission.
function transferOwnership(address newOwner) onlywizard {
wizardAddress = newOwner;
}
}