NXTER.ORG

Ardor Contract add-on examples

Jelurida is Developing the Contract Concept

Jelurida continues to hone and further develop their Lightweight add-on contracts concept. In the second week of March, we introduced this in the Nxter Newsletter.  

Lior wrote:

You don’t need to pay gas for these contracts and you can program in Java. On the other hand the “contracts” are only executed by anyone running the addon and it’s not part of the consensus i.e. you can verify that anyone who created a transaction based on the contract did not cheat, but if they cheat or just choose not to run the contract then you cannot fix it. i.e. some trust in the contract executor is required.

Lior continues deploying example contracts to the decentralized data cloud, and we expect to see a number of blog posts from him soon going into detail about the add-ons concept. Until then, here’s the first view, as posted in the #developers channel in ArdorNxt.Slack.com.

 

Hello World 

Lior –

While we continue to develop our contracts concept, you can experiment with it by sending a message transaction, on the Ardor testnet, with text:

{ “chain”: 2, “fullHash”: “53758cc1f44a3eaf86cc187cbd2b73c2a60c0cf60adafb734fc42477bf6d29c2” }

to account ARDOR-NFAY-XYBA-SZ4G-H8SHA

In response, you should receive an automatic greeting message from the HelloWorld contract deployed to cloud data.

The contract code is:

 public void processTransaction(TransactionContext context) {
      if (!context.validateSameRecipient()) {
          return;
      }
      JO transactionJson = context.getTransactionJson();
      int chainId = transactionJson.getInt(“chain”);
      Chain chain = Chain.getChain(chainId);
      String recipientRS = transactionJson.getString(“senderRS”);
      JO params = new JO();
      params.put(“recipient”, recipientRS);
      JO message = new JO();
      message.put(“text”, “Hello ” + recipientRS);
      params.put(“message”, message.toJSONString());
      params.put(“messageIsPrunable”, “true”);
      context.createTransaction(“sendMessage”, chain, params);
  }

The contract transaction is 2:71660bdaa260d790772e3fc64470a8db465f6b395a0e134f921d57d6fd9589f0

The PingPong Lottery

Send any amount in any chain, on the Ardor testnet, with attached message text:

{ “chain”: 2, “fullHash”: “798131112caf0f417abd44eaac64f432d0dac147a0d7021b9232d726e215b4be” }

to account ARDOR-NFAY-XYBA-SZ4G-H8SHA

In response you will receive back amount between 0 and 2x your investment.

Contract code is:

public void processTransaction(TransactionContext context) {
if (!context.validateSameRecipient() || !context.validateTransactionType(PaymentTransactionType.ORDINARY, FxtTransactionType.findTransactionType((byte)-2, (byte)0))) {
return;
}
Random r = context.getRandom();
long amount = context.getAmountNQT();
long returnAmount = BigInteger.valueOf(Math.abs(r.nextLong())).multiply(BigInteger.valueOf(2)).multiply(BigInteger.valueOf(amount)).divide(BigInteger.valueOf(Long.MAX_VALUE)).longValue();
Logger.logInfoMessage(String.format(“amount paid %d amount returned %d”, amount, returnAmount));
Chain chain = context.getChain();
long recipient = context.getSenderId();
JO input = new JO();
input.put(“recipient”, recipient);
input.put(“amountNQT”, returnAmount);
context.createTransaction(“sendMoney”, chain, input);
}

The contract transaction id is, of course, the transaction id we mentioned in our message 2:798131112caf0f417abd44eaac64f432d0dac147a0d7021b9232d726e215b4be

Oracle

Here is an example for an “Oracle” contract.

Send 1 IGNIS or more with attached message:

{ “chain”: 2, “fullHash”: “409c120e6e7551927be4856389bb34cd257ccb84cfb202569327c4a3a89f0e7a” }

to account ARDOR-NFAY-XYBA-SZ4G-H8SHA

In response you will get back a message with the calculated rate of IGNIS per ARDOR from both Bittrex and the Coin Exchange to help you identify arbitrage opportunities.

Contract code:

package nxt.addons.contracts;

import nxt.addons.TransactionContext;
import nxt.blockchain.ChildChain;
import nxt.util.Logger;
import org.json.simple.JSONValue;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class IgnisArdorRates extends AbstractContract {

/**
* Sample contract which receives amount from the trigger transaction and returns a random amount between 0 and twice the received amount
* @param context contract context
*/
@Override
public void processTransaction(TransactionContext context) {
JO response = new JO();
if (!(context.getChain() == ChildChain.IGNIS) || context.getAmountNQT() < ChildChain.IGNIS.ONE_COIN) {
context.setErrorResponse(10001, "Oracle requires a payment of 1 IGNIS to operate");
return;
}
// {"success":true,"message":"","result":{"Bid":0.00003072,"Ask":0.00003098,"Last":0.00003090}}
JO ignisTickerResponse = getRate("IGNIS");
if (ignisTickerResponse.get("errorCode") != null) {
context.setResponse(response);
return;
}
Double ignisLastTrade = ignisTickerResponse.getJo("result").numericToDouble("Last");
JO ardorTickerResponse = getRate("ARDR");
if (ardorTickerResponse.get("errorCode") != null) {
context.setResponse(response);
return;
}
Double ardorLastTrade = ardorTickerResponse.getJo("result").numericToDouble("Last");
long ignisNQTPerARDR = BigDecimal.valueOf(ardorLastTrade).
multiply(BigDecimal.valueOf(ChildChain.IGNIS.ONE_COIN)).
divide(BigDecimal.valueOf(ignisLastTrade), RoundingMode.HALF_EVEN).
longValue();
response.put("BittrexIgnisNQTPerARDR", ignisNQTPerARDR);
JO requestParams = new JO();
requestParams.put("chain", 2);
requestParams.put("exchange", 1);
requestParams.put("firstIndex", 0);
requestParams.put("lastIndex", 1);
JO getCoinExchangeTradesResponse = context.sendRequest("getCoinExchangeTrades", requestParams);
JA trades = getCoinExchangeTradesResponse.getArray("trades");
if (trades.size() > 0) {
JO trade = trades.get(0);
response.put("BlockchainIgnisNQTPerARDR", trade.get("priceNQTPerCoin")); // TODO test with real data
}
JO input = new JO();
input.put("recipient", context.getSenderId());
input.put("message", response.toJSONString());
input.put("messageIsPrunable", true);
context.createTransaction("sendMessage", context.getChain(), input);
}

private JO getRate(String coin) {
HttpURLConnection connection;
JO response = new JO();
String protocol = "https";
String host = "bittrex.com";
int port = 443;
String urlParams = "/api/v1.1/public/getticker?market=BTC-" + coin;
URL url;
try {
url = new URL(protocol, host, port, urlParams);
} catch (MalformedURLException e) {
response.put("errorCode", 10002);
response.put("errorDescription", e.getMessage());
return response;
}
try {
Logger.logDebugMessage("Sending request to server: " + url.toString());
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
try (Reader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
return new JO(JSONValue.parse(reader));
}
} else {
response.put("errorCode", 10003);
response.put("errorDescription", "No response");
return response;
}
} catch (RuntimeException | IOException e) {
response.put("errorCode", 10004);
response.put("errorDescription", e.getMessage());
return response;
}
}
}

Class file is deployed as cloud data txid 2:409c120e6e7551927be4856389bb34cd257ccb84cfb202569327c4a3a89f0e7a

Note that when you send a message to the contract you always use this txid in the message

ProbertyBasedLottery

And contract 2:ab2ee853bf8bf57b550d16d2ffd1bed087b79eefb8b879f8d22f9ec969960a41 is a new version of the PropertyBasedLottery contract used by Bitswift to determine the winner of their twitter campaign: https://www.nxter.org/nxter-news-april-2018-i/#Bitswift_childchain_thread

UPDATE:

Lior has published a series of articles about Lightweight Contracts on his Medium blog, since this post was written. You should check them: https://medium.com/@lyaffe/lightweight-contracts-articles-49c3032a50da

Follow Lior’s blog on Medium.

Lior Yaffe: Advanced Concepts in Blockchain Design

Lior Yaffe explains some design concepts that have made it into NXT and the upcoming Ardor platform, such as: Proof of Stake, Brain Wallets, Forging, Prunable data, The Ardor platform, Smart transactions and hard fork management.

The lecture took place on 27.7.2016, at Campus Tel Aviv.

Slides:
https://bitcoil.co.il/files/Advanced….
http://prezi.com/x8jyard5-h51/

Event page: http://www.meetup.com/bitcoin-il/even…

Shareholders Meeting via Blockchain

It seems we are witnessing a revolution in the corporate world caused by blockchain technologies. We’re moving quickly towards a new business ecosystem of virtual corporations, distributed autonomous corporations, smart contracts, new models of funding and so on. This article is about the exciting possibility of having distributed shareholders’ meetings where results are public and counted in a trustless way.

Since late April last year, I’ve been working on the NXT cryptocurrency as a core developer. NXT is a 100% proof-of-stake cryptocurrency aiming “to transform a cryptocurrency into a decentralised financial platform that supports a thriving and fast-growing digital economy” (unlike hybrid Ripple’s approach which isn’t fully decentralized).

Since 12 May, NXT has had the Asset Exchange (NXT AE) as a core feature. Anyone can now issue assets on this totally decentralized and uncontrolled exchange and trade them.

You can monitor your Nxt asset purchases either via your client or via a number of independent web sites: NextBlocks, NXTReporting and SecureAE  (where you can also purchase Nxt and issue assets).

Read the asset descriptions and you’ll quickly gain an appreciation of the wide range of different applications and services that have already been built on top of the Nxt platform and they’re just the beginning; the start of what is set to evolve into an entire financial and economic ecosystem.

The key feature of the NXT AE for businesspeople is that they can fund their business via asset issuance, getting money from anyone (not just angels/VCs, as with KickStarter), and they can do so from day one and for a low fee.

Imagine getting funding directly from a community needing your product. And, wouldn’t it also be awesome to get feedback and community-powered decisions?

With the voting system I have finished recently that will all be possible. The voting system will be introduced in NRS (NXT Reference Software) 1.5. The latest release version is 1.4.16, so voting API & GUI is already accessible. I can share some API details right now as they will likely remain unchanged.

Also see: Nxt Voting Teaser video (GUI and functionality)

Consider the example of an indy developer making a game. First, he got some funds via the asset exchange. Then he made a promising v.1 of the game. Both the concept and its implementation are still raw but the fans are excited! So he wants to ask the community whether he should polish v.1 or instead build v.2 on the basis of a better concept, or… Having decided on the different options, he starts the poll:

    val question = "Further directions in game development. "
    val description = "I got some great reviews. I have 10000 NXTs left. How should I spend them?"

    val finishBlockHeight = Nxt.getBlockchain.getHeight + 1440 // ~= 1 day
    val options = Array("Improve graphics and release it ASAP", "Start to work on v.2 to get funds for it's development", "Better ask experts, e.g. attend GameDev Conference", "Game is abortive. Stop working on it.")

    val optionModel = Poll.OPTION_MODEL_CHOICE
    val votingModel = Poll.VOTING_MODEL_ASSET

    val pb = new PollBuilder(question, desc, options, finishBlockHeight, optionModel, votingModel)
    val assetId: Long =  // assetId here
    pb.assetId(ai)
    pb.optionsNumRange(1, 1) // only 1 option to choose

    issueTxToGodId(new Attachment.MessagingPollCreation(pb), phrase1)

A vote could be sent with following code:

    val poll = Poll.getByName(question).head
    val vote = Array(0.toByte, 1.toByte, 0.toByte, 0.toByte)
    val attachment = new Attachment.MessagingVoteCasting(poll.getId, vote)
    issueTxToGodId(attachment, phrase2) 

1440 blocks after starting the poll we can get and print to console poll results (where 1 asset=1 vote):

    val pr = PollResults.get(poll.getId).get
    pr match {
        case cpr: nxt.PollResults#Choice =
            val m = cpr.getResults.toMap
            println(m)      
    }

So, we are soon going to have fair, cheap, public and distributed shareholders voting! Just imagine how that could change the world of business.

Notes:

1. This blog post (as revised) was first released by Kushti on 2. The minimum fee to issue an asset on the NXT AE is 1000 NXT. The transaction fee is currently 1 NXT.