ligo/gitlab-pages/docs/reference/current.md
2020-02-25 05:13:25 -08:00

7.5 KiB

id title
current-reference Current - Things relating to the current execution context

Current.balance() : tez

Get the balance for the contract.

function main (const p : unit; const s: tez) : list(operation) * storage is
  ((nil : list(operation)), balance)
let main (p, s : unit * storage) =
  ([] : operation list), balance
let main = (p: unit, storage) => ([]: list(operation), balance);

Current.time() : timestamp

Returns the current time as a unix timestamp.

In LIGO, timestamps are type compatible in operations with int(s). This lets you set e.g. time constraints for your smart contracts like this:

Examples

24 hours from now

const today: timestamp = now;
const one_day: int = 86400;
const in_24_hrs: timestamp = today + one_day;
const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp);
const one_day_later: timestamp = some_date + one_day;
let today: timestamp = Current.time
let one_day: int = 86400
let in_24_hrs: timestamp = today + one_day
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp)
let one_day_later: timestamp = some_date + one_day
let today: timestamp = Current.time;
let one_day: int = 86400;
let in_24_hrs: timestamp = today + one_day;
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp);
let one_day_later: timestamp = some_date + one_day;

24 hours ago

const today: timestamp = now;
const one_day: int = 86400;
const in_24_hrs: timestamp = today - one_day;
let today: timestamp = Current.time
let one_day: int = 86400
let in_24_hrs: timestamp = today - one_day
let today: timestamp = Current.time;
let one_day: int = 86400;
let in_24_hrs: timestamp = today - one_day;

Comparing timestamps

You can also compare timestamps using the same comparison operators as for numbers:

const not_tommorow: bool = (now = in_24_hrs)
let not_tomorrow: bool = (Current.time = in_24_hrs)
let not_tomorrow: bool = (Current.time == in_24_hrs);

Current.amount() : tez

Get the amount of tez provided by the sender to complete this transaction.

function check (const p: unit) : int is
  begin
    var result : int := 0;
    if amount = 100tz then
      result := 42
    else
      result := 0
  end with result
let check_ (p: unit) : int = if Current.amount = 100tz then 42 else 0
let check_ = (p: unit) : int =>
  if (Current.amount == 100tz) {
    42;
  }
  else {
    0;
  };

Current.sender() : address

Get the address that initiated the current transaction.

function main (const p: unit) : address is sender
let main (p: unit) : address = Current.sender
let main = (p: unit) : address => Current.sender;

Current.address(c: a' contract) : address

Get the address associated with a contract.

function main (const p : key_hash) : address is block {
  const c : contract(unit) = implicit_account(p) ;
} with address(c)
let main (p : key_hash) =
  let c : unit contract = Current.implicit_account p in 
  Current.address c
let main = (p : key_hash) : address => {
  let c : contract(unit) = Current.implicit_account(p) ;
  Current.address(c) ;
};

Current.self_address() : address

Get the address of the currently running contract.

function main (const p: unit) : address is self_address
let main (p: unit) : address = Current.self_address 
let main = (p: unit): address => Current.self_address;

Current.implicit_account(p: key_hash) : a' contract

Get the default contract associated with an on-chain keypair. This contract doesn't execute code, instead it exists to receive money on behalf of a keys owner.

function main (const kh: key_hash) : contract(unit) is implicit_account(kh)
let main (kh: key_hash) : unit contract = Current.implicit_account kh
let main = (kh: key_hash): contract(unit) => Current.implicit_account(kh);

Current.source() : address

Get the originator of the current transaction. That is, if a chain of transactions led to the current execution get the address that began the chain. Not to be confused with Current.sender, which gives the address of the contract or user which directly caused the current transaction.

⚠️ There are a few caveats you should keep in mind before using SOURCE over SENDER:

  1. SOURCE will never be a contract, so if you want to allow contracts (multisigs etc) to operate your contract, you need to use SENDER
  2. https://vessenes.com/tx-origin-and-ethereum-oh-my/ -- in general it is somewhat unsafe to assume that SOURCE understands everything that's going to happen in a transaction. If SOURCE transfers to a malicious (or sufficiently attackable) contract, that contract might potentially transfer to yours, without SOURCE's consent. So if you are using SOURCE for authentication, you risk being confused. A good historical example of this is bakers paying out delegation rewards. Naive bakers did (and probably still do) just use tezos-client to transfer to whatever KT1 delegates they had, even if those KT1 were malicious scripts.
function main (const p: unit) : address is source
let main (p: unit) : address = Current.source
let main = (p: unit) : address => Current.source;

Current.failwith(error_message: string) : a'

Cause the contract to fail with an error message.

⚠ Using this currently requires a type annotation on the failwith to unify it with the type of whatever other code branch it's on.

function main (const p : param; const s : unit) : list(operation) * unit is
  block {
    case p of
    | Zero (n) -> if n > 0n then failwith("fail") else skip
    | Pos (n) -> if n > 0n then skip else failwith("fail")
    end
  }
  with ((nil : list(operation)), s)
let main (p: unit) storage =
  if true then failwith "This contract always fails" else ()
let main = (p: unit, storage) =>
  if (true) {
    failwith("This contract always fails");
  } else {
    ();
  };