Sword-Smith / Sword

Sword — A financial derivative language for the blockchain
MIT License
29 stars 2 forks source link
blockchain derivatives ethereum

The Sword Financial Contract Language

Sword is a declarative language for expressing fully-collateralized financial contracts. It distinguishes itself from other financial contract languages by being adapted to the blockchain.

WARNING: This is highly experimental software. Use at your own risk.

Nomenclature

Example

A bet based on the value of an oracle can be formulated as

if obs(bool, <oracle-address>, <oracle-index>) within days(1) then
    transfer(<dai-address>, 1)
else
    transfer(<dai-address>, 2)

In this contract, holders of party token 1 will receive 1 DAI unit (1e-18 DAI) per party token of ID 1 that they hold if the oracle returns true at any point within 1 day from activation. Otherwise, holders of party token 2 will receive this payout. If you prefer that each position instead pays out 1 DAI, this can be achieved by

scale(1e18, 1e18,
    if obs(bool, <oracle-address>, <oracle-index>) within days(1) then
        transfer(<dai-address>, 1)
    else
        transfer(<dai-address>, 2)
)

where the 2nd argument to scale represents the expression with which the amount of all contained transfers are multiplied, and the 1st argument to scale represent a upper bound to this expression.

Entrypoints

Entrypoints for the Derivative Logic

Party Token IDs

Each transfer as specified in the grammar has an ID as the 2nd argument. This 2nd argument maps directly to the tokenID as specified in the ERC1155 standard. Each ID in a transfer construct must be unique and the IDs must go from 1 to N where N is the number of transfer constructs in the contract. All these IDs are created upon activation in an equal amount. More can be created or destroyed later through calls to mint and burn as specified above.

A special party token with tokenID = 0 is also created and burned in the same amounts as the other tokenIDs. This tokenID = 0 represents positions that get the collateral refunds. If we for example consider the contract below and we imagine that the datafeed-address returns a value of 10 for its datafeed-index, then the payout evaluates to 10 for tokenID = 1 and a holder of party token 1 would receive 10 * balance(party-token-1) when they call pay. But the collateral of the contract is 20 as specified in the 1st argument to scale, so the derivative contract would be left with 10 DAI for each unit of its total party token supply. To ensure that all contracts always payout their full collateral when all party token owners have invoked pay, tokenID = 0 is introduced and it is minted and burned along with the other party tokens. And payouts to party token 0 owners also happen when they call pay.

scale(20, obs(int, <datafeed-address>, <datafeed-index>), transfer(<DAI-address>, 1))

With the additional (impplicit) party token ID 0, this contract becomes

both(
    scale(20, obs(int, <datafeed-address>, <datafeed-index>), transfer(<DAI-address>, 1)),
    scale(20, 20 - obs(int, <datafeed-address>, <datafeed-index>), transfer(<DAI-address>, 0))
)

This way, the existence of tokenID = 0 ensures that no funds are left on the derivative contract after maturity. At the moment party token 0 are always minted even though they in some cases never will receive a payout. It is the goal of this project to only mint party token 0 when they are needed.

Description

The derivatives work as fully-collateralized financial contracts where the derivative contract holds the settlement assets until the contract reaches maturity and the funds can be paid out to the involved parties. The parties are identified by the ownership of ERC1155 tokens. The ERC1155 assets are minted by depositing settlement assets (most likely a stablecoin) in the DC and party tokens are then paid to the minter in return. The minter can then sell some or all of their party tokens at an exchange that handles ERC1155 tokens. The minter would call approve on the settlement asset smart contract (e.g. DAI) and then call activate or mint on the DC as described above. The number of tokens in the ERC1155 PT contract is equal to the number of parties in the DSL definition of the derivative contract plus one to receive any collateral that was not paid out during evaluation of the other positions. The total supply of all party tokens will be the same as long as the contract is not partially matured since they are all always minted and burned by the same amount.

Grammar of Sword

contracts:
c ::= scale(nsc,e,c1) | zero | both(c1,c2) |
      transfer(a, n) | translate(t,c1) |
      if e within t1
      then c1 else c2

expressions:
e ::= nsc | obs(ot, f, n) | e1 op e2 | uop e1

time:
t ::= now | u(nsc)

time unit:
u ::= seconds | minutes | hours | days | weeks

operators:
op ::= + | - | x | / | = | if | or | and
uop ::=  not

operator types:
ot ::= int | bool

where

More Examples

All payouts happen when an owner of the party token calls the endpoint pay().

Basic Constructs

First some simple examples that cover all the language elements.

European put option, an Insurance Against a Drop in the ETH price

Scenario: A owns 1 ETH and A would like an insurance of a drop in the ETH price below 600 EUR three months from now. So A would like a contract whose value plus the value of an ether is at least 600 EUR. This can be achieved by the following contract:

translate(
   days(90),
   scale(
      600,
      max(0, 600 - obs(int, priceFeed, ETHUSD))
      transfer(DAI, A )))

If the ETH price at the strike time is 500 EUR, then this contract will pay out 100 EUR, thus guaranteeing A a value of 600 EUR at the maturity of the contract. DAI is the address of an ERC20-complaint token.

Note that the first parameter to the scale function (defining the token amount to lock in escrow) is important when the second parameter (the token amount) can depend on external information. Without the tokens in escrow, we would have no guarantee that the derivative would have the liquidity needed at excecution time.

Installation

git, stack, ghc

Development

Sword, the language, is inspired by the work of Peyton-Jones et al. (2000) (ref), as well as Bahr et al. (2015) (ref).

Several attempts to create a domain-specific language to represent financial contracts have run into the same two issues: negative balances and poor liquidity of the financial contracts, in part caused by high transaction fees.

Competition

The Findel contract language and execution environment faced the problem of negative balances, high gas cost, and poor liquidity. Findel's execution environment was not deployed (ref), and has not been actively developed on since 2017 (ref).

The Lira contract language, a predecessor to Sword sponsored by eToroX Labs, solved the problem of negative balances but not the problem of poor liquidity.

Simon Peyton-Jones' financial contract language, and others derived from it, are not designed with the blockchain in mind. They are designed for a world of well-identied legal entities functioning as parties and government- sanctioned enforcement to deal with the potential of negative balances and breach of contract. A successful financial DSL for the blockchain must abandon these implicit premises.

Tests

A decent set of integration tests for this compiler is included in geth_tools.

References