Bertani's pre-hackathon prototype of InsurETH, deployed twelve hours before Hack The Block London opened.
Historical Significance
First on-chain deployment of the InsurETH design, by the founder of Oraclize, twelve hours before the team formally presented at Hack The Block London. Together with the September 20 hackathon deployment it forms the earliest peer-to-peer flight insurance product on Ethereum and one of the first production uses of Oraclize callbacks on mainnet.
Context
Deployed during Ethereum's Frontier era, six weeks after mainnet launch. The InsurETH project was widely covered in the wave of post-launch press as a demonstration of insurance primitives on smart contracts, and was the winning entry of the Programmable Assets track at Hack The Block.
Key Facts
Description
InsurETH v1 is the pre-hackathon prototype of the contract that would go on to win the Programmable Assets challenge at Hack The Block during London FinTech Week 2015. It was deployed by Thomas Bertani, founder of the Oraclize oracle service, on September 18, 2015 at block 253556, roughly twelve hours before the hackathon opened. Two days later the hackathon team of Francesco Canessa, Kristina Butkute, and Thomas Bertani deployed the polished v2 at 0x88d675e08b053404209e6b0461a1b648592cfbaa.
The contract implements a peer-to-peer flight-delay insurance market. Users pay a premium via register() to insure a specific flight, supplying an Oraclize formula that queries flight status at arrival time. If the Oraclize callback reports the flight as delayed, the contract pays the user five times the premium. Investors fund the payout pool via invest() and withdraw a proportional share of the pool surplus via deinvest(). The investment_ratio() view function reports investment coverage as a percentage of invested capital relative to the funds at risk, allowing prospective investors to gauge pool capitalization before contributing.
The pool holds at most five concurrent insured flights and reserves five times each user's premium against investor funds to guarantee solvency. The contract uses Oraclize at the hardcoded mainnet address 0x393519c01e80b188d326d461e4639bc0e3f62af0, paid out of the contract's own balance, with arrival-time queries scheduled three hours after the user-supplied scheduled arrival.
Source Verified
Exact creation-bytecode match (init + runtime). Runtime: 2077 bytes. Creation: 2096 bytes (19 bytes init, 0 bytes constructor args). Runtime SHA-256: 762d662dabb3493ca4832e0df558cdd60cf46fe4ed54f2aa88674d806d391272. Creation SHA-256: 61dae5357f55c84e07a4933a303582b66df32d94212d67525475ecec0dccb883. The crack hinged on identifying that the investment_ratio() formula divides invested_total by the at-risk balance (investment coverage ratio), not the inverse; this was diagnosed by symbolic stack analysis of a SWAP/DIV permutation that diverged from the candidate compile.
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 {
address[5] public users_list;
mapping (address => uint) public balances;
address[5] public investors_list;
mapping (address => uint) public investors;
uint public users_list_length;
uint public investors_list_length;
function register(byte[] formula_1a, byte[] flight_number, byte[] formula_3a, byte[] formula_4a, uint arrivaltime) returns (uint){
if (balances[msg.sender] > 0) return;
uint balance_busy = 0;
for (uint k=0; k<users_list_length; k++){
balance_busy += 5*balances[users_list[k]];
}
if (uint(address(this).balance)-balance_busy < 5*uint(msg.value)){ msg.sender.send(msg.value); return; }
OraclizeI oracle = OraclizeI(0x393519c01e80b188d326d461e4639bc0e3f62af0);
oracle.query(arrivaltime+3*3600, msg.sender, formula_1a, flight_number, formula_3a, formula_4a);
balances[msg.sender] = msg.value;
users_list[users_list_length] = msg.sender;
users_list_length++;
}
function __callback(address sender, uint result){
var bal = balances[sender];
delete balances[sender];
if (result > 0) sender.send(5*bal);
for (uint k=0; k<users_list_length; k++){
if (users_list[k] == sender){
users_list[k] = 0x0;
}
}
}
function invest() {
if (investors[msg.sender] == 0){
investors_list[investors_list_length] = msg.sender;
investors_list_length++;
}
investors[msg.sender] += uint(msg.value);
}
function deinvest(){
if (investors[msg.sender] == 0) return;
uint balance_busy = 0;
for (uint k=0; k<users_list_length; k++){
balance_busy += 5*balances[users_list[k]];
}
if (balance_busy > uint(address(this).balance)) return;
uint invested_total = 0;
for (k=0; k<investors_list_length; k++){
invested_total += investors[investors_list[k]];
}
uint gain = investors[msg.sender] / invested_total * (address(this).balance - balance_busy);
msg.sender.send(gain);
investors[msg.sender] = 0;
for (k=0; k<investors_list_length; k++){
if (investors_list[k] == msg.sender) investors_list[k] = 0x0;
}
}
function get() returns (uint){
return balances[msg.sender];
}
function get_user(address user) returns (uint){
return balances[user];
}
function investment_ratio() returns (uint){
uint insured_customers_funds = 0;
for (uint k=0; k<users_list_length; k++){
insured_customers_funds += 5*balances[users_list[k]];
}
uint invested_total = 0;
for (k=0; k<investors_list_length; k++){
invested_total += investors[investors_list[k]];
}
uint ratio = invested_total / (uint(address(this).balance) - insured_customers_funds) * 100;
return ratio;
}
}