Winning entry of the Programmable Assets challenge at Hack The Block London (September 2015), built by Francesco Canessa, Kristina Butkute, and Thomas Bertani (
Historical Significance
The first on-chain flight-delay insurance contract, predating Etherisc's FlightDelay rewrite by roughly a year. Demonstrated a self-contained insurance market with oracle-driven payouts and an investor pool, all on Frontier-era Solidity (v0.1.1). Co-built by Thomas Bertani, founder of Oraclize (now Provable), the dominant Ethereum oracle service of that era. The team cited UK Civil Aviation Authority data showing 558,000 passengers had not claimed delay compensation in the 12 months to May 2015 as their motivation.
Context
Deployed September 20, 2015 at block 262,936, just under two months after Ethereum mainnet launched on July 30, 2015. The Frontier era had no standard library, no require()/revert(), and Solidity v0.1.1 was the latest compiler. Hack The Block was sponsored by Lloyds Banking Group, IBM, and Thomson Reuters and was one of the earliest international Ethereum hackathons. The other winning team, Issuefficient, presented an IPO-streamlining concept; runner-up entries included Blockathon Swaps and SmartBond.
Key Facts
Description
InsurETH is a peer-to-peer flight-delay insurance contract deployed during the Frontier era. A user calls register() with a flight identifier, an arrival time, and a premium in ETH; the contract submits two queries to Oraclize for the actual arrival time and, on a confirmed delay, pays out five times the premium from a pool funded by separate invest()/deinvest() participants.
The contract holds at most five concurrent insured flights, enforces a two-day registration cutoff before scheduled arrival, and reserves five times each user's premium against the investor pool to guarantee solvency. Investors share gains proportionally to their stake when they call deinvest(). Oraclize callbacks are routed through a sender check in the fallback function.
The contract was the winning entry of the Programmable Assets challenge (a £1,000 prize) at the two-day Hack The Block hackathon held at Thomson Reuters' Canary Wharf headquarters during London FinTech Week.
Source Verified
Exact bytecode match. Init: 19 bytes. Runtime: 2894 bytes. Creation total: 2913 bytes. Compiler: soljson v0.1.1 with optimizer enabled. Source recovered from the bertani/insurETH GitHub repository with one function reordering (deinvest moved above register) — Kristina Butkute committed a 'layout from insureth air' rearrangement four days post-deploy that did not match the deployed bytecode emission order. Init terminator f3 00 confirms v0.1.1 over v0.1.2 (which uses f3 only).
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)
// Copyright (C) 2015 Thomas Bertani - Oraclize srl
// https://www.oraclize.it/service/api
contract OraclizeI {
function query(uint timestamp, byte[] formula_1, byte[] formula_2, byte[] formula_3, byte[] formula_4){}
function query(uint timestamp, address param, byte[] formula_1, byte[] formula_2, byte[] formula_3, byte[] formula_4){}
}
contract Insurance {
event Log(uint k);
address[5] public users_list;
uint public users_list_length;
mapping (address => uint) public users_balance;
address[5] public investors_list;
uint public investors_list_length;
mapping (address => uint) public investors_invested;
function RETURN(){
msg.sender.send(msg.value);
}
function(){
if (msg.sender == address(0x26588a9301b0428d95e6fc3a5024fce8bec12d51)) callback();
}
function deinvest(){
if (investors_invested[msg.sender] == 0) return;
uint balance_busy = 0;
for (uint k=0; k<users_list_length; k++){
balance_busy += 5*users_balance[users_list[k]];
}
uint invested_total = 0;
for (k=0; k<investors_list_length; k++){
invested_total += investors_invested[investors_list[k]];
}
uint gain = investors_invested[msg.sender] / invested_total * (uint(address(this).balance) - balance_busy);
if (gain > uint(address(this).balance)-balance_busy) return;
msg.sender.send(gain);
investors_invested[msg.sender] = 0;
for (k=0; k<investors_list_length; k++){
if (investors_list[k] == msg.sender) investors_list[k] = 0x0;
}
}
function register(byte[] formula_1a, byte[] flight_number, byte[] formula_3a, byte[] formula_4a, byte[] formula_4b, uint arrivaltime){
if (uint(msg.value) == 0) return;
if (now > arrivaltime-2*24*3600){ RETURN(); return; }
if (users_list_length > 4){ RETURN(); return; }
if (users_balance[msg.sender] > 0){ RETURN(); return; }
uint balance_busy = 0;
for (uint k=0; k<users_list_length; k++){
balance_busy += 5*users_balance[users_list[k]];
}
if (uint(address(this).balance)-balance_busy < 5*uint(msg.value)){ RETURN(); return; }
OraclizeI oracle = OraclizeI(0x393519c01e80b188d326d461e4639bc0e3f62af0);
oracle.query(arrivaltime+3*3600, msg.sender, formula_1a, flight_number, formula_3a, formula_4a);
uint160 sender_b = uint160(msg.sender);
oracle.query(arrivaltime+3*3600, address(++sender_b), formula_1a, flight_number, formula_3a, formula_4b);
delete users_balance[msg.sender];
users_balance[msg.sender] = msg.value;
users_list[users_list_length] = msg.sender;
users_list_length++;
}
function callback(){
uint160 sender_;
for (uint j=0; j<20; j++){
sender_ *= 256;
sender_ += uint160(msg.data[j]);
}
address sender = address(sender_);
uint sender_b_ = uint160(sender);
sender_b_--;
address sender_b = address(sender_b_);
uint status = 0;
if (users_balance[sender_b] > 0){
status = 1;
uint balance = users_balance[sender_b];
delete users_balance[sender_b];
} else {
delete users_balance[sender];
}
if ((users_balance[sender_b] > 0)&&(status == 1)) sender.send(balance*5);
for (uint k=0; k<users_list_length; k++){
if ((users_list[k] == sender)||(users_list[k] == sender_b)){
users_list[k] = 0x0;
}
}
}
function invest() {
if (investors_invested[msg.sender] == 0){
investors_list[investors_list_length] = msg.sender;
investors_list_length++;
}
investors_invested[msg.sender] += uint(msg.value);
}
function get() returns (uint){
return users_balance[msg.sender];
}
function get_user(address user) returns (uint){
return users_balance[user];
}
function investment_ratio() returns (uint){
uint insured_customers_funds = 0;
for (uint k=0; k<users_list_length; k++){
insured_customers_funds += users_balance[users_list[k]];
}
uint invested_total = 0;
for (k=0; k<investors_list_length; k++){
invested_total += investors_invested[investors_list[k]];
}
uint ratio = 100 * ((uint(address(this).balance) - insured_customers_funds)/invested_total);
return ratio;
}
}