Kieran Elby's redesigned successor throne, deployed Feb 6, 2016 — three hours after the v0.3.0 throne fell silent in what he later called the 'Turbulent Age' tr
Historical Significance
The first attempt to patch the gas-stipend bug that broke its predecessor. v0.4.0 was deployed under time pressure during the Turbulent Age and only partially fixed the issue — the same .send() pattern remained in the compensation payment, so Mist-wallet monarchs continued to lose compensation. The eventual proper fix (call.value with manual gas) and the v1.0 rewrite were both downstream consequences of the bug Kieran first encountered on this contract.
Key Facts
Description
King of the Ether Throne v0.4.0 is the redesigned successor to the original v0.3.0 throne (0xa9d160e3), deployed on February 6, 2016 (block 963,186) during the 'Turbulent Age' (Feb 6–8, 2016) — the period when the original v0.3.0 throne stopped paying compensation to monarchs whose addresses required more than 2,300 gas to receive ether. Kieran Elby deployed v0.4.0 about three hours after the v0.3.0 send() bug was discovered, attempting a fix-and-improve revision.
Notable changes from v0.3.0:
• Starting claim price raised from 10 finney (0.01 ETH) to 100 finney (0.1 ETH).
• No accumulatedWizardPayments slot — wizard now sweeps commission directly via sweepCommission(uint amount) rather than from an accumulating balance.
• No 12-monarch limit — anyone can become king as long as the throne is active.
• transferOwnership(address) added so the wizard role can be reassigned.
• Two-significant-figure rounding of next claim price across tiers (0.001, 0.01, 0.1, 1, 10, 100, 1000 ETH) so prices don't accrue silly trailing decimals.
Ironically, v0.4.0 does NOT fully fix the send() bug — currentMonarch.etherAddress.send(compensation) still uses the default 2,300 gas stipend, so Mist-style contract wallets would still fail to receive their compensation. The proper fix didn't land until commit 120f5a26 (Feb 21, 2016) and the v1.0 rewrite.
The contract author references this exact contract address in the v0.4.0 source comment: '// This contract lives on the blockchain at 0xb336a86e2feb1e87a328fcb7dd4d04de3df254d0'.
Source Verified
Byte-for-byte runtime match (2,109 bytes) and creation match. Source published by author Kieran Elby in the KingOfTheEtherThrone GitHub repo at commit 6d77929 ('Bump to new contract', Feb 6 2016 16:23 UTC — eleven minutes after deployment). The source as committed defines sweepCommission before transferOwnership, but the deployed bytecode requires the opposite order; Kieran appears to have cosmetically swapped the two functions in the source after deploying. With the function order restored to deployment order, the source compiles to an exact byte-for-byte match using soljson v0.2.1-nightly.2016.2.3+commit.fad2d4df with optimizer ON. Verification repo: https://github.com/cartoonitunes/koth-v04-verification
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Frontier Era
The initial release of Ethereum. A bare-bones implementation for technical users.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
// 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?
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 transferOwnership(address newOwner) onlywizard {
wizardAddress = newOwner;
}
// Used only by the wizard to collect his commission.
function sweepCommission(uint amount) onlywizard {
wizardAddress.send(amount);
}
}