Waves smart assets: blacklists and whitelists, interval trading

Waves smart assets: blacklists and whitelists, interval trading

In the previous two articles, we talked about smart accounts and how they can be used. for holding auctions and creating loyalty programsand also help ensure transparency of financial instruments.

Now we will look at smart assets and several use cases for them, including freezing assets and creating restrictions on transactions at given addresses.

Waves Smart Assets allow users to script assets, following the same mechanics as smart accounts. Each new transaction created using a smart asset will be confirmed first by the script, and only then by the blockchain.

It is worth noting the following differences between smart assets and smart accounts:

  1. In the code of a smart asset, it is impossible to check proofs (we talked about them in the first article).
  2. In the smart account code, you can check ExchangeTransaction only if your account is a matcher account. Otherwise, only the order is checked. In the smart asset code, you cannot check the order directly, you can check the ExchangeTransaction, and extract the order from it if necessary.
  3. A smart asset, unlike a smart account, does not have a state, but we still have access to the account states from the script.

Smart assets greatly simplify the writing of contracts, making the implementation of many cases concise and elegant.

Asset freeze

To freeze assets up to a certain block height targetHeight, you can simply set this value in the script of the following smart asset:

let targetHeight = 1500000
height >= targetHeight
 
height - функция языка, возращающая текущую высоту.

Specific matcher condition

To set a specific matcher as the desired one, you can set its address as the sender in a smart asset script like this:

match tx {
    case t : ExchangeTransaction =>
        t.sender == addressFromString("3PJaDyprvekvPXPuAtxrapacuDJopgJRaU3")
    case _ => true
}

"White list" of recipients

To allow tokens to be sent only to certain accounts - to create a "white list" of recipients - you can use a smart asset with the following schema that checks for inclusion in the list:

match tx {
  case t : TransferTransaction =>
    let trustedRecipient1 = addressFromString("3P6ms9EotRX8JwSrebeTXYVnzpsGCrKWLv4")
    let trustedRecipient2 = addressFromString("3PLZcCJyYQnfWfzhKXRA4rteCQC9J1ewf5K")
    let trustedRecipient3 = addressFromString("3PHrS6VNPRtUD8MHkfkmELavL8JnGtSq5sx")
    t.recipient == trustedRecipient1 || t.recipient == trustedRecipient2 || t.recipient == trustedRecipient3
  case _ => false
}

For safety reasons and provable language finality, the list does not contain an iterator implementation. Therefore, it is specified as a set of concrete elements.

"Black list" of recipients

Similarly, to prevent sending tokens to certain accounts, you can create a "black list". In this case, exactly the same smart asset is used, but with checking the address for the absence of a blacklist:

match tx {
  case t : TransferTransaction =>
    let bannedRecipient1 = addressFromString("3P6ms9EotRX8JwSrebeTXYVnzpsGCrKWLv4")
    let bannedRecipient2 = addressFromString("3PLZcCJyYQnfWfzhKXRA4rteCQC9J1ewf5K")
    let bannedRecipient3 = addressFromString("3PHrS6VNPRtUD8MHkfkmELavL8JnGtSq5sx")
    t.recipient != bannedRecipient1 && t.recipient != bannedRecipient2 && t.recipient != bannedRecipient3
  case _ => false
}

Sending with the permission of the issuer

With a smart asset, you can also set the option to send a smart asset only with the permission of the issuer (commitment/debt label). The issuer expresses its consent by posting the transaction ID in the state of his account:

match tx {
  case t : TransferTransaction =>
    let issuer = extract(addressFromString("3P6ms9EotRX8JwSrebeTXYVnzpsGCrKWLv4"))
    #убеждаемся, что в стейте эмитента содержится ID текущей транзакции
    isDefined(getInteger(issuer, toBase58String(t.id)))
  case _ => false
}

Exchange only for certain coins

A smart asset allows permission to exchange it only for certain coins. For example, to allow exchange only for bitcoins, you can use the following code:

let BTCId = base58'8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS'
match tx {
  case t : ExchangeTransaction =>
    t.sellOrder.assetPair.priceAsset == BTCId ||
     t.sellOrder.assetPair.amountAsset == BTCId
  case _ => true
}

Trade by price from the oracle

In the smart asset script, you can set the permission to trade only at the price fixed in the state of a reliable oracle. Here is an example of such a script:

let oracle = Address(base58'3PLNmokt22NrSiNvCLvwMUP84LCMJqbXwAD')
let assetId = toBase58String(base58'oWgJN6YGZFtZrV8BWQ1PGktZikgg7jzGmtm16Ktyvjd')
 
match tx {
  #запрещаем передачу ассета
  case t: TransferTransaction | MassTransferTransaction => false
  case e: ExchangeTransaction =>
    #убеждаемся, что торговля происходит по цене, заданной в стейте оракла для этого ассета
    let correctPrice = e.price == extract(getInteger(oracle, assetId))
    #убеждаемся, что торговля происходит в обмен на WAVES
    let correctPriceAsset = !isDefined(e.sellOrder.assetPair.priceAsset) 
correctPrice && correctPriceAsset
  case _ => true
}

Here we are faced with a non-obvious point when checking the ID of the asset that is being traded. The fact is that if the asset ID is not defined, then we are talking about WAVES. In the script, we make sure that trading is carried out in tandem with WAVES, in this way.

Fixed price increase

You can set a fixed price for a smart asset, which will increase step by step in a given proportion. Here is an example of an asset script that will increase its price by 5% every 1000 blocks:

let startPrice = 10
let startHeight = 1000
let interval = 1000
#на сколько процентов цена увеличивается за один шаг
let raise = 5
 
match tx {
  case t: TransferTransaction | MassTransferTransaction => false
  case e: ExchangeTransaction =>
    e.price == startPrice + ((height - startHeight) / interval) * (100 + raise) / 100
    && !isDefined(e.sellOrder.assetPair.priceAsset)
  case _ => true
}


Interval trading

Also, thanks to the script, smart asset trading can be limited to predetermined intervals. Here is an example of such a script:

let startHeight = 10000
let interval = 44000
let limit = 1500
 
match tx {
  case t: TransferTransaction | MassTransferTransaction | ExchangeTransaction =>
    (height - startHeight) % interval < limit
  case _ => true
}

In the script, we make sure that from the beginning of trading startHeight passed no more than limit intervals. The length of the interval is equal to the number of blocks specified in the field interval.

Source: habr.com

Add a comment