Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ligo version #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions FLOOD_INSURANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

## Example use case

Suppose we wanted to create a smart contract to insure against
flooding.

Furthermore, suppose an instance of this oracle exists that
accepts physical locations and returns a `string`: `FLOODED` or `NOT_FLOODED`.

Then our insurance contract can take the following form:

Storage:
- `oracle_address : address`: The `address` of the priced event oracle
- `oracle_price : mutez`: The `price` of the priced event oracle
- `premium : mutez`: The cost per `period` to be insured
- `payout : mutez`: The amount paid out in case of a flood
- `period : nat`: The amount of time (in seconds) that you're covered for per payment of the `premium`
- `policyholders : big_map address (pair (pait timestamp (bool %paid_out)) string)`
+ `address`: The policyholder
+ `timestamp`: The last time the `premium` was paid
+ `bool`: Has this policyholder already made a claim this `period`?
+ `string`: The policyholder's location
- `claim_counter : nat`: The number of claims already made
- `current_claim : option (pair address string)`:
The `address` and location `string` of the policyholder currently making a claim

Parameters:
- `(string %pay_premium)`:
+ The `string` is the policyholder's location: it will be updated if it already exists
+ Accept only the exact `premium` amount in Tez (or fail)
+ Updates the `timestamp` for the `policyholder` to `NOW`
+ Resets the `bool` to `false` (there hasn't been a claim yet)
+ Fails if the contract has insufficient balance to pay out a claim
- `(unit %make_claim)`
+ Fails if the `SENDER` `address` is not a known `policyholder`
+ Fails if a claim is already being made
+ Fails if the policyholder has not paid the premium within `period` seconds
of the `timestamp`
+ Fails if the policyholder has already successfully made a claim this `period`, i.e. if the `paid_out` `bool` is `true`
+ Fails if the `oracle_price` in Tez is not sent by the user
+ Sets the `current_claim` to the `address` and location `string` of the
policyholder currently making a claim
+ Calls the _priced event oracle_ with the policyholder's location `string` and
the `confirm_claim` entrypoint of this contract and pays the `oracle_price`
- `(pair %confirm_claim string nat)`
+ Fails if a `current_claim` is `None`, i.e. we are not expecting a confirmation from the oracle
+ Fails if the `SENDER` is not the stored `oracle_address`
+ Fails if the `nat` is not the current `claim_counter`
+ Increments the `claim_counter` by one
+ If the `string` equals `FLOODED`, it sends the `payout` amount to the policyholder's `address` and
the policyholder's `paid_out` `bool` to `true`
+ Sets the `current_claim` to `None`

### User flow

1. A user pays the `premium` for first time by sending their location `string`
and the correct amount of Tez to the contract
2. The user makes a claim by calling the `make_claim` entrypoint with the fee for the oracle
3. The insurance contract calls the priced event oracle's `ask` entrypoint with the user's location `string`
4. The priced event oracle consumes the `query` and the oracle's host calculates the result `string`: `FLOODED` or `NOT_FLOODED`
5. The oracle's host calls `confirm_claim` with the result `string` and `counter`: the user is paid if its `FLOODED`


62 changes: 62 additions & 0 deletions distribution_sink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

~/C/m/priced-event-oracle ❯❯❯ tezos-client --wait none originate contract DistributionSink \ $
transferring 0 from tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8 running \
"$(cat distribution_sink.tz | tr -d '\n')" --burn-cap 1
Waiting for the node to be bootstrapped...
Current head: BLBSxwMhYe8H (timestamp: 2021-03-25T20:41:07.000-00:00, validation: 2021-03-25T20:41:09.974-00:00)
Node is bootstrapped.
Estimated gas: 1620.274 units (will add 100 for safety)
Estimated storage: 303 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'ooxkNGaiBYxPPfairb8mf2q71zwhGDnQ7Kb5A8gUek6z8uUDPYE'
NOT waiting for the operation to be included.
Use command
tezos-client wait for ooxkNGaiBYxPPfairb8mf2q71zwhGDnQ7Kb5A8gUek6z8uUDPYE to be included --confirmations 30 --branch BLBSxwMhYe8HvBgGzoRoYUwk3ASrjgyCoFQNtqQ8784QB6xUfkJ
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
Manager signed operations:
From: tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8
Fee to the baker: ꜩ0.000359
Expected counter: 323895
Gas limit: 1000
Storage limit: 0 bytes
Balance updates:
tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8 ................. -ꜩ0.000359
fees(the baker who will include this operation,56) ... +ꜩ0.000359
Revelation of manager public key:
Contract: tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8
Key: edpkukGE7x3P4U3VR3rN59yAkvj7LmMtq42HcVsrGngz6zLoFgvZxj
This revelation was successfully applied
Consumed gas: 1000
Manager signed operations:
From: tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8
Fee to the baker: ꜩ0.000352
Expected counter: 323896
Gas limit: 1721
Storage limit: 323 bytes
Balance updates:
tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8 ................. -ꜩ0.000352
fees(the baker who will include this operation,56) ... +ꜩ0.000352
Origination:
From: tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8
Credit: ꜩ0
Script:
{ parameter (list (pair nat (list address))) ;
storage unit ;
code { CDR ; NIL operation ; PAIR } }
Initial storage: Unit
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1B9seWkK5o5kyuSLNDPWMbKXNKq7y3aZvc
Storage size: 46 bytes
Paid storage size diff: 46 bytes
Consumed gas: 1620.274
Balance updates:
tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8 ... -ꜩ0.0115
tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8 ... -ꜩ0.06425

New contract KT1B9seWkK5o5kyuSLNDPWMbKXNKq7y3aZvc originated.
Contract memorized as DistributionSink.


3 changes: 3 additions & 0 deletions distribution_sink.tz
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parameter (list (pair nat (list address)));
storage unit;
code {CDR; NIL operation; PAIR}
10 changes: 10 additions & 0 deletions ligo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

An implementation of `user_contract.tz` in LIGO.

Compile with:

```bash
docker run --rm -v "$PWD":"$PWD" -w "$PWD" ligolang/ligo:0.19.0 compile-contract \
--syntax=cameligo --output=ligo_user_contract.tz user_contract.ligo.ml main
```

85 changes: 85 additions & 0 deletions ligo/ligo_user_contract.tz
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{ parameter (or (unit %ask) (pair %respond bytes nat)) ;
storage
(pair (pair (nat %counter) (address %owner)) (pair (bytes %response) (bool %waiting))) ;
code { SELF %respond ;
SWAP ;
UNPAIR ;
IF_LEFT
{ DROP ;
DUP ;
CAR ;
CDR ;
SENDER ;
COMPARE ;
EQ ;
IF { PUSH bool True ;
SWAP ;
DUP ;
DUG 2 ;
CDR ;
CAR ;
PAIR ;
SWAP ;
CAR ;
PAIR ;
NIL operation ;
PUSH address "KT1VcDH6SWd3QAWZf3M1DuD4i7zqtZq8CXSa%ask" ;
CONTRACT (pair (contract (pair bytes nat)) string) ;
IF_NONE
{ DIG 2 ; DROP ; PUSH string "oracle not found" ; FAILWITH }
{ PUSH mutez 1 ;
PUSH string
"query=AirTemperatureData[Entity[\\\"City\\\", {\\\"NewYork\\\", \\\"NewYork\\\", \\\"UnitedStates\\\"}]]&precision=auto&unit=metric" ;
DIG 5 ;
PAIR ;
TRANSFER_TOKENS } ;
CONS ;
PAIR }
{ DROP 2 ; PUSH string "only admin may update" ; FAILWITH } }
{ DIG 2 ;
DROP ;
SWAP ;
DUP ;
DUG 2 ;
CDR ;
CDR ;
IF { PUSH address "tz1drDkC2hJk1pzyMuqbDpvB3HeRVmVJRL2E" ;
SENDER ;
COMPARE ;
EQ ;
IF { UNPAIR ;
DUP 3 ;
CAR ;
CAR ;
DIG 2 ;
COMPARE ;
EQ ;
IF { PUSH bool False ;
DUP 3 ;
CDR ;
CAR ;
PAIR ;
DUP 3 ;
CAR ;
PAIR ;
DUP ;
CDR ;
CDR ;
DIG 2 ;
PAIR ;
SWAP ;
CAR ;
CDR ;
PUSH nat 1 ;
DIG 3 ;
CAR ;
CAR ;
ADD ;
PAIR ;
PAIR ;
NIL operation ;
PAIR }
{ DROP 2 ; PUSH string "unexpected counter" ; FAILWITH } }
{ DROP 2 ; PUSH string "not responder" ; FAILWITH } }
{ DROP 2 ; PUSH string "not waiting" ; FAILWITH } } } }

63 changes: 63 additions & 0 deletions ligo/user_contract.ligo.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

let oracle_address : address =
("KT1VcDH6SWd3QAWZf3M1DuD4i7zqtZq8CXSa%ask" : address)

let responder_address : address =
("tz1drDkC2hJk1pzyMuqbDpvB3HeRVmVJRL2E" : address)

let query_string : string =
"query=AirTemperatureData[Entity[\"City\", {\"NewYork\", \"NewYork\", \"UnitedStates\"}]]&precision=auto&unit=metric"

let oracle_price : tez = 1mutez


type response = bytes * nat

let self_response_ref : response contract = Tezos.self "%respond"

type parameter_type =
Ask
| Respond of response

type storage_type =
{
owner : address;
waiting : bool;
response : bytes;
counter : nat;
}

type return = operation list * storage_type

let ask (_u : unit) : operation =
match (Tezos.get_contract_opt (oracle_address): ((response contract * string) contract) option) with
Some contract_ref ->
Tezos.transaction (self_response_ref, query_string) oracle_price contract_ref
| None -> (failwith ("oracle not found") : operation)

let main (parameter, storage : parameter_type * storage_type) : return =
match parameter with
| Ask ->
if (Tezos.sender = storage.owner) then
([ask ()],
{ storage with waiting = true })
else
(failwith "only admin may update" : return)

| Respond res ->
if storage.waiting
then if (Tezos.sender = responder_address)
then
let (response_bytes, response_counter) = res in
if (response_counter = storage.counter)
then
(([] : operation list),
{ storage with
waiting = false;
response = response_bytes;
counter = storage.counter + 1n
})
else (failwith "unexpected counter" : return)
else (failwith "not responder" : return)
else (failwith "not waiting" : return)

68 changes: 68 additions & 0 deletions ping_oracle.tz
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
parameter (or (unit %ask)
(pair %respond string
nat));
storage (pair (bool %waiting)
(pair (string %response)
(nat %counter)));
code { DUP;
CAR;
DIP { CDR };
IF_LEFT { DROP;
DUP;
CAR;
DIP { CDR };
IF { PUSH string "waiting";
FAILWITH }
{ SENDER;
PUSH address "tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8";
COMPARE;
EQ;
IF { PUSH address "tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8";
CONTRACT (pair (contract (pair string nat)) string);
IF_NONE { PUSH string "oracle not found";
FAILWITH }
{ SWAP;
DIP { PUSH string "some_query";
SELF %respond;
PAIR;
PUSH mutez 10;
SWAP;
TRANSFER_TOKENS };
PUSH bool True;
PAIR;
SWAP;
NIL operation;
SWAP;
CONS } }
{ PUSH string "not owner";
FAILWITH } } }
{ SWAP;
DUP;
CAR;
DIP { CDR };
IF { SENDER;
PUSH address "tz1QS8VYYVDjv7iReBzXeheL6x63A1oATTj8";
COMPARE;
EQ;
IF { CDR;
SWAP;
DUP;
CAR;
DIP { CDR;
DUP;
PUSH nat 1;
ADD;
DIP { COMPARE;
EQ;
IF { }
{ PUSH string "unexpected counter";
FAILWITH } } };
PAIR;
PUSH bool False;
PAIR;
NIL operation }
{ PUSH string "not responder";
FAILWITH } }
{ PUSH string "not waiting";
FAILWITH } };
PAIR };
Loading