Breaking Down DeFi Code Snippets in Clarity

Today, $228B is locked in DeFi protocols across different blockchains. Since the Stacks mainnet launch a little over a year ago, we’ve seen a lot of exciting progress in Bitcoin DeFi. Let’s take a look at some of the things developers have built.

Type
Tutorial
Topic(s)
Clarity
Published
March 31, 2022
Author(s)
Community Manager
Breaking Down DeFi Code Snippets in Clarity
Contents
Your subscription could not be saved. Please try again.
Thanks for subscribing.

Product updates & dev resources straight to your inbox

Copy link

Unlike other DeFi protocols, Bitcoin DeFi is built with Clarity, a programming language that is different from other smart contract programming languages in two important ways.

  1. The language is interpreted and broadcasted on the blockchain as is (it’s not compiled). This ensures that the executed code is human-readable, and in fact with Clarity, the source code for every smart contract is made available on the blockchain. This means that anyone can audit and verify a specific smart contract if they want to.
  2. The language is decidable (not Turing incomplete). This means that it is possible to determine precisely what a program will do purely based on the code. This allows developers to accurately determine things like runtime costs and data usage.

Let’s take a look at the powers of Clarity in action with a few examples.

Declaration of the DIKO Fungible Token

Arkadiko is a DeFi protocol on the Stacks blockchain that serves a number of different functions, including creating the first stablecoin in the ecosystem USDA, offering self-repaying loans, as well as adding liquidity to the ecosystem through a number of different pools for different trading pairs.

Arkadiko uses the token DIKO for governance on the Arkadiko Protocol. This token is the main coordination mechanism they use within the ecosystem. Let’s take a look at that code:


;; ---------------------------------------------------------
;; SIP-10 Functions
;; ---------------------------------------------------------

(define-read-only (get-total-supply)
  (ok (ft-get-supply diko))
)

(define-read-only (get-name)
  (ok "Arkadiko Token")
)

(define-read-only (get-symbol)
  (ok "DIKO")
)

(define-read-only (get-decimals)
  (ok u6)
)

(define-read-only (get-balance (account principal))
  (ok (ft-get-balance diko account))
)

(define-public (set-token-uri (value (string-utf8 256)))
  (if (is-eq tx-sender (var-get contract-owner))
    (ok (var-set token-uri value))
    (err ERR-NOT-AUTHORIZED)
  )
)

(define-read-only (get-token-uri)
  (ok (some (var-get token-uri)))
)

(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
  (begin
    (asserts! (is-eq tx-sender sender) (err ERR-NOT-AUTHORIZED))

    (match (ft-transfer? diko amount sender recipient)
      response (begin
        (print memo)
        (ok response)
      )
      error (err error)
    )
  )
)
}

This token uses the correct SIP-010 declaration functions to configure the metadata for the DIKO token used on the platform. DIKO serves as the governance token of the Arkadiko Protocol and is the main coordination mechanism used within the Arkadiko ecosystem. It is necessary to have the default set of functions from the FT (fungible token) trait available in order to perform important token operations such as transferring an asset or querying metadata of a particular cryptocurrency. 

This contract correctly implements the seven functions from the SIP-010 fungible token trait.

With this concise but powerful set of default functions, users can execute an array of operations on the Arkadiko platform using the DIKO token. Additionally, this developer included one more unique function when creating the contract. The set-token-uri, is similar to get-token-uri, but with some special permissions. It can be called only by the owner of the smart contract (the principal that deployed the Clarity file to the public Stacks blockchain), and is used to update the token’s metadata. If this function is called by someone other than the contract owner, it throws an ERR-NOT-AUTHORIZED error. 

You can see the contract in full on GitHub here, or in action on the Stacks Explorer.

CryptoMate Swap 

CryptoMate is a Latin American-based token swapping platform that allows users to buy and sell cryptocurrency with other individuals. It’s a completely decentralized platform that uses smart contracts to handle all the business logic behind-the-scenes. They’ve even set up a helpful Telegram bot that walks beginners through the basics of the application and enables certain features through the Telegram chat app. 

A token swapping platform requires a robust array of Clarity smart contracts on the back end to handle orders, liquidity, pricing, and more, and the CryptoMate developer(s) was sure to instantiate a multitude of constant variables at the top of their contract for use throughout. A whooping 26 constant variables are defined, and they all store important data needed for executing swaps.


;; Defining Constants for CryptoMates Swap

(define-constant contract-owner tx-sender)
(define-constant not-authorized u4101)
(define-constant no-liquidity-err (err u4161))
(define-constant not-owner-err (err u4163))
(define-constant no-fee-to-address-err (err u4164))
(define-constant invalid-pair-err (err u4165))
(define-constant no-such-position-err (err u4166))
(define-constant balance-too-low-err (err u4167))
(define-constant too-many-pairs-err (err u4168))
(define-constant pair-already-exists-err (err u4169))
(define-constant wrong-token-err (err u4170))
(define-constant too-much-slippage-err (err u4171))
(define-constant transfer-x-failed-err (err u4172))
(define-constant transfer-y-failed-err (err u4173))
(define-constant value-out-of-range-err (err u4174))
(define-constant no-fee-x-err (err u4175))
(define-constant no-fee-y-err (err u4176))
(define-constant pair-token-already-used-err (err u4177))
(define-constant fee-contract-err (err u4178))
(define-constant not-upgraded-err (err u4179))
(define-constant lp-data-set-err (err u4180))
(define-constant lp-data-get-err (err u4181))
(define-constant SAFE_TRANSFER_AMOUNT_ERR (err u4182))
(define-constant SAFE_BURN_AMOUNT_ERR (err u4183))
(define-constant SAFE_MINT_AMOUNT_ERR (err u4184))
(define-constant PERMISSION_DENIED_ERROR u4185)

Let’s highlight a few of these constants.

  • tx-sender is defined as the owner of the contract. This gives the original individual who deployed the contract special control over operation of the platform. Later in the contract, a percentage of the fees are disbursed to the owner of the contract as compensation for offering a user-friendly, secure, functional platform. 
  • Invalid-pair-err is a defined error constant. You can envision this being utilized when a user tries to execute a trade on a token pair that is invalid. For example, if a user tried to swap two tokens that don’t exist on the platform, or they attempt a pointless swap like SOL to SOL, then an error would occur. 
  • Too-much-slippage is another defined error. Slippage in trading is any situation in which a market participant receives a different trade execution price than intended, one in which the price “slips.” This can occur when there is extremely low liquidity, and the trade being executed moves the price above or below the estimated value. This valuable safeguard can protect users from making a financially dangerous trade, and disallow disadvantageous swaps. 

Under-the-hood, CryptoMate’s swap smart contract is responsible for establishing valid token pairs based on availability and liquidity. That means we need an account of all token pairs, along with the token metadata, in order for the contract to function. Further down in the contract, you can find the map declaration, a useful Clarity data structure leveraged to hold important token information, including that metadata.

The map is one of the most powerful functions in Clarity. Those familiar with programming can most easily compare it to an array. It’s a multi-dimensional data structure in which similar elements of information are grouped and archived together.


;; Using a Map to Store Token Pairs

(define-map pairs-map
  { pair-id: uint }
  {
    token-x: principal,
    token-y: principal,
    liquidity-token: principal
  }
)

In this code snippet we see an essential function from the CryptoMate Swap contract. The developer of this contract uses the define-map function to establish a data structure to inventory all the available token pairs users can perform swaps with. It organizes metadata into a multivariable list, where important token information is stored, like principal contracts for each token and the accompanying liquidity token of the application. 

You can view the contract in full on GitHub as well as on the Stacks Explorer.

xBTC 

One of the most exciting innovations to emerge on the Stacks blockchain over the last year is the development of the xBTC token. This enables a method of “wrapping” native Bitcoin as xBTC for use on the Stacks network. Developed by TokenSoft, xBTC allows a whole new set of use cases, such as NFTs, trading pairs, and AMMS all denominated in xBTC, which is paired 1:1 with Bitcoin itself. It’s a huge step forward for applications in the Bitcoin ecosystem.

The xBTC smart contract is massive and handles countless operations. The Clarity code facilitates role-based access control, minting, burning, transfers, trait implementation, and initialization of the token. 

For example, their blacklist functionality is one of the most novel and important features of the smart contract. Crypto strives to be totally decentralized, but it’s been proven with a plethora of incidents that having an authority with a privileged role can be extremely beneficial in some cases. If there is a malicious or bad actor attempting to abuse the platform, having a blacklist feature to ban attackers or abusers can protect other users. Let’s take a look at how that works in practice:


;; Blacklisting Principals
;; --------------------------------------------------------------------------

;; Blacklist mapping.  If an account has blacklisted = true then no transfers in or out are allowed
(define-map blacklist { account: principal } { blacklisted: bool })

;; Checks if an account is blacklisted
(define-read-only (is-blacklisted (principal-to-check principal))
  (default-to false (get blacklisted (map-get? blacklist { account: principal-to-check }))))

;; Updates an account's blacklist status
;; Only existing principals with the BLACKLISTER_ROLE can update blacklist status
(define-public (update-blacklisted (principal-to-update principal) (set-blacklisted bool))
  (begin
    (asserts! (has-role BLACKLISTER_ROLE contract-caller) (err PERMISSION_DENIED_ERROR))
    ;; Print the action for any off chain watchers
    (print { action: "update-blacklisted", principal-to-update: principal-to-update, set-blacklisted: set-blacklisted })
    (ok (map-set blacklist { account: principal-to-update } { blacklisted: set-blacklisted }))))

Here we see three functions from the xBTC contract that establishes blacklisting parameters. The first defines a map named blacklist. This is a simple data structure that contains a list of principals (accounts) that use the platform, and an accompanying boolean variable signaling if a specific principal’s blacklist status is true or false. 

The second is a read-only function that checks if a principal is included in the blacklist, and whether the user should be limited from using xBTC features. It does a simple query of the blacklist map, and if a principal has the accompanying true boolean signaling a wallet address is blacklisted, they lose access. 

Lastly, the final function allows an authority figure (with the designated BLACKLISTER_ROLE) to update the blacklist, appending or omitting principals from the map of blacklisted addresses. This is critical for an arbiter to remove hackers, loophole investigators, manipulating whales, and everything in between. 

Further down in the contract, you can observe the blacklist hard at work:


;; Transfer Restrictions
;; --------------------------------------------------------------------------
(define-constant RESTRICTION_NONE u0) ;; No restriction detected
(define-constant RESTRICTION_BLACKLIST u5) ;; Sender or receiver is on the blacklist

;; Checks to see if a transfer should be restricted.  If so returns an error code that specifies restriction type.
(define-read-only (detect-transfer-restriction (amount uint) (sender principal) (recipient principal))
  (if (or (is-blacklisted sender) (is-blacklisted recipient))
    (err RESTRICTION_BLACKLIST)
    (ok RESTRICTION_NONE)))

;; Returns the user viewable string for a specific transfer restriction
(define-read-only (message-for-restriction (restriction-code uint))
  (if (is-eq restriction-code RESTRICTION_NONE)
    (ok "No Restriction Detected")
    (if (is-eq restriction-code RESTRICTION_BLACKLIST)
      (ok "Sender or recipient is on the blacklist and prevented from transacting")
      (ok "Unknown Error Code"))))

In the detect-transfer-restriction function, there is a conditional if-statement. First, the function locates a specific principal in the blacklist map that was set up earlier. If the associated boolean is true, then an error is thrown, and feedback is given to the user explaining that their address is prevented from transacting. If the associated boolean is false, then that means the principal is not on the blacklist and has access to all the features of the xBTC smart contract. 

You can learn so much about fungible tokens written in Clarity from this monster contract. Take a look at it on Github, or deployed live on the Stacks Explorer

Conclusion

DeFi is one of the most popular spaces in crypto for a reason. It adds liquidity to the network and enables a lot of the fundamental building blocks that will be used to create applications. I’m thrilled to see what DeFi developers come up with next. If you’re feeling inspired by these snippets, check out our documentation to learn more and start building.

Copy link
Hiro news & product updates straight to your inbox
Only relevant communications. We promise we won’t spam.

Related stories