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.

Nxt and Ardor hackaton March 22, Norway

NFEA Autonomy Conference + Ardor/Ignis Workshop and Hackaton


At the upcoming NFEA Autonomy Conference in Norway, there will be hands-on Ardor/Nxt workshops and a hackathon for developers on the 22nd. Bring your own laptop.

riker:
Developers are invited for the March 22nd hackaton.

Details:

March 20-21, The Autonomy Conference 2018, Scandic Bystranda Hotel, Kristiansand, Norway
Go to the Registration Site for the conference (in Norwegian).

Full program

March 22, Ardor Hackaton, Scandic Bystranda Hotel, Kristiansand, Norway
Go to the Registration Site for the hackaton. This event is sponsored by SFI Offshore Mechatronics and is free for the participants, but the number of seats is limited to 50.

Program for the hackaton event:
08:00 – 08:30 Coffee/tee
08:30 – 10:00 Ardor API programming, test page, account creation, node JS module, security considerations
10:00 – 10:30 Coffee/tee
10:30 – 11:30 Using the Ardor API exercises (Javascript skills recommended)
11:30 – 12:30 Lunch
12:30 – 14:00 Ardor server side add-ons, custom bundlers, dbshell
14:00 – 14:30 Coffee/tee
14:30 – 16:30 Building Ardor add-ons exercises (Java skills required)