Skip to content

Latest commit

 

History

History
205 lines (154 loc) · 10.7 KB

chip-0008.md

File metadata and controls

205 lines (154 loc) · 10.7 KB
CHIP Number 0008
Title Splitter Puzzle
Description A standard puzzle for splitting a coin according to a predefined splitting schema.
Author Andreas Greimel (@acevail_ on Twitter)
Editor Dan Perry
Comments-URI #30
Status Final
Category Informational
Sub-Category Informative
Created 2022-09-03
Dependencies None

Abstract

This proposal aims to define a standard puzzle for splitting a coin according to a predefined splitting schema.

Motivation

One of the great features of NFT1 is the built-in payment of royalties. It is very flexible, since any address and therefore any puzzle can be used as royalty recipient. Many people in the community have requested the option to split the royalty payment between different recipients. For example, a share should be sent to a charity, or multiple artists want to share the royalties automatically. Having this features available increases the value of the Chia NFT ecosystem as a whole.

Backwards Compatibility

This proposal does not have any backwards incompatibilities.

Rationale

There have already been approaches to split royalties in the Chia ecosystem. The shortcoming of the existing approaches is a dependence on a single actor to trigger the royalty split.

The solution outlined in this propsal ensures independence from any single actor. This means that any observer of the Chia blockchain is able to trigger the royalty split, including the users wallet or an NFT marketplace.

The core is a simple Chialisp puzzle without many moving parts. It includes a payout scheme defining how the royalty should be split. The payment scheme is fixed and can not be altered by third parties. Anyone is able to trigger the royalty payout for any NFT.

Specification

An example payout scheme could look like this

Recipient Address Share
xch18qt2ju2sj3k8w3290az6flkkc95fqcmcg7edl90ns0jrjav8xttsfmtqfp 80
xch1p9e3l3ttl7qrrhy6zmmqmjm0v33fvrxhd494yv7at0ppd97hljns4uw464 20

The proposed Chialisp puzzle looks like this.

; This puzzle is designed to split its coin amount according to a predefined payout scheme.

(mod
  (
  PAYOUT_SCHEME ; The payout scheme is a list of recipient puzzle hashes and their share, e.g.
                ; ((0xcafef00d 80) (0xdeadbeef 20)) for an 80/20 split
  my_amount ; The amount of the coin to be split.
  total_shares ; The sum of all shares in the payout scheme. Passed in to reduce the complexity of the puzzle.
  )

  (include condition_codes.clib)
  (include curry_and_treehash.clib)

  (defun-inline get_puzhash (payout_scheme_item)
    (f payout_scheme_item)
  )

  (defun-inline get_share (payout_scheme_item)
    (f (r payout_scheme_item))
  )

  (defun-inline calculate_share (total_amount share total_shares)
    (f (divmod (* total_amount share) total_shares))
  )

  (defun-inline get_amount (payout_scheme_item total_amount total_shares)
    (calculate_share total_amount (get_share payout_scheme_item) total_shares)
  )

  ; mutual recursive function to calculate the amount only once
  (defun calculate_amount_and_split (PAYOUT_SCHEME total_amount total_shares shares_sum remaining_amount)
    (if PAYOUT_SCHEME
      (split_amount_and_create_coins PAYOUT_SCHEME (get_amount (f PAYOUT_SCHEME) total_amount total_shares) total_amount total_shares shares_sum remaining_amount)
      (if (= total_shares shares_sum)
        ()
        (x) ; raise if total shares input doesn't match the sum of all shares
      )
    )
  )

   ; Loop through the royalty payout scheme and create coins
  (defun split_amount_and_create_coins (PAYOUT_SCHEME this_amount total_amount total_shares shares_sum remaining_amount)
    (c
      (list
        CREATE_COIN
        (get_puzhash (f PAYOUT_SCHEME))
        (if (r PAYOUT_SCHEME) this_amount remaining_amount)
        (list (get_puzhash (f PAYOUT_SCHEME)))
      )
      (calculate_amount_and_split
        (r PAYOUT_SCHEME)
        total_amount
        total_shares
        (+ shares_sum (get_share (f PAYOUT_SCHEME)))
        (- remaining_amount this_amount)
      )
    )
  )

  ; main
  (c
    (list CREATE_COIN_ANNOUNCEMENT ())
    (c
      (list ASSERT_MY_AMOUNT my_amount)
      (calculate_amount_and_split PAYOUT_SCHEME my_amount total_shares 0 my_amount)
    )
  )
)

The payout scheme PAYOUT_SCHEME is curried into this puzzle, to make it immutable. Using the above scheme as an example, it looks like this:

((0x3816a97150946c7745457f45a4fed6c16890637847b2df95f383e439758732d7 80) (0x09731fc56bff8031dc9a16f60dcb6f6462960cd76d4b5233dd5bc21697d7fca7 20)

The only solution parameter needed on spend is the actual amount of the coin and the total number of shares. The total number of shares is defined as the sum of all individual shares in the scheme.

The puzzle is very flexible and doesn't require a specific number of shares. This means the following share distributions are equivalent:

Recipient Address Share
xch18qt2ju2sj3k8w3290az6flkkc95fqcmcg7edl90ns0jrjav8xttsfmtqfp 4
xch1p9e3l3ttl7qrrhy6zmmqmjm0v33fvrxhd494yv7at0ppd97hljns4uw464 1

is equivalent to

Recipient Address Share
xch18qt2ju2sj3k8w3290az6flkkc95fqcmcg7edl90ns0jrjav8xttsfmtqfp 80
xch1p9e3l3ttl7qrrhy6zmmqmjm0v33fvrxhd494yv7at0ppd97hljns4uw464 20

is equivalent to

Recipient Address Share
xch18qt2ju2sj3k8w3290az6flkkc95fqcmcg7edl90ns0jrjav8xttsfmtqfp 8000
xch1p9e3l3ttl7qrrhy6zmmqmjm0v33fvrxhd494yv7at0ppd97hljns4uw464 2000

This gives the creator of the puzzle a lot of flexibility on how to split the coin.

On spend, the puzzle steps through the entries of the PAYOUT_SCHEME and creates a new coin per entry. The amount of the new coins will be a share of the total amount, determined by the share defined in the PAYOUT_SCHEME and the total number of shares.

If the created coins do not use up the full coin amount, the rest is added to the last recipient in the payout scheme. This difference is at most NUMBER_OF_RECIPIENTS mojos, therefore its not worth the effort to construct a more complicated mechanism. It is important that the full coin amount is being reissued, otherwise it breaks CAT coins.

Here are some example coin splits for the above schema

Coin Amount Recipient 1 receives Recipient 2 receives
1 mojos 0 mojos 1 mojos
2 mojos 1 mojos 1 mojos
100 mojos 80 mojos 20 mojos
101 mojos 80 mojos 21 mojos
102 mojos 81 mojos 21 mojos
1000 mojos 800 mojos 200 mojos
1001 mojos 800 mojos 201 mojos

Test Cases

The unit test for the split Chialisp puzzle is located in the greimela/chialisp GitHub repository: royalty_share/tests/test_p2_royalty_share_arbitrary_shares.py.

Reference Implementation

The Chialisp puzzle itself is located in the greimela/chialisp GitHub repository: royalty_share/clsp/p2_royalty_share_arbitrary_shares/p2_royalty_share_arbitrary_shares_rest_to_last.clsp.

This repository is a fork of the Chialisp repository by @trgarrett, which already contains some driver code for this and other royalty puzzles. The plan is to unify all those royalty puzzles into one standard.

Security

The Chialisp code has been covered by unit tests, but has not been audited yet by Chia Network or the broader community.

Potential risks:

  • Royalty recipient can be altered
    • The royalty recipients are curried into the puzzle and the only parameter in the solution is the amount. So the payout scheme can not be altered after it has been created.
  • Puzzle can be bricked by wrong configuration
    • Due to the dynamic share calculation, any payout scheme with positive integers as shares will work fine.
    • The nature of Chialisp is that the puzzle will only execute and check the validity of the payout scheme when spending the coin. This is too late to detect any configuration errors, so the tools constructing the puzzle have to make sure that the payout scheme adheres to the defined format.
    • The puzzle does not support negative shares or fractional shares and will behave in undefined ways if configured that way.
  • Royalty payout can be stalled
    • Since the royalty payment can be triggered by any party on a permissionless blockchain, nobody can stall or prevent this.
  • Info to construct split puzzle can get lost
    • As soon as one particular split occurs for the first time, the puzzle is stored on the blockchain. Also, it is in the best interest of recipients of the split to store the payout scheme in order to get paid in the future.

Additional Assets

No additional assets.

Errata

  • Added the CHIP number to the preamble as it was missing (2023/05/19)

Copyright

Copyright and related rights waived via CC0.