diff --git a/C#/Samples/WalletSample/WalletSample/Program.cs b/C#/Samples/WalletSample/WalletSample/Program.cs index 6d9fa88..560fbc5 100644 --- a/C#/Samples/WalletSample/WalletSample/Program.cs +++ b/C#/Samples/WalletSample/WalletSample/Program.cs @@ -22,7 +22,7 @@ internal static class Program private static AccountDto _account; private static KeyPair _key; private static List _chains; - private static List _tokens; + private static IList _tokens; private static void Main(string[] args) { @@ -116,8 +116,8 @@ private static async Task RunConsole() private static async Task ListTransactions() { - var txs = await _phantasmaApiService.GetAddressTxs.SendRequestAsync(_key.Address.ToString(), 10); - foreach (var tx in txs.Txs) + var txs = await _phantasmaApiService.GetAddressTxs.SendRequestAsync(_key.Address.ToString(), 0, 10); + foreach (var tx in txs.AccountTransactionsDto.Txs) { Console.WriteLine(Utils.Helper.GetTxDescription(tx, _chains, _tokens)); } @@ -142,7 +142,7 @@ private static async Task ShowBalance() Console.WriteLine("********************"); Console.WriteLine($"Token: {balanceSheetDto.Symbol}"); Console.WriteLine($"Chain: {balanceSheetDto.ChainName}"); - Console.WriteLine($"Amount: {TokenUtils.ToDecimal(BigInteger.Parse(balanceSheetDto.Amount), Helper.GetTokenDecimals(balanceSheetDto.Symbol, _tokens))}"); + Console.WriteLine($"Amount: {UnitConversion.ToDecimal(BigInteger.Parse(balanceSheetDto.Amount), Helper.GetTokenDecimals(balanceSheetDto.Symbol, _tokens))}"); Console.WriteLine(); } } @@ -183,7 +183,7 @@ private static async Task CrossChainTransfer()//todo var destinationChain = _chains[selectedChainOption - 1]; - Console.WriteLine($"Enter amount: (max {TokenUtils.ToDecimal(BigInteger.Parse(token.Amount), Helper.GetTokenDecimals(token.Symbol, _tokens))}"); + Console.WriteLine($"Enter amount: (max {UnitConversion.ToDecimal(BigInteger.Parse(token.Amount), Helper.GetTokenDecimals(token.Symbol, _tokens))}"); var amount = Console.ReadLine(); Console.WriteLine("Enter destination address: "); @@ -202,22 +202,23 @@ private static async Task CrossChainTransfer()//todo } else { - var listSteps = Helper.GetShortestPath(token.ChainName, destinationChain.Name, _chains); - if (listSteps.Count >= 2) - { - while (listSteps.Count >= 2) - { - Console.WriteLine($"Sending {cont} transaction of {listSteps.Count}"); - var txHash = await CrossChainTransferToken(destinationAddress, listSteps[0].Name, listSteps[1].Name, token.Symbol, - amount); - var confirmationDto = await _phantasmaApiService.GetTxConfirmations.SendRequestAsync(txHash); - while (!confirmationDto.IsConfirmed) await Task.Delay(100); - Console.WriteLine($"Settling block..."); - var settleTx = await SettleBlock(listSteps[0].Address, confirmationDto.Hash, listSteps[1].Address); - listSteps.RemoveAt(0); - cont++; - } - } + Console.WriteLine("TODO"); + //var listSteps = Helper.GetShortestPath(token.ChainName, destinationChain.Name, _chains); + //if (listSteps.Count >= 2) + //{ + // while (listSteps.Count >= 2) + // { + // Console.WriteLine($"Sending {cont} transaction of {listSteps.Count}"); + // var txHash = await CrossChainTransferToken(destinationAddress, listSteps[0].Name, listSteps[1].Name, token.Symbol, + // amount); + // var confirmationDto = await _phantasmaApiService.GetConfirmations.SendRequestAsync(txHash); + // while (!confirmationDto.IsConfirmed) await Task.Delay(100); + // Console.WriteLine($"Settling block..."); + // var settleTx = await SettleBlock(listSteps[0].Address, confirmationDto.Hash, listSteps[1].Address); + // listSteps.RemoveAt(0); + // cont++; + // } + //} } } @@ -225,10 +226,10 @@ private static async Task SameChainTransfer(string addressTo, string amount, str { var destinationAddress = Address.FromText(addressTo); int decimals = Helper.GetTokenDecimals(tokenSymbol, _tokens); - var bigIntAmount = TokenUtils.ToBigInteger(decimal.Parse(amount), decimals); + var bigIntAmount = UnitConversion.ToBigInteger(decimal.Parse(amount), decimals); var script = ScriptUtils.BeginScript() - .AllowGas(_key.Address, 1, 9999) + .AllowGas(_key.Address, Address.Null, 1, 9999) .TransferTokens(tokenSymbol, _key.Address, destinationAddress, bigIntAmount) .SpendGas(_key.Address) .EndScript(); @@ -245,7 +246,7 @@ private static async Task SettleBlock(string sourceChainAddress, string var settleTxScript = ScriptUtils.BeginScript() .CallContract("token", "SettleBlock", sourceChain, block) - .AllowGas(_key.Address, 1, 9999) + .AllowGas(_key.Address, Address.Null, 1, 9999) .SpendGas(_key.Address) .EndScript(); return await SignAndSendTx(settleTxScript, destinationChainName); @@ -257,11 +258,11 @@ private static async Task CrossChainTransferToken(string addressTo, stri var toChain = _chains.Find(p => p.Name == destinationChain); var destinationAddress = Address.FromText(addressTo); int decimals = Helper.GetTokenDecimals(symbol, _tokens); - var bigIntAmount = TokenUtils.ToBigInteger(decimal.Parse(amount), decimals); - var fee = TokenUtils.ToBigInteger(0.0001m, 8); + var bigIntAmount = UnitConversion.ToBigInteger(decimal.Parse(amount), decimals); + var fee = UnitConversion.ToBigInteger(0.0001m, 8); var script = ScriptUtils.BeginScript() - .AllowGas(_key.Address, 1, 9999) + .AllowGas(_key.Address, Address.Null, 1, 9999) .CrossTransferToken(Address.FromText(toChain.Address), symbol, _key.Address, _key.Address, fee) .CrossTransferToken(Address.FromText(toChain.Address), symbol, _key.Address, @@ -282,7 +283,7 @@ private static async Task RegisterName() Console.WriteLine("Enter name for address: "); var name = Console.ReadLine(); var script = ScriptUtils.BeginScript() - .AllowGas(_key.Address, 1, 9999) + .AllowGas(_key.Address, Address.Null, 1, 9999) .CallContract("account", "Register", _key.Address, name) .SpendGas(_key.Address) .EndScript(); diff --git a/C#/Samples/WalletSample/WalletSample/Utils/Utils.cs b/C#/Samples/WalletSample/WalletSample/Utils/Utils.cs index 3041e1d..86fecb0 100644 --- a/C#/Samples/WalletSample/WalletSample/Utils/Utils.cs +++ b/C#/Samples/WalletSample/WalletSample/Utils/Utils.cs @@ -13,7 +13,7 @@ namespace WalletSample.Utils { internal static class Helper { - public static int GetTokenDecimals(string tokenSymbol, List tokens) + public static int GetTokenDecimals(string tokenSymbol, IList tokens) { return tokens.SingleOrDefault(p => p.Symbol.Equals(tokenSymbol)).Decimals; } @@ -89,7 +89,7 @@ public static List GetShortestPath(string from, string to, List phantasmaChains, List phantasmaTokens) + public static string GetTxDescription(TransactionDto tx, List phantasmaChains, IList phantasmaTokens) { string description = null; @@ -108,18 +108,18 @@ public static string GetTxDescription(TransactionDto tx, List phantasm Event nativeEvent; if (evt.Data != null) { - nativeEvent = new Event((EventKind)evt.EvtKind, + nativeEvent = new Event((Phantasma.Blockchain.Contracts.EventKind)evt.EventKind, Address.FromText(evt.EventAddress), evt.Data.Decode()); } else { nativeEvent = - new Event((EventKind)evt.EvtKind, Address.FromText(evt.EventAddress)); + new Event((Phantasma.Blockchain.Contracts.EventKind)evt.EventKind, Address.FromText(evt.EventAddress)); } - switch (evt.EvtKind) + switch (evt.EventKind) { - case EvtKind.TokenSend: + case Phantasma.RpcClient.DTOs.EventKind.TokenSend: { var data = nativeEvent.GetContent(); amount = data.value; @@ -128,7 +128,7 @@ public static string GetTxDescription(TransactionDto tx, List phantasm } break; - case EvtKind.TokenReceive: + case Phantasma.RpcClient.DTOs.EventKind.TokenReceive: { var data = nativeEvent.GetContent(); amount = data.value; @@ -138,11 +138,11 @@ public static string GetTxDescription(TransactionDto tx, List phantasm } break; - case EvtKind.TokenEscrow: + case Phantasma.RpcClient.DTOs.EventKind.TokenEscrow: { var data = nativeEvent.GetContent(); amount = data.value; - var amountDecimal = TokenUtils.ToDecimal(amount, + var amountDecimal = UnitConversion.ToDecimal(amount, phantasmaTokens.SingleOrDefault(p => p.Symbol == data.symbol).Decimals); receiverAddress = nativeEvent.Address; receiverChain = data.chainAddress; @@ -151,21 +151,21 @@ public static string GetTxDescription(TransactionDto tx, List phantasm $"{amountDecimal} {data.symbol} tokens escrowed for address {receiverAddress} in {chain}"; } break; - case EvtKind.AddressRegister: + case Phantasma.RpcClient.DTOs.EventKind.AddressRegister: { var name = nativeEvent.GetContent(); description = $"{nativeEvent.Address} registered the name '{name}'"; } break; - case EvtKind.FriendAdd: + case Phantasma.RpcClient.DTOs.EventKind.AddFriend: { var address = nativeEvent.GetContent
(); description = $"{nativeEvent.Address} added '{address} to friends.'"; } break; - case EvtKind.FriendRemove: + case Phantasma.RpcClient.DTOs.EventKind.RemoveFriend: { var address = nativeEvent.GetContent
(); description = $"{nativeEvent.Address} removed '{address} from friends.'"; @@ -179,14 +179,14 @@ public static string GetTxDescription(TransactionDto tx, List phantasm if (amount > 0 && senderAddress != Address.Null && receiverAddress != Address.Null && senderToken != null && senderToken == receiverToken) { - var amountDecimal = TokenUtils.ToDecimal(amount, + var amountDecimal = UnitConversion.ToDecimal(amount, phantasmaTokens.SingleOrDefault(p => p.Symbol == senderToken).Decimals); description = $"{amountDecimal} {senderToken} sent from {senderAddress.Text} to {receiverAddress.Text}"; } else if (amount > 0 && receiverAddress != Address.Null && receiverToken != null) { - var amountDecimal = TokenUtils.ToDecimal(amount, + var amountDecimal = UnitConversion.ToDecimal(amount, phantasmaTokens.SingleOrDefault(p => p.Symbol == receiverToken).Decimals); description = $"{amountDecimal} {receiverToken} received on {receiverAddress.Text} "; } diff --git a/C++/Bindings/PhantasmaAPI.cpp b/C++/Bindings/PhantasmaAPI.cpp deleted file mode 100644 index f93a9dd..0000000 --- a/C++/Bindings/PhantasmaAPI.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include "pch.h" -#include "PhantasmaAPI.h" - -RPCRequest::RPCRequest(std::string method) -{ - requestBody = - { - {"jsonrpc", "2.0"}, - {"method", method}, - {"id", "1"}, - {"params", {}} - }; -} - -template -void RPCRequest::AddParameter(T param) -{ - requestBody["params"].emplace_back(param); -} - -json::value RPCRequest::BuildRequest() -{ - std::string str = requestBody.dump(); - return json::value::parse(converter.from_bytes(str)); -} - -template -void RPCRequest::AddParameter(T param, Args... params) -{ - AddParameter(param); - AddParameter(params...); -} - - -PhantasmaAPI::PhantasmaAPI(std::string host) -{ - apiHost = converter.from_bytes(host); -} - -PhantasmaAPI::~PhantasmaAPI() -= default; - -std::string PhantasmaAPI::FieldToString(value json, const string_t field) -{ - if(!json.has_string_field(field)) - { - std::string str1 = "Unexpected JSON format: missing string field "; - std::string str2 = (std::string) converter.to_bytes(field); - throw new std::exception(str1.append(str2).c_str()); - } - - return conversions::to_utf8string(json.at(field).as_string()); -} - -uint32_t PhantasmaAPI::FieldToNumber(value json, const string_t field) -{ - if (!json.has_number_field(field)) - { - std::string str1 = "Unexpected JSON format: missing number field "; - std::string str2 = (std::string) converter.to_bytes(field); - throw new std::exception(str1.append(str2).c_str()); - } - - return json.at(field).as_number().to_uint32(); -} - -json::value PhantasmaAPI::SendRequest(const json::value& body) -{ - http_client client(apiHost); - - // Build request URI and start the request. - uri_builder builder(U("/rpc")); - json::value output; - - pplx::task requestTask = client.request(methods::POST, builder.to_string(), body) - .then([&](http_response response) -> json::value // Handle response headers arriving. - { - const auto statusCode = response.status_code(); - printf("Received response status code:%u\n", statusCode); - - if (statusCode != 200) - throw http_exception("Malformed RPC request or endpoint: response status = " + statusCode); - - - response.content_ready().wait(); - - auto json = response.extract_json().then([&](value body) -> json::value - { - if (body.is_null()) - throw json_exception("Failed to parse JSON"); - - if (body.has_field(U("error"))) - throw std::exception(("Error: " + conversions::to_utf8string(body.at(U("error")).at(U("message")).as_string())).c_str()); - - if (!body.has_field(U("result"))) - throw json_exception("Malformed response: No \"result\" node on the JSON body"); - - return body.at(U("result")); - }).get(); - - return json; - }); - - try - { - output = requestTask.get(); - } - catch (const std::exception &e) - { - printf("Error exception:%s\n", e.what()); - } - - return output; -} - -{{#each types}} -{{#fix-type Key}} PhantasmaAPI::Deserialize{{#fix-type Key}}(json::value json) -{ -{{#parse-lines false}} -{{#each Value}} -{{#if FieldType.Name=='String[]'}}{{#parse-lines true}} - std::vector<{{#fix-type FieldType.Name}}> {{Name}}Vector; - if(json.has_array_field(U("{{Name}}"))) - { - json::array {{Name}}JsonArray = json.at(U("{{Name}}")).as_array(); - - for(int i = 0; i < {{Name}}JsonArray.size(); i++) - { - {{Name}}Vector.push_back(conversions::to_utf8string({{Name}}JsonArray[i].as_string())); - } - }{{#parse-lines false}} -{{#else}} -{{#if FieldType.Name contains '[]'}}{{#parse-lines true}} - std::vector<{{#fix-type FieldType.Name}}> {{Name}}Vector; - if(json.has_array_field(U("{{Name}}"))) - { - json::array {{Name}}JsonArray = json.at(U("{{Name}}")).as_array(); - - for(int i = 0; i < {{Name}}JsonArray.size(); i++) - { - {{Name}}Vector.push_back(Deserialize{{#fix-type FieldType.Name}}({{Name}}JsonArray[i])); - } - }{{#parse-lines false}} -{{#else}} -{{#if FieldType.Name=='UInt32'}} - uint32_t {{Name}} = FieldToNumber(json, U("{{Name}}"));{{#new-line}} - -{{#else}} -{{#if FieldType.Name=='Int32'}} - uint32_t {{Name}} = FieldToNumber(json, U("{{Name}}"));{{#new-line}} - -{{#else}} -{{#if FieldType.Name=='String'}} - std::string {{Name}} = FieldToString(json, U("{{Name}}"));{{#new-line}} -{{#else}} -{{#if FieldType.Name=='IAPIResult'}} - json::value {{Name}} = json.at(U("result"));{{#new-line}} -{{#else}} - "Variable type {{FieldType.Name}} isnt currently handled by the template system"{{#new-line}} -{{/if}} -{{/if}} -{{/if}} -{{/if}} -{{/if}} -{{/if}} -{{/each}} -{{#parse-lines true}} - return {{#fix-type Key}} { {{#each Value}}{{Name}}{{#if FieldType.Name contains '[]'}}Vector{{/if}}{{#if !@last}}, {{/if}}{{/each}} }; -} -{{/each}} - -{{#each methods}}//{{#if Info.IsPaginated}}Paginated api call: {{/if}}{{Info.Description}} -{{#if Info.ReturnType.IsArray}}std::vector<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} PhantasmaAPI::{{Info.Name}}({{#each Info.Parameters}}{{#fix-type Type.Name}} {{Name}}{{#if !@last}}, {{/if}}{{/each}}) -{ - RPCRequest body("{{#camel-case Info.Name}}"); - {{#if Info.Parameters}}body.AddParameter({{#each Info.Parameters}}{{Name}}{{#if !@last}}, {{/if}}{{/each}});{{/if}} - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - {{#if Info.ReturnType.IsArray}}std::vector<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} output; - - {{#if Info.IsPaginated}}Paginated pageStruct = DeserializePaginated(jsonResponse); - -{{#parse-lines false}} -{{#if Info.ReturnType.IsArray}} - for(int i = 0; i < pageStruct.result.size(); i++){{#new-line}} - { -{{#new-line}} -{{#if Info.ReturnType.Name=='UInt32'}} - output.push_back(pageStruct.result[i].as_number().to_uint32());{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='Int32'}} - output.push_back(pageStruct.result[i].as_number().to_uint32());{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='String'}} - output.push_back(conversions::to_utf8string(pageStruct.result[i].as_string()));{{#new-line}} -{{#else}} - output.push_back(Deserialize{{#fix-type Info.ReturnType.Name}}(pageStruct.result[i]));{{#new-line}} -{{/if}} -{{/if}} -{{/if}} - }{{#new-line}} -{{/if}} -{{#if Info.ReturnType.IsArray==false}} - output = Deserialize{{#fix-type Info.ReturnType.Name}}(pageStruct.result);{{#new-line}} -{{/if}} -{{#new-line}} - return output;{{#new-line}} -} -{{#parse-lines true}}{{/if}}{{#if Info.IsPaginated==false}}{{#parse-lines false}} -{{#if Info.ReturnType.IsArray}} -if (!jsonResponse.is_array()){{#new-line}} - throw json_exception("Malformed response: No JSON array on the \"result\" node");{{#new-line}} -{{#new-line}} - json::array resultArray = jsonResponse.as_array();{{#new-line}} - for(int i = 0; i < resultArray.size(); i++){{#new-line}} - { -{{#new-line}} -{{#if Info.ReturnType.Name=='UInt32'}} - output.push_back(resultArray[i].as_number().to_uint32());{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='Int32'}} - output.push_back(resultArray[i].as_number().to_uint32());{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='String'}} - output.push_back(conversions::to_utf8string(resultArray[i].as_string()));{{#new-line}} -{{#else}} - output.push_back(Deserialize{{#fix-type Info.ReturnType.Name}}(resultArray[i]));{{#new-line}} -{{/if}} -{{/if}} -{{/if}} - }{{#new-line}} -{{/if}} - -{{#if Info.ReturnType.IsArray==false}} -{{#if Info.ReturnType.Name=='UInt32'}} -output = jsonResponse.as_number().to_uint32();{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='Int32'}} -output = jsonResponse.as_number().to_uint32();{{#new-line}} -{{#else}} -{{#if Info.ReturnType.Name=='String'}} -output = conversions::to_utf8string(jsonResponse.as_string());{{#new-line}} -{{#else}} -output = Deserialize{{#fix-type Info.ReturnType.Name}}(jsonResponse);{{#new-line}} -{{/if}} -{{/if}} -{{/if}} -{{/if}} -{{#new-line}} - return output;{{#new-line}} -} -{{#parse-lines true}} - -{{/if}} -{{/each}} \ No newline at end of file diff --git a/C++/Bindings/PhantasmaAPI.h b/C++/Bindings/PhantasmaAPI.h index d1b1e43..3a00c0c 100644 --- a/C++/Bindings/PhantasmaAPI.h +++ b/C++/Bindings/PhantasmaAPI.h @@ -1,75 +1,750 @@ -#include "pch.h" -#include -#include -#include // JSON library -#include // WebSocket client -#include -#include +#pragma once +//------------------------------------------------------------------------------ +// Low-level API +//------------------------------------------------------------------------------ +// The PhantasmaJsonAPI namespace can construct JSON requests and parse JSON responses, +// but you are responsible for sending/receiving these messages via HTTP on your own. +// You can call PhantasmaJsonAPI::Uri() to determine where to send them. +// +// void PhantasmaJsonAPI::Make{Message}Request(JSONBuilder&, {Parameters}); +// bool PhantasmaJsonAPI::Parse{Message}Response(const JSONValue&, {Output}); +// +//------------------------------------------------------------------------------ +// High-level API +//------------------------------------------------------------------------------ +// If you have defined PHANTASMA_HTTPCLIENT, then you can construct a PhantasmaAPI object, +// which provides a simplified API that hides the internal JSON messaging. +// +// PhantasmaAPI phantasmaAPI(httpClient); +// {Output} phantasmaAPI->{Message}({Parameters}); +// +//------------------------------------------------------------------------------ +// API configuration +//------------------------------------------------------------------------------ +// As different C++ projects may use different primitive types, you can use the +// following #defines (BEFORE including phantasma.h) to override the default types. +// +// #define | typedef | Default | Notes +// PHANTASMA_INT32 | phantasma::Int32 | int32_t | +// PHANTASMA_UINT32 | phantasma::UInt32 | uint32_t | +// PHANTASMA_CHAR | phantasma::Char | char | See Unicode section +// PHANTASMA_STRING | phantasma::String | std::string | Must support construction from `const phantasma::Char*` +// PHANTASMA_VECTOR | | std::vector | Must support `push_back` and `size` members +// PHANTASMA_JSONVALUE | phantasma::JSONValue | std::string_view | See JSON section +// PHANTASMA_JSONARRAY | phantasma::JSONArray | JSONValue | See JSON section +// PHANTASMA_JSONDOCUMENT| phantasma::JSONDocument| std::string | See JSON section +// PHANTASMA_JSONBUILDER | phantasma::JSONBuilder | std::stringstream*| See JSON section +// PHANTASMA_HTTPCLIENT | phantasma::HttpClient | | See HTTP section +// +// The behavior of this header can further be modified by using the following +// #defines (BEFORE including phantasma.h) +// +// #define | Notes +// PHANTASMA_EXCEPTION(message) | See Exceptions section +// PHANTASMA_EXCEPTION_MESSAGE(message, String) | See Exceptions section +// PHANTASMA_LITERAL(x) | See Unicode section +// PHANTASMA_FUNCTION | See Integration section +// PHANTASMA_IMPLEMENTATION | See Integration section +// +//------------------------------------------------------------------------------ +// Integration +//------------------------------------------------------------------------------ +// This API is provided in the "single header" style to support simple and flexible +// integration into your project (see https://github.com/nothings/single_file_libs). +// The implementation of function bodies will be excluded unless you define +// PHANTASMA_IMPLEMENTATION before including phantasma.h. +// +// Typical linking: +// In one CPP file, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// +// Inline linking: +// In every CPP file that uses the API, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// #define PHANTASMA_FUNCTION inline +// +// Aside from PHANTASMA_IMPLEMENTATION / PHANTASMA_FUNCTION, you should take care +// to ensure that every other PHANTASMA_* macro is defined to the same value in +// all of yoru CPP files that use the phantasma API. +// +//------------------------------------------------------------------------------ +// Exceptions +//------------------------------------------------------------------------------ +// Support for C++ exceptions is opt-in. Define the following (or an alternative +// based on your own exception classes) before including phantasma.h: +// #define PHANTASMA_EXCEPTION(message) throw std::runtime_error(message) +// #define PHANTASMA_EXCEPTION_MESSAGE(message, string) throw std::runtime_error(string) +// +//------------------------------------------------------------------------------ +// Unicode +//------------------------------------------------------------------------------ +// To build a wide-character version of the API, define the following before +// including phantasma.h: +// #define PHANTASMA_CHAR wchar_t +// #define PHANTASMA_LITERAL(x) L ## x +// #define PHANTASMA_STRING std::wstring +// +// You should also provide a JSON and HTTP library with wide-character support. +// +//------------------------------------------------------------------------------ +// JSON +//------------------------------------------------------------------------------ +// This header contains JSON parsing and building code, but it is written to be +// as simple as possible (approx 200 lines of code) and is not high-performance +// or highly robust. +// +// It is recommended that you supply another JSON-parsing API, by defining the +// following macros before including phantasma.h: +// #define PHANTASMA_JSONVALUE Your_Json_Value_Type +// #define PHANTASMA_JSONARRAY Your_Json_Array_Type +// #define PHANTASMA_JSONDOCUMENT Your_JSON_Document_Type +// #define PHANTASMA_JSONBUILDER Your_Json_Serializer_Type +// +// Also, this header uses the following procedural API to interact with these types. +// If you have supplied your own JSON types, you must implement the following functions: +// +// namespace phantasma { namespace json { +// +// JSONValue Parse(const JSONDocument&); +// +// Int32 LookupInt32( const JSONValue&, const Char* field, bool& out_error); +// UInt32 LookupUInt32( const JSONValue&, const Char* field, bool& out_error); +// String LookupString( const JSONValue&, const Char* field, bool& out_error); +// JSONValue LookupValue( const JSONValue&, const Char* field, bool& out_error); +// JSONArray LookupArray( const JSONValue&, const Char* field, bool& out_error); +// bool HasField( const JSONValue&, const Char* field, bool& out_error); +// bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); +// +// Int32 AsInt32( const JSONValue&, bool& out_error); +// UInt32 AsUInt32( const JSONValue&, bool& out_error); +// String AsString( const JSONValue&, bool& out_error); +// JSONArray AsArray( const JSONValue&, bool& out_error); +// bool IsArray( const JSONValue&, bool& out_error); +// bool IsObject( const JSONValue&, bool& out_error); +// +// int ArraySize( const JSONArray&, bool& out_error); +// JSONValue IndexArray( const JSONArray&, int index, bool& out_error); +// +// void BeginObject(JSONBuilder&); +// void AddString (JSONBuilder&, const Char* key, const Char* value); +// template void AddArray (JSONBuilder&, const Char* key, Args...); +// void EndObject (JSONBuilder&); +// }} +// +//------------------------------------------------------------------------------ +// HTTP +//------------------------------------------------------------------------------ +// This header does not contain a HTTP client, nor a dependency on any specific +// HTTP client library. If you do not supply a HTTP client library, then only +// the Low-level phantasma API (PhantasmaJsonAPI) is available. +// +// To enable the PhantasmaAPI class, defining the following macro before +// including phantasma.h: +// #define PHANTASMA_HTTPCLIENT Your_HTTP_Client_Type +// +// Also, this header uses the following procedural API to interact with this type. +// If you have defined PHANTASMA_HTTPCLIENT, you must implement the following, +// function, which should perform a HTTP POST request and return the result: +// +// namespace phantasma { +// JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +// } +// +//------------------------------------------------------------------------------ + +#if !defined(PHANTASMA_STRING) || !defined(PHANTASMA_JSONDOCUMENT) || !defined(PHANTASMA_JSONVALUE) #include -#include +#endif -using namespace utility; // Common utilities like string conversions -using namespace web; // Common features like URIs. -using namespace http; // Common HTTP functionality -using namespace client; // HTTP client features -using namespace concurrency::streams; // Asynchronous streams -using namespace json; // JSON library +#if !defined(PHANTASMA_JSONVALUE) && __cplusplus > 201402L +#include +#endif -#pragma once +#if !defined(PHANTASMA_JSONBUILDER) +#include +#endif + +#if !defined(PHANTASMA_VECTOR) +#define PHANTASMA_VECTOR std::vector +#include +#endif + +#if !defined(PHANTASMA_S32) || !defined(PHANTASMA_U32) +#include +#endif + +#if !defined(PHANTASMA_EXCEPTION) +#define PHANTASMA_EXCEPTION(literal) +#define PHANTASMA_EXCEPTION_MESSAGE(literal, string) +#endif + +#if !defined(PHANTASMA_LITERAL) +#define PHANTASMA_LITERAL(x) x +#endif + +#if !defined(PHANTASMA_FUNCTION) +#define PHANTASMA_FUNCTION +#endif + +namespace phantasma +{ +#ifdef PHANTASMA_CHAR +typedef PHANTASMA_CHAR Char; +#else +typedef char Char; +#endif + +#ifdef PHANTASMA_INT32 +typedef PHANTASMA_INT32 Int32; +#else +typedef int32_t Int32; +#endif + +#ifdef PHANTASMA_UINT32 +typedef PHANTASMA_UINT32 UInt32; +#else +typedef uint32_t UInt32; +#endif + +#ifdef PHANTASMA_STRING +typedef PHANTASMA_STRING String; +#else +typedef std::string String; +#endif + +#ifdef PHANTASMA_JSONVALUE +typedef PHANTASMA_JSONVALUE JSONValue; +#elif __cplusplus > 201402L +typedef std::string_view JSONValue; +#else +typedef std::string JSONValue; +#endif + +#ifdef PHANTASMA_JSONARRAY +typedef PHANTASMA_JSONARRAY JSONArray; +#else +typedef JSONValue JSONArray; +#endif + +#ifdef PHANTASMA_JSONDOCUMENT +typedef PHANTASMA_JSONDOCUMENT JSONDocument; +#else +typedef std::string JSONDocument; +#endif + + +#ifdef PHANTASMA_JSONBUILDER +typedef PHANTASMA_JSONBUILDER JSONBuilder; +#else +struct JSONBuilder // A VERY simple json string builder. Highly recommended that you provide a real JSON library instead! +{ + std::stringstream s; + bool empty = true; + operator std::stringstream&() { return s; } + void AddKey(const Char* key) { if(!empty) { s << ", "; } empty = false; s << '"' << key << "\": "; } + void AddValues() {} + void AddValues(const char* arg) { s << '"' << arg << '"'; } + template void AddValues(T arg) { s << arg; } + template void AddValues(T arg0, Args... args) { AddValues(arg0); s << ", "; AddValues(args...); } + + void BeginObject() { s << "{"; } + void AddString(const Char* key, const Char* value) { AddKey(key); s << '"' << value << '"'; } + template void AddArray(const Char* key, Args... args) { AddKey(key); s << '['; AddValues(args...); s << ']'; } + void EndObject() { s << "}"; } +}; +#endif + +#ifdef PHANTASMA_HTTPCLIENT +typedef PHANTASMA_HTTPCLIENT HttpClient; +//JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +#endif + +//If providing a JSON library (highly recommended that you do!), then you must provide these functions yourself: +namespace json +{ +#ifndef PHANTASMA_JSONBUILDER + JSONValue Parse(const JSONDocument&); + Int32 LookupInt32(const JSONValue&, const Char* field, bool& out_error); + UInt32 LookupUInt32(const JSONValue&, const Char* field, bool& out_error); + String LookupString(const JSONValue&, const Char* field, bool& out_error); + JSONValue LookupValue(const JSONValue&, const Char* field, bool& out_error); + JSONArray LookupArray(const JSONValue&, const Char* field, bool& out_error); + bool HasField(const JSONValue&, const Char* field, bool& out_error); + bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); + Int32 AsInt32(const JSONValue&, bool& out_error); + UInt32 AsUInt32(const JSONValue&, bool& out_error); + String AsString(const JSONValue&, bool& out_error); + JSONArray AsArray(const JSONValue&, bool& out_error); + bool IsArray(const JSONValue&, bool& out_error); + bool IsObject(const JSONValue&, bool& out_error); + + int ArraySize(const JSONArray&, bool& out_error); + JSONValue IndexArray(const JSONArray&, int index, bool& out_error); + + void BeginObject(JSONBuilder&); + void AddString(JSONBuilder&, const Char* key, const Char* value); + template + void AddArray(JSONBuilder&, const Char* key, Args... args); + void EndObject(JSONBuilder&); +#endif +} {{#each types}} struct {{#fix-type Key}}{{#parse-lines false}}{{#new-line}} { {{#new-line}} {{#each Value}} - {{#if FieldType.IsArray}}std::vector<{{/if}}{{#fix-type FieldType.Name}}{{#if FieldType.IsArray}}>{{/if}} {{Name}};//{{Key.Description}} + {{#if FieldType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type FieldType.Name}}{{#if FieldType.IsArray}}>{{/if}} {{Name}};//{{Key.Description}} {{#new-line}} {{/each}} {{#parse-lines true}}}; {{/each}} -class RPCRequest +class PhantasmaJsonAPI { -private: - std::wstring_convert> converter; //to convert from std::string to std::wstring - nlohmann::json requestBody; - public: - template - void AddParameter(T param); + static const Char* Uri() { return PHANTASMA_LITERAL("/rpc"); } - template - void AddParameter(T param, Args... args); - - RPCRequest(std::string); + {{#each methods}}// {{Info.Description}} {{#if Info.IsPaginated==true}}(paginated call){{/if}} + static void Make{{Info.Name}}Request(JSONBuilder&{{#each Info.Parameters}}, {{#fix-ref Type.Name}} {{Name}}{{/each}}); + static bool Parse{{Info.Name}}Response(const JSONValue&, {{#if Info.ReturnType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}}& out); + {{/each}} - json::value BuildRequest(); +private: + static JSONValue CheckResponse(JSONValue response, bool& out_error); + {{#each types}}static {{#fix-type Key}} Deserialize{{#fix-type Key}}(const JSONValue& json, bool& out_error); + {{/each}} }; +#if defined(PHANTASMA_HTTPCLIENT) class PhantasmaAPI { -protected: - std::wstring_convert> converter; //to convert from std::string to std::wstring - - std::wstring apiHost; +public: + PhantasmaAPI(HttpClient& client) // client must have a longer lifetime than this API object + : m_httpClient(client) + {} - std::string FieldToString(json::value json, const string_t field); - uint32_t FieldToNumber(json::value json, const string_t field); + {{#each methods}}// {{Info.Description}} {{#if Info.IsPaginated==true}}(paginated call){{/if}} + {{#if Info.ReturnType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} {{Info.Name}}({{#each Info.Parameters}}{{#fix-ref Type.Name}} {{Name}}, {{/each}}bool* out_error = nullptr); + {{/each}} +private: + HttpClient& m_httpClient; +}; +#endif + +#if defined(PHANTASMA_IMPLEMENTATION) +{{#each types}} +PHANTASMA_FUNCTION {{#fix-type Key}} PhantasmaJsonAPI::Deserialize{{#fix-type Key}}(const JSONValue& value, bool& err) +{ {{#parse-lines false}} +{{#each Value}} +{{#if FieldType.Name=='String[]'}}{{#parse-lines true}} + PHANTASMA_VECTOR<{{#fix-type FieldType.Name}}> {{Name}}Vector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("{{Name}}"), err)) + { + const JSONArray& {{Name}}JsonArray = json::LookupArray(value, PHANTASMA_LITERAL("{{Name}}"), err); + int size = json::ArraySize({{Name}}JsonArray, err); + {{Name}}Vector.reserve(size); + for(int i = 0; i < size; ++i) + { + {{Name}}Vector.push_back(json::AsString(json::IndexArray({{Name}}JsonArray, i, err), err)); + } + }{{#parse-lines false}} +{{#else}} +{{#if FieldType.Name contains '[]'}}{{#parse-lines true}} + PHANTASMA_VECTOR<{{#fix-type FieldType.Name}}> {{Name}}Vector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("{{Name}}"), err)) + { + const JSONArray& {{Name}}JsonArray = json::LookupArray(value, PHANTASMA_LITERAL("{{Name}}"), err); + int size = json::ArraySize({{Name}}JsonArray, err); + {{Name}}Vector.reserve(size); + for(int i = 0; i < size; ++i) + { + {{Name}}Vector.push_back(Deserialize{{#fix-type FieldType.Name}}(json::IndexArray({{Name}}JsonArray, i, err), err)); + } + }{{#parse-lines false}} +{{/if}} +{{/if}} +{{/each}} + {{#new-line}} + return {{#fix-type Key}} { {{#new-line}} +{{#each Value}} +{{#if FieldType.Name contains '[]'}} + {{Name}}Vector +{{#else}} +{{#if FieldType.Name=='UInt32'}} + json::LookupUInt32(value, PHANTASMA_LITERAL("{{Name}}"), err) +{{#else}} +{{#if FieldType.Name=='Int32'}} + json::LookupInt32(value, PHANTASMA_LITERAL("{{Name}}"), err) +{{#else}} +{{#if FieldType.Name=='String'}} + json::LookupString(value, PHANTASMA_LITERAL("{{Name}}"), err) +{{#else}} +{{#if FieldType.Name=='IAPIResult'}} + json::LookupValue(value, PHANTASMA_LITERAL("result"), err) +{{#else}} + (err=true, "Variable type {{FieldType.Name}} isnt currently handled by the template system") +{{/if}} +{{/if}} +{{/if}} +{{/if}} +{{/if}}{{#if !@last}}, {{/if}}{{#new-line}} +{{/each}} + };{{#parse-lines true}} +} +{{/each}} - json::value SendRequest(const json::value& body); - {{#each types}}{{#fix-type Key}} Deserialize{{#fix-type Key}}(json::value json); - {{/each}} +PHANTASMA_FUNCTION JSONValue PhantasmaJsonAPI::CheckResponse(JSONValue response, bool& out_error) +{ + if( !json::IsObject(response, out_error) ) + { + PHANTASMA_EXCEPTION("Failed to parse JSON"); + out_error = true; + return response; + } + if( json::HasField(response, PHANTASMA_LITERAL("error"), out_error) ) + { + String msg = json::LookupString(response, PHANTASMA_LITERAL("error"), out_error); + PHANTASMA_EXCEPTION_MESSAGE("Server returned error: %s", msg); + out_error = true; + return response; + } + if( !json::HasField(response, PHANTASMA_LITERAL("result"), out_error) ) + { + PHANTASMA_EXCEPTION("Malformed response: No \"result\" node on the JSON body"); + out_error = true; + return response; + } + return json::LookupValue(response, PHANTASMA_LITERAL("result"), out_error); +} -public: - PhantasmaAPI(std::string host); - ~PhantasmaAPI(); +{{#each methods}} +// {{Info.Description}} {{#if Info.IsPaginated}}(Paginated){{/if}} +PHANTASMA_FUNCTION void PhantasmaJsonAPI::Make{{Info.Name}}Request(JSONBuilder& request{{#each Info.Parameters}}, {{#fix-ref Type.Name}} {{Name}}{{/each}}) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("{{#camel-case Info.Name}}")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"){{#each Info.Parameters}}, {{Name}}{{/each}}); + json::EndObject(request);{{#parse-lines true}} +} - {{#each methods}}//{{Info.Description}} - {{#if Info.IsPaginated==true}}//paginated call - {{/if}}{{#if Info.ReturnType.IsArray}}std::vector<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} {{Info.Name}}({{#each Info.Parameters}}{{#fix-type Type.Name}} {{Name}}{{#if !@last}}, {{/if}}{{/each}}); - +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::Parse{{Info.Name}}Response(const JSONValue& _jsonResponse, {{#if Info.ReturnType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}}& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + {{#if Info.IsPaginated}}Paginated pageStruct = DeserializePaginated(jsonResponse, err); +{{#parse-lines false}} +{{#if Info.ReturnType.IsArray}} + if(!json::IsArray(pageStruct.result, err)){{#new-line}} + { {{#new-line}} + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node");{{#new-line}} + return false;{{#new-line}} + } {{#new-line}} + const JSONArray& pages = json::AsArray(pageStruct.result, err);{{#new-line}} + int size = json::ArraySize(pages, err);{{#new-line}} + output.reserve(size);{{#new-line}} + for(int i = 0; i < size; ++i){{#new-line}} + { +{{#new-line}} +{{#if Info.ReturnType.Name=='UInt32'}} + output.push_back(json::AsUInt32(json::IndexArray(pages, i, err), err));{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='Int32'}} + output.push_back(json::AsInt32(json::IndexArray(pages, i, err), err));{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='String'}} + output.push_back(json::AsString(json::IndexArray(pages, i, err), err));{{#new-line}} +{{#else}} + output.push_back(Deserialize{{#fix-type Info.ReturnType.Name}}(json::IndexArray(pages, i, err), err));{{#new-line}} +{{/if}} +{{/if}} +{{/if}} + }{{#new-line}} +{{/if}} +{{#if Info.ReturnType.IsArray==false}} + output = Deserialize{{#fix-type Info.ReturnType.Name}}(pageStruct.result, err);{{#new-line}} +{{/if}} + return !err;{{#new-line}} +} +{{#parse-lines true}}{{/if}}{{#if Info.IsPaginated==false}}{{#parse-lines false}} +{{#if Info.ReturnType.IsArray}} +if (!json::IsArray(jsonResponse, err)){{#new-line}} + { {{#new-line}} + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node");{{#new-line}} + return false;{{#new-line}} + } {{#new-line}} +{{#new-line}} + const JSONArray& resultArray = json::AsArray(jsonResponse, err);{{#new-line}} + int resultArraySize = json::ArraySize(resultArray, err);{{#new-line}} + output.reserve(resultArraySize);{{#new-line}} + for(int i = 0; i < resultArraySize; ++i){{#new-line}} + { +{{#new-line}} +{{#if Info.ReturnType.Name=='UInt32'}} + output.push_back(json::AsUInt32(json::IndexArray(resultArray, i, err), err));{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='Int32'}} + output.push_back(json::AsInt32(json::IndexArray(resultArray, i, err), err));{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='String'}} + output.push_back(json::AsString(json::IndexArray(resultArray, i, err), err));{{#new-line}} +{{#else}} + output.push_back(Deserialize{{#fix-type Info.ReturnType.Name}}(json::IndexArray(resultArray, i, err), err));{{#new-line}} + if( err ) return false;{{#new-line}} +{{/if}} +{{/if}} +{{/if}} + }{{#new-line}} +{{/if}} +{{#if Info.ReturnType.IsArray==false}} +{{#if Info.ReturnType.Name=='UInt32'}} +output = json::AsUInt32(jsonResponse, err);{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='Int32'}} +output = json::AsInt32(jsonResponse, err);{{#new-line}} +{{#else}} +{{#if Info.ReturnType.Name=='String'}} +output = json::AsString(jsonResponse, err);{{#new-line}} +{{#else}} +output = Deserialize{{#fix-type Info.ReturnType.Name}}(jsonResponse, err);{{#new-line}} + if( err ) return false;{{#new-line}} +{{/if}} +{{/if}} +{{/if}} +{{/if}} + return !err;{{#new-line}} +} +{{#parse-lines true}} +{{/if}} +{{/each}} - {{/each}} -}; +#if defined(PHANTASMA_HTTPCLIENT) +{{#each methods}} +PHANTASMA_FUNCTION {{#if Info.ReturnType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} PhantasmaAPI::{{Info.Name}}({{#each Info.Parameters}}{{#fix-ref Type.Name}} {{Name}}, {{/each}}bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::Make{{Info.Name}}Request(request{{#each Info.Parameters}}, {{Name}}{{/each}}); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + {{#if Info.ReturnType.IsArray}}PHANTASMA_VECTOR<{{/if}}{{#fix-type Info.ReturnType.Name}}{{#if Info.ReturnType.IsArray}}>{{/if}} output; + bool success = PhantasmaJsonAPI::Parse{{Info.Name}}Response(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} +{{/each}} +#endif + +namespace json +{ +#ifndef PHANTASMA_JSONVALUE + JSONValue Parse(const JSONDocument& doc) { return doc; } + + inline size_t SkipNumber(const JSONValue& v, size_t i, bool& out_error) + { + size_t j = v.find_first_not_of("+-0123456789.eE", i); + if( i==j ) { PHANTASMA_EXCEPTION("Invalid Number"); out_error = true; return i+1; } + return j; + } + inline size_t SkipString(const JSONValue& v, size_t i, bool& out_error) + { + if( v[i] != '"' ) { PHANTASMA_EXCEPTION("Invalid String"); out_error = true; return i+1; } + for(++i; i + void AddArray(JSONBuilder& b, const Char* key, Args... args) { b.AddArray(key, args...); } + PHANTASMA_FUNCTION void EndObject(JSONBuilder& b) { b.EndObject(); } +#endif +} +#endif +} diff --git a/C++/Bindings/language.ini b/C++/Bindings/language.ini index 4230375..c10d16e 100644 --- a/C++/Bindings/language.ini +++ b/C++/Bindings/language.ini @@ -1,4 +1,7 @@ -String,std::string -UInt32,uint32_t -Int32,uint32_t -IAPI,json::value \ No newline at end of file +String,String +@String,const Char* +UInt32,UInt32 +Int32,Int32 +IAPI,JSONValue +@IAPI,const JSONValue& +Boolean,bool \ No newline at end of file diff --git a/C++/Sample/Cli Sample/.gitignore b/C++/Sample/Cli Sample/.gitignore new file mode 100644 index 0000000..9715442 --- /dev/null +++ b/C++/Sample/Cli Sample/.gitignore @@ -0,0 +1,5 @@ +/.vs +/x64 +/*/Debug +/*/Release +/*/x64 \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CppApiSample.sln b/C++/Sample/Cli Sample/CppApiSample.sln index ad05423..9bea880 100644 --- a/C++/Sample/Cli Sample/CppApiSample.sln +++ b/C++/Sample/Cli Sample/CppApiSample.sln @@ -2,7 +2,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.329 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppApiSample", "CppApiSample\CppApiSample.vcxproj", "{9D365426-34B6-4EA6-AF93-293DACC8A03E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CpprestSample", "CpprestSample\CpprestSample.vcxproj", "{9D365426-34B6-4EA6-AF93-293DACC8A03E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CurlRapidjsonSample", "CurlRapidjsonSample\CurlRapidjsonSample.vcxproj", "{080A680E-5B2B-4FBA-B5EF-629C6284B55A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LowLevelSample", "LowLevelSample\LowLevelSample.vcxproj", "{4F3FA074-DD64-48BE-B226-241225052279}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -32,6 +36,38 @@ Global {9D365426-34B6-4EA6-AF93-293DACC8A03E}.RelWithDebInfo|x64.Build.0 = Release|x64 {9D365426-34B6-4EA6-AF93-293DACC8A03E}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 {9D365426-34B6-4EA6-AF93-293DACC8A03E}.RelWithDebInfo|x86.Build.0 = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Debug|x64.ActiveCfg = Debug|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Debug|x64.Build.0 = Debug|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Debug|x86.ActiveCfg = Debug|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Debug|x86.Build.0 = Debug|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.MinSizeRel|x64.Build.0 = Debug|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.MinSizeRel|x86.ActiveCfg = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.MinSizeRel|x86.Build.0 = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Release|x64.ActiveCfg = Release|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Release|x64.Build.0 = Release|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Release|x86.ActiveCfg = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.Release|x86.Build.0 = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.RelWithDebInfo|x64.Build.0 = Release|x64 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A}.RelWithDebInfo|x86.Build.0 = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.Debug|x64.ActiveCfg = Debug|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.Debug|x64.Build.0 = Debug|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.Debug|x86.ActiveCfg = Debug|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.Debug|x86.Build.0 = Debug|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.MinSizeRel|x64.Build.0 = Debug|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.MinSizeRel|x86.ActiveCfg = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.MinSizeRel|x86.Build.0 = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.Release|x64.ActiveCfg = Release|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.Release|x64.Build.0 = Release|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.Release|x86.ActiveCfg = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.Release|x86.Build.0 = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.RelWithDebInfo|x64.Build.0 = Release|x64 + {4F3FA074-DD64-48BE-B226-241225052279}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {4F3FA074-DD64-48BE-B226-241225052279}.RelWithDebInfo|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/C++/Sample/Cli Sample/CppApiSample/Debug/C++SpookTest.log b/C++/Sample/Cli Sample/CppApiSample/Debug/C++SpookTest.log deleted file mode 100644 index 6f7c6c8..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/Debug/C++SpookTest.log +++ /dev/null @@ -1,18 +0,0 @@ - pch.cpp - main.cpp -d:\repos\c++spooktest\c++spooktest\main.cpp(30): warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'std::string' -d:\repos\c++spooktest\c++spooktest\main.cpp(32): warning C4018: '<': signed/unsigned mismatch - PhantasmaAPI.cpp -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(129): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(147): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(198): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(216): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(249): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(281): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(556): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(578): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(630): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(650): warning C4018: '<': signed/unsigned mismatch -d:\repos\c++spooktest\c++spooktest\phantasmaapi.cpp(713): warning C4018: '<': signed/unsigned mismatch - Generating Code... - C++SpookTest.vcxproj -> D:\Repos\C++SpookTest\Debug\CppApiSample.exe diff --git a/C++/Sample/Cli Sample/CppApiSample/Debug/C++SpookTest.vcxproj.CopyComplete b/C++/Sample/Cli Sample/CppApiSample/Debug/C++SpookTest.vcxproj.CopyComplete deleted file mode 100644 index e69de29..0000000 diff --git a/C++/Sample/Cli Sample/CppApiSample/Debug/CppAPISample.Build.CppClean.log b/C++/Sample/Cli Sample/CppApiSample/Debug/CppAPISample.Build.CppClean.log deleted file mode 100644 index c886c2f..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/Debug/CppAPISample.Build.CppClean.log +++ /dev/null @@ -1,23 +0,0 @@ -d:\repos\c++spooktest\cppapisample\debug\cppapisample.pch -d:\repos\c++spooktest\cppapisample\debug\vc141.pdb -d:\repos\c++spooktest\cppapisample\debug\vc141.idb -d:\repos\c++spooktest\cppapisample\debug\pch.obj -d:\repos\c++spooktest\cppapisample\debug\phantasmaapi.obj -d:\repos\c++spooktest\cppapisample\debug\main.obj -d:\repos\c++spooktest\c++spooktest\debug\vcpkg.applocal.log -d:\repos\c++spooktest\debug\cpprest_2_10d.dll -d:\repos\c++spooktest\debug\boost_date_time-vc141-mt-gd-x32-1_69.dll -d:\repos\c++spooktest\debug\ssleay32.dll -d:\repos\c++spooktest\debug\libeay32.dll -d:\repos\c++spooktest\debug\zlibd1.dll -d:\repos\c++spooktest\cppapisample\debug\vcpkg.applocal.log -d:\repos\c++spooktest\debug\cppapisample.exe -d:\repos\c++spooktest\debug\cppapisample.ilk -d:\repos\c++spooktest\debug\cppapisample.pdb -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\cl.command.1.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\cl.read.1.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\cl.write.1.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\cppapisample.write.1u.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\link.command.1.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\link.read.1.tlog -d:\repos\c++spooktest\cppapisample\debug\cppapisample.tlog\link.write.1.tlog diff --git a/C++/Sample/Cli Sample/CppApiSample/Debug/CppApiSample.log b/C++/Sample/Cli Sample/CppApiSample/Debug/CppApiSample.log deleted file mode 100644 index 5f28270..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/Debug/CppApiSample.log +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CppApiSample/Debug/CppApiSample.vcxproj.CopyComplete b/C++/Sample/Cli Sample/CppApiSample/Debug/CppApiSample.vcxproj.CopyComplete deleted file mode 100644 index e69de29..0000000 diff --git a/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.cpp b/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.cpp deleted file mode 100644 index ca33cca..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.cpp +++ /dev/null @@ -1,719 +0,0 @@ -#include "pch.h" -#include "PhantasmaAPI.h" - -RPCRequest::RPCRequest(std::string method) -{ - requestBody = - { - {"jsonrpc", "2.0"}, - {"method", method}, - {"id", "1"}, - {"params", {}} - }; -} - -template -void RPCRequest::AddParameter(T param) -{ - requestBody["params"].emplace_back(param); -} - -json::value RPCRequest::BuildRequest() -{ - std::string str = requestBody.dump(); - return json::value::parse(converter.from_bytes(str)); -} - -template -void RPCRequest::AddParameter(T param, Args... params) -{ - AddParameter(param); - AddParameter(params...); -} - - -PhantasmaAPI::PhantasmaAPI(std::string host) -{ - apiHost = converter.from_bytes(host); -} - -PhantasmaAPI::~PhantasmaAPI() -= default; - -std::string PhantasmaAPI::FieldToString(value json, const string_t field) -{ - if(!json.has_string_field(field)) - { - std::string str1 = "Unexpected JSON format: missing string field "; - std::string str2 = (std::string) converter.to_bytes(field); - throw new std::exception(str1.append(str2).c_str()); - } - - return conversions::to_utf8string(json.at(field).as_string()); -} - -uint32_t PhantasmaAPI::FieldToNumber(value json, const string_t field) -{ - if (!json.has_number_field(field)) - { - std::string str1 = "Unexpected JSON format: missing number field "; - std::string str2 = (std::string) converter.to_bytes(field); - throw new std::exception(str1.append(str2).c_str()); - } - - return json.at(field).as_number().to_uint32(); -} - -json::value PhantasmaAPI::SendRequest(const json::value& body) -{ - http_client client(apiHost); - - // Build request URI and start the request. - uri_builder builder(U("/rpc")); - json::value output; - - pplx::task requestTask = client.request(methods::POST, builder.to_string(), body) - .then([&](http_response response) -> json::value // Handle response headers arriving. - { - const auto statusCode = response.status_code(); - printf("Received response status code:%u\n", statusCode); - - if (statusCode != 200) - throw http_exception("Malformed RPC request or endpoint: response status = " + statusCode); - - - response.content_ready().wait(); - - auto json = response.extract_json().then([&](value body) -> json::value - { - if (body.is_null()) - throw json_exception("Failed to parse JSON"); - - if (body.has_field(U("error"))) - throw std::exception(("Error: " + conversions::to_utf8string(body.at(U("error")).at(U("message")).as_string())).c_str()); - - if (!body.has_field(U("result"))) - throw json_exception("Malformed response: No \"result\" node on the JSON body"); - - return body.at(U("result")); - }).get(); - - return json; - }); - - try - { - output = requestTask.get(); - } - catch (const std::exception &e) - { - printf("Error exception:%s\n", e.what()); - } - - return output; -} - - -Balance PhantasmaAPI::DeserializeBalance(json::value json) -{ - std::string chain = FieldToString(json, U("chain")); - std::string amount = FieldToString(json, U("amount")); - std::string symbol = FieldToString(json, U("symbol")); - uint32_t decimals = FieldToNumber(json, U("decimals")); - - std::vector idsVector; - if(json.has_array_field(U("ids"))) - { - json::array idsJsonArray = json.at(U("ids")).as_array(); - - for(int i = 0; i < idsJsonArray.size(); i++) - { - idsVector.push_back(conversions::to_utf8string(idsJsonArray[i].as_string())); - } - } - return Balance { chain, amount, symbol, decimals, idsVector }; -} - -Account PhantasmaAPI::DeserializeAccount(json::value json) -{ - std::string address = FieldToString(json, U("address")); - std::string name = FieldToString(json, U("name")); - - std::vector balancesVector; - if(json.has_array_field(U("balances"))) - { - json::array balancesJsonArray = json.at(U("balances")).as_array(); - - for(int i = 0; i < balancesJsonArray.size(); i++) - { - balancesVector.push_back(DeserializeBalance(balancesJsonArray[i])); - } - } - return Account { address, name, balancesVector }; -} - -Chain PhantasmaAPI::DeserializeChain(json::value json) -{ - std::string name = FieldToString(json, U("name")); - std::string address = FieldToString(json, U("address")); - std::string parentAddress = FieldToString(json, U("parentAddress")); - uint32_t height = FieldToNumber(json, U("height")); - - return Chain { name, address, parentAddress, height }; -} - -App PhantasmaAPI::DeserializeApp(json::value json) -{ - std::string id = FieldToString(json, U("id")); - std::string title = FieldToString(json, U("title")); - std::string url = FieldToString(json, U("url")); - std::string description = FieldToString(json, U("description")); - std::string icon = FieldToString(json, U("icon")); - - return App { id, title, url, description, icon }; -} - -Event PhantasmaAPI::DeserializeEvent(json::value json) -{ - std::string address = FieldToString(json, U("address")); - std::string kind = FieldToString(json, U("kind")); - std::string data = FieldToString(json, U("data")); - - return Event { address, kind, data }; -} - -Transaction PhantasmaAPI::DeserializeTransaction(json::value json) -{ - std::string hash = FieldToString(json, U("hash")); - std::string chainAddress = FieldToString(json, U("chainAddress")); - uint32_t timestamp = FieldToNumber(json, U("timestamp")); - uint32_t blockHeight = FieldToNumber(json, U("blockHeight")); - std::string script = FieldToString(json, U("script")); - - std::vector eventsVector; - if(json.has_array_field(U("events"))) - { - json::array eventsJsonArray = json.at(U("events")).as_array(); - - for(int i = 0; i < eventsJsonArray.size(); i++) - { - eventsVector.push_back(DeserializeEvent(eventsJsonArray[i])); - } - } std::string result = FieldToString(json, U("result")); - - return Transaction { hash, chainAddress, timestamp, blockHeight, script, eventsVector, result }; -} - -AccountTransactions PhantasmaAPI::DeserializeAccountTransactions(json::value json) -{ - std::string address = FieldToString(json, U("address")); - - std::vector txsVector; - if(json.has_array_field(U("txs"))) - { - json::array txsJsonArray = json.at(U("txs")).as_array(); - - for(int i = 0; i < txsJsonArray.size(); i++) - { - txsVector.push_back(DeserializeTransaction(txsJsonArray[i])); - } - } - return AccountTransactions { address, txsVector }; -} - -Paginated PhantasmaAPI::DeserializePaginated(json::value json) -{ - uint32_t page = FieldToNumber(json, U("page")); - uint32_t pageSize = FieldToNumber(json, U("pageSize")); - uint32_t total = FieldToNumber(json, U("total")); - uint32_t totalPages = FieldToNumber(json, U("totalPages")); - json::value result = json.at(U("result")); - - return Paginated { page, pageSize, total, totalPages, result }; -} - -Block PhantasmaAPI::DeserializeBlock(json::value json) -{ - std::string hash = FieldToString(json, U("hash")); - std::string previousHash = FieldToString(json, U("previousHash")); - uint32_t timestamp = FieldToNumber(json, U("timestamp")); - uint32_t height = FieldToNumber(json, U("height")); - std::string chainAddress = FieldToString(json, U("chainAddress")); - std::string payload = FieldToString(json, U("payload")); - - std::vector txsVector; - if(json.has_array_field(U("txs"))) - { - json::array txsJsonArray = json.at(U("txs")).as_array(); - - for(int i = 0; i < txsJsonArray.size(); i++) - { - txsVector.push_back(DeserializeTransaction(txsJsonArray[i])); - } - } std::string validatorAddress = FieldToString(json, U("validatorAddress")); - std::string reward = FieldToString(json, U("reward")); - - return Block { hash, previousHash, timestamp, height, chainAddress, payload, txsVector, validatorAddress, reward }; -} - -TokenMetadata PhantasmaAPI::DeserializeTokenMetadata(json::value json) -{ - std::string key = FieldToString(json, U("key")); - std::string value = FieldToString(json, U("value")); - - return TokenMetadata { key, value }; -} - -Token PhantasmaAPI::DeserializeToken(json::value json) -{ - std::string symbol = FieldToString(json, U("symbol")); - std::string name = FieldToString(json, U("name")); - uint32_t decimals = FieldToNumber(json, U("decimals")); - std::string currentSupply = FieldToString(json, U("currentSupply")); - std::string maxSupply = FieldToString(json, U("maxSupply")); - std::string ownerAddress = FieldToString(json, U("ownerAddress")); - - std::vector metadataListVector; - if(json.has_array_field(U("metadataList"))) - { - json::array metadataListJsonArray = json.at(U("metadataList")).as_array(); - - for(int i = 0; i < metadataListJsonArray.size(); i++) - { - metadataListVector.push_back(DeserializeTokenMetadata(metadataListJsonArray[i])); - } - } std::string flags = FieldToString(json, U("flags")); - - return Token { symbol, name, decimals, currentSupply, maxSupply, ownerAddress, metadataListVector, flags }; -} - -TokenData PhantasmaAPI::DeserializeTokenData(json::value json) -{ - std::string ID = FieldToString(json, U("ID")); - std::string chainAddress = FieldToString(json, U("chainAddress")); - std::string ownerAddress = FieldToString(json, U("ownerAddress")); - std::string ram = FieldToString(json, U("ram")); - std::string rom = FieldToString(json, U("rom")); - - return TokenData { ID, chainAddress, ownerAddress, ram, rom }; -} - -TxConfirmation PhantasmaAPI::DeserializeTxConfirmation(json::value json) -{ - std::string hash = FieldToString(json, U("hash")); - std::string chainAddress = FieldToString(json, U("chainAddress")); - uint32_t confirmations = FieldToNumber(json, U("confirmations")); - uint32_t height = FieldToNumber(json, U("height")); - - return TxConfirmation { hash, chainAddress, confirmations, height }; -} - -SendRawTx PhantasmaAPI::DeserializeSendRawTx(json::value json) -{ - std::string hash = FieldToString(json, U("hash")); - std::string error = FieldToString(json, U("error")); - - return SendRawTx { hash, error }; -} - -Auction PhantasmaAPI::DeserializeAuction(json::value json) -{ - std::string creatorAddress = FieldToString(json, U("creatorAddress")); - uint32_t startDate = FieldToNumber(json, U("startDate")); - uint32_t endDate = FieldToNumber(json, U("endDate")); - std::string baseSymbol = FieldToString(json, U("baseSymbol")); - std::string quoteSymbol = FieldToString(json, U("quoteSymbol")); - std::string tokenId = FieldToString(json, U("tokenId")); - std::string price = FieldToString(json, U("price")); - - return Auction { creatorAddress, startDate, endDate, baseSymbol, quoteSymbol, tokenId, price }; -} - - -//Returns the account name and balance of given address. -Account PhantasmaAPI::GetAccount(std::string addressText) -{ - RPCRequest body("getAccount"); - body.AddParameter(addressText); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Account output; - - output = DeserializeAccount(jsonResponse); - - return output; -} - - -//Returns the height of a chain. -uint32_t PhantasmaAPI::GetBlockHeight(std::string chainInput) -{ - RPCRequest body("getBlockHeight"); - body.AddParameter(chainInput); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Returns the number of transactions of given block hash or error if given hash is invalid or is not found. -uint32_t PhantasmaAPI::GetBlockTransactionCountByHash(std::string blockHash) -{ - RPCRequest body("getBlockTransactionCountByHash"); - body.AddParameter(blockHash); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Returns information about a block by hash. -Block PhantasmaAPI::GetBlockByHash(std::string blockHash) -{ - RPCRequest body("getBlockByHash"); - body.AddParameter(blockHash); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Block output; - - output = DeserializeBlock(jsonResponse); - - return output; -} - - -//Returns a serialized string, containing information about a block by hash. -std::string PhantasmaAPI::GetRawBlockByHash(std::string blockHash) -{ - RPCRequest body("getRawBlockByHash"); - body.AddParameter(blockHash); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::string output; - - output = conversions::to_utf8string(jsonResponse.as_string()); - - return output; -} - - -//Returns information about a block by height and chain. -Block PhantasmaAPI::GetBlockByHeight(std::string chainInput, uint32_t height) -{ - RPCRequest body("getBlockByHeight"); - body.AddParameter(chainInput, height); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Block output; - - output = DeserializeBlock(jsonResponse); - - return output; -} - - -//Returns a serialized string, in hex format, containing information about a block by height and chain. -std::string PhantasmaAPI::GetRawBlockByHeight(std::string chainInput, uint32_t height) -{ - RPCRequest body("getRawBlockByHeight"); - body.AddParameter(chainInput, height); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::string output; - - output = conversions::to_utf8string(jsonResponse.as_string()); - - return output; -} - - -//Returns the information about a transaction requested by a block hash and transaction index. -Transaction PhantasmaAPI::GetTransactionByBlockHashAndIndex(std::string blockHash, uint32_t index) -{ - RPCRequest body("getTransactionByBlockHashAndIndex"); - body.AddParameter(blockHash, index); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Transaction output; - - output = DeserializeTransaction(jsonResponse); - - return output; -} - - -//Paginated api call: Returns last X transactions of given address. -AccountTransactions PhantasmaAPI::GetAddressTransactions(std::string addressText, uint32_t page, uint32_t pageSize) -{ - RPCRequest body("getAddressTransactions"); - body.AddParameter(addressText, page, pageSize); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - AccountTransactions output; - - Paginated pageStruct = DeserializePaginated(jsonResponse); - - output = DeserializeAccountTransactions(pageStruct.result); - - return output; -} -//Get number of transactions in a specific address and chain -uint32_t PhantasmaAPI::GetAddressTransactionCount(std::string addressText, std::string chainInput) -{ - RPCRequest body("getAddressTransactionCount"); - body.AddParameter(addressText, chainInput); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Returns the number of confirmations of given transaction hash and other useful info. -uint32_t PhantasmaAPI::GetConfirmations(std::string hashText) -{ - RPCRequest body("getConfirmations"); - body.AddParameter(hashText); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Allows to broadcast a signed operation on the network, but it's required to build it manually. -std::string PhantasmaAPI::SendRawTransaction(std::string txData) -{ - RPCRequest body("sendRawTransaction"); - body.AddParameter(txData); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::string output; - - output = conversions::to_utf8string(jsonResponse.as_string()); - - return output; -} - - -//Returns information about a transaction by hash. -Transaction PhantasmaAPI::GetTransaction(std::string hashText) -{ - RPCRequest body("getTransaction"); - body.AddParameter(hashText); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Transaction output; - - output = DeserializeTransaction(jsonResponse); - - return output; -} - - -//Removes a pending transaction from the mempool. -std::string PhantasmaAPI::CancelTransaction(std::string hashText) -{ - RPCRequest body("cancelTransaction"); - body.AddParameter(hashText); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::string output; - - output = conversions::to_utf8string(jsonResponse.as_string()); - - return output; -} - - -//Returns an array of all chains deployed in Phantasma. -std::vector PhantasmaAPI::GetChains() -{ - RPCRequest body("getChains"); - - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::vector output; - - if (!jsonResponse.is_array()) - throw json_exception("Malformed response: No JSON array on the \"result\" node"); - - json::array resultArray = jsonResponse.as_array(); - for(int i = 0; i < resultArray.size(); i++) - { - output.push_back(DeserializeChain(resultArray[i])); - } - - return output; -} - - -//Returns an array of tokens deployed in Phantasma. -std::vector PhantasmaAPI::GetTokens() -{ - RPCRequest body("getTokens"); - - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::vector output; - - if (!jsonResponse.is_array()) - throw json_exception("Malformed response: No JSON array on the \"result\" node"); - - json::array resultArray = jsonResponse.as_array(); - for(int i = 0; i < resultArray.size(); i++) - { - output.push_back(DeserializeToken(resultArray[i])); - } - - return output; -} - - -//Returns info about a specific token deployed in Phantasma. -Token PhantasmaAPI::GetToken(std::string symbol) -{ - RPCRequest body("getToken"); - body.AddParameter(symbol); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Token output; - - output = DeserializeToken(jsonResponse); - - return output; -} - - -//Returns data of a non-fungible token, in hexadecimal format. -TokenData PhantasmaAPI::GetTokenData(std::string symbol, std::string IDtext) -{ - RPCRequest body("getTokenData"); - body.AddParameter(symbol, IDtext); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - TokenData output; - - output = DeserializeTokenData(jsonResponse); - - return output; -} - - -//Returns an array of apps deployed in Phantasma. -std::vector PhantasmaAPI::GetApps() -{ - RPCRequest body("getApps"); - - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::vector output; - - if (!jsonResponse.is_array()) - throw json_exception("Malformed response: No JSON array on the \"result\" node"); - - json::array resultArray = jsonResponse.as_array(); - for(int i = 0; i < resultArray.size(); i++) - { - output.push_back(DeserializeApp(resultArray[i])); - } - - return output; -} - - -//Paginated api call: Returns last X transactions of given token. -std::vector PhantasmaAPI::GetTokenTransfers(std::string tokenSymbol, uint32_t page, uint32_t pageSize) -{ - RPCRequest body("getTokenTransfers"); - body.AddParameter(tokenSymbol, page, pageSize); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::vector output; - - Paginated pageStruct = DeserializePaginated(jsonResponse); - - for(int i = 0; i < pageStruct.result.size(); i++) - { - output.push_back(DeserializeTransaction(pageStruct.result[i])); - } - - return output; -} -//Returns the number of transaction of a given token. -uint32_t PhantasmaAPI::GetTokenTransferCount(std::string tokenSymbol) -{ - RPCRequest body("getTokenTransferCount"); - body.AddParameter(tokenSymbol); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Returns the balance for a specific token and chain, given an address. -Balance PhantasmaAPI::GetTokenBalance(std::string addressText, std::string tokenSymbol, std::string chainInput) -{ - RPCRequest body("getTokenBalance"); - body.AddParameter(addressText, tokenSymbol, chainInput); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - Balance output; - - output = DeserializeBalance(jsonResponse); - - return output; -} - - -//Returns the number of active auctions. -uint32_t PhantasmaAPI::GetAuctionsCount(std::string symbol) -{ - RPCRequest body("getAuctionsCount"); - body.AddParameter(symbol); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - uint32_t output; - - output = jsonResponse.as_number().to_uint32(); - - return output; -} - - -//Paginated api call: Returns the auctions available in the market. -std::vector PhantasmaAPI::GetAuctions(std::string symbol, uint32_t page, uint32_t pageSize) -{ - RPCRequest body("getAuctions"); - body.AddParameter(symbol, page, pageSize); - json::value request = body.BuildRequest(); - json::value jsonResponse = SendRequest(request); - std::vector output; - - Paginated pageStruct = DeserializePaginated(jsonResponse); - - for(int i = 0; i < pageStruct.result.size(); i++) - { - output.push_back(DeserializeAuction(pageStruct.result[i])); - } - - return output; -} diff --git a/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.h b/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.h deleted file mode 100644 index f11e7d5..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/PhantasmaAPI.h +++ /dev/null @@ -1,305 +0,0 @@ -#include "pch.h" -#include -#include -#include // JSON library -#include // WebSocket client -#include -#include -#include -#include - -using namespace utility; // Common utilities like string conversions -using namespace web; // Common features like URIs. -using namespace http; // Common HTTP functionality -using namespace client; // HTTP client features -using namespace concurrency::streams; // Asynchronous streams -using namespace json; // JSON library - -#pragma once - - -struct Balance -{ - std::string chain;// - std::string amount;// - std::string symbol;// - uint32_t decimals;// - std::vector ids;// -}; - -struct Account -{ - std::string address;// - std::string name;// - std::vector balances;// -}; - -struct Chain -{ - std::string name;// - std::string address;// - std::string parentAddress;// - uint32_t height;// -}; - -struct App -{ - std::string id;// - std::string title;// - std::string url;// - std::string description;// - std::string icon;// -}; - -struct Event -{ - std::string address;// - std::string kind;// - std::string data;// -}; - -struct Transaction -{ - std::string hash;// - std::string chainAddress;// - uint32_t timestamp;// - uint32_t blockHeight;// - std::string script;// - std::vector events;// - std::string result;// -}; - -struct AccountTransactions -{ - std::string address;// - std::vector txs;// -}; - -struct Paginated -{ - uint32_t page;// - uint32_t pageSize;// - uint32_t total;// - uint32_t totalPages;// - json::value result;// -}; - -struct Block -{ - std::string hash;// - std::string previousHash;// - uint32_t timestamp;// - uint32_t height;// - std::string chainAddress;// - std::string payload;// - std::vector txs;// - std::string validatorAddress;// - std::string reward;// -}; - -struct TokenMetadata -{ - std::string key;// - std::string value;// -}; - -struct Token -{ - std::string symbol;// - std::string name;// - uint32_t decimals;// - std::string currentSupply;// - std::string maxSupply;// - std::string ownerAddress;// - std::vector metadataList;// - std::string flags;// -}; - -struct TokenData -{ - std::string ID;// - std::string chainAddress;// - std::string ownerAddress;// - std::string ram;// - std::string rom;// -}; - -struct TxConfirmation -{ - std::string hash;// - std::string chainAddress;// - uint32_t confirmations;// - uint32_t height;// -}; - -struct SendRawTx -{ - std::string hash;// - std::string error;// -}; - -struct Auction -{ - std::string creatorAddress;// - uint32_t startDate;// - uint32_t endDate;// - std::string baseSymbol;// - std::string quoteSymbol;// - std::string tokenId;// - std::string price;// -}; - - -class RPCRequest -{ -private: - std::wstring_convert> converter; //to convert from std::string to std::wstring - nlohmann::json requestBody; - -public: - template - void AddParameter(T param); - - template - void AddParameter(T param, Args... args); - - RPCRequest(std::string); - - json::value BuildRequest(); -}; - -class PhantasmaAPI -{ -protected: - std::wstring_convert> converter; //to convert from std::string to std::wstring - - std::wstring apiHost; - - std::string FieldToString(json::value json, const string_t field); - uint32_t FieldToNumber(json::value json, const string_t field); - - json::value SendRequest(const json::value& body); - - Balance DeserializeBalance(json::value json); - Account DeserializeAccount(json::value json); - Chain DeserializeChain(json::value json); - App DeserializeApp(json::value json); - Event DeserializeEvent(json::value json); - Transaction DeserializeTransaction(json::value json); - AccountTransactions DeserializeAccountTransactions(json::value json); - Paginated DeserializePaginated(json::value json); - Block DeserializeBlock(json::value json); - TokenMetadata DeserializeTokenMetadata(json::value json); - Token DeserializeToken(json::value json); - TokenData DeserializeTokenData(json::value json); - TxConfirmation DeserializeTxConfirmation(json::value json); - SendRawTx DeserializeSendRawTx(json::value json); - Auction DeserializeAuction(json::value json); - - -public: - PhantasmaAPI(std::string host); - ~PhantasmaAPI(); - - //Returns the account name and balance of given address. - Account GetAccount(std::string addressText); - - - //Returns the height of a chain. - uint32_t GetBlockHeight(std::string chainInput); - - - //Returns the number of transactions of given block hash or error if given hash is invalid or is not found. - uint32_t GetBlockTransactionCountByHash(std::string blockHash); - - - //Returns information about a block by hash. - Block GetBlockByHash(std::string blockHash); - - - //Returns a serialized string, containing information about a block by hash. - std::string GetRawBlockByHash(std::string blockHash); - - - //Returns information about a block by height and chain. - Block GetBlockByHeight(std::string chainInput, uint32_t height); - - - //Returns a serialized string, in hex format, containing information about a block by height and chain. - std::string GetRawBlockByHeight(std::string chainInput, uint32_t height); - - - //Returns the information about a transaction requested by a block hash and transaction index. - Transaction GetTransactionByBlockHashAndIndex(std::string blockHash, uint32_t index); - - - //Returns last X transactions of given address. - //paginated call - AccountTransactions GetAddressTransactions(std::string addressText, uint32_t page, uint32_t pageSize); - - - //Get number of transactions in a specific address and chain - uint32_t GetAddressTransactionCount(std::string addressText, std::string chainInput); - - - //Returns the number of confirmations of given transaction hash and other useful info. - uint32_t GetConfirmations(std::string hashText); - - - //Allows to broadcast a signed operation on the network, but it's required to build it manually. - std::string SendRawTransaction(std::string txData); - - - //Returns information about a transaction by hash. - Transaction GetTransaction(std::string hashText); - - - //Removes a pending transaction from the mempool. - std::string CancelTransaction(std::string hashText); - - - //Returns an array of all chains deployed in Phantasma. - std::vector GetChains(); - - - //Returns an array of tokens deployed in Phantasma. - std::vector GetTokens(); - - - //Returns info about a specific token deployed in Phantasma. - Token GetToken(std::string symbol); - - - //Returns data of a non-fungible token, in hexadecimal format. - TokenData GetTokenData(std::string symbol, std::string IDtext); - - - //Returns an array of apps deployed in Phantasma. - std::vector GetApps(); - - - //Returns last X transactions of given token. - //paginated call - std::vector GetTokenTransfers(std::string tokenSymbol, uint32_t page, uint32_t pageSize); - - - //Returns the number of transaction of a given token. - uint32_t GetTokenTransferCount(std::string tokenSymbol); - - - //Returns the balance for a specific token and chain, given an address. - Balance GetTokenBalance(std::string addressText, std::string tokenSymbol, std::string chainInput); - - - //Returns the number of active auctions. - uint32_t GetAuctionsCount(std::string symbol); - - - //Returns the auctions available in the market. - //paginated call - std::vector GetAuctions(std::string symbol, uint32_t page, uint32_t pageSize); - - - -}; - diff --git a/C++/Sample/Cli Sample/CppApiSample/main.cpp b/C++/Sample/Cli Sample/CppApiSample/main.cpp deleted file mode 100644 index cae413b..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// C++SpookTest.cpp : This file contains the 'main' function. Program execution begins and ends there. -// -#include "pch.h" -#include -#include // HTTP server -#include // JSON library -#include // Async streams backed by raw pointer to memory -#include "PhantasmaAPI.h" -#include - -using namespace utility; // Common utilities like string conversions -using namespace web; // Common features like URIs. -using namespace web::http; // Common HTTP functionality -using namespace web::http::client; // HTTP client features -using namespace concurrency::streams; // Asynchronous streams -using namespace web::json; // JSON library - -int main() -{ - std::string host = "http://localhost:7077"; - PhantasmaAPI api(host); - - //std::wstring address = L"P2f7ZFuj6NfZ76ymNMnG3xRBT5hAMicDrQRHE4S7SoxEr"; //genesis address - //std::wstring address = L"NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; //nft address - - std::string wif = "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; - - Account account = api.GetAccount(wif); - - printf("Balance description for address %s", wif); - - for (int i = 0; i < account.balances.size(); i++) - { - std::wstring_convert> converter; - std::wostringstream os; - os << converter.from_bytes(account.balances[i].amount) << " " << converter.from_bytes(account.balances[i].symbol) << " tokens available on " << converter.from_bytes(account.balances[i].chain) << " chain" << std::endl; - OutputDebugString((os.str().c_str())); - } -} diff --git a/C++/Sample/Cli Sample/CppApiSample/packages.config b/C++/Sample/Cli Sample/CppApiSample/packages.config deleted file mode 100644 index 5452db3..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CppApiSample/pch.cpp b/C++/Sample/Cli Sample/CppApiSample/pch.cpp deleted file mode 100644 index 3a3d12b..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/pch.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// pch.cpp: source file corresponding to pre-compiled header; necessary for compilation to succeed - -#include "pch.h" - -// In general, ignore this file, but keep it around if you are using pre-compiled headers. diff --git a/C++/Sample/Cli Sample/CppApiSample/pch.h b/C++/Sample/Cli Sample/CppApiSample/pch.h deleted file mode 100644 index b04e71e..0000000 --- a/C++/Sample/Cli Sample/CppApiSample/pch.h +++ /dev/null @@ -1,14 +0,0 @@ -// Tips for Getting Started: -// 1. Use the Solution Explorer window to add/manage files -// 2. Use the Team Explorer window to connect to source control -// 3. Use the Output window to see build output and other messages -// 4. Use the Error List window to view errors -// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project -// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file - -#ifndef PCH_H -#define PCH_H - -// TODO: add headers that you want to pre-compile here - -#endif //PCH_H diff --git a/C++/Sample/Cli Sample/CppApiSample/CppApiSample.filters b/C++/Sample/Cli Sample/CpprestSample/CpprestSample.filters similarity index 81% rename from C++/Sample/Cli Sample/CppApiSample/CppApiSample.filters rename to C++/Sample/Cli Sample/CpprestSample/CpprestSample.filters index 0b1567e..1b900b4 100644 --- a/C++/Sample/Cli Sample/CppApiSample/CppApiSample.filters +++ b/C++/Sample/Cli Sample/CpprestSample/CpprestSample.filters @@ -15,20 +15,14 @@ - - Header Files - - + Header Files - + Header Files - - Source Files - Source Files @@ -36,7 +30,4 @@ Source Files - - - \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CppApiSample/CppApiSample.vcxproj b/C++/Sample/Cli Sample/CpprestSample/CpprestSample.vcxproj similarity index 78% rename from C++/Sample/Cli Sample/CppApiSample/CppApiSample.vcxproj rename to C++/Sample/Cli Sample/CpprestSample/CpprestSample.vcxproj index 69e2fdb..ea02c90 100644 --- a/C++/Sample/Cli Sample/CppApiSample/CppApiSample.vcxproj +++ b/C++/Sample/Cli Sample/CpprestSample/CpprestSample.vcxproj @@ -24,7 +24,7 @@ Win32Proj CSpookTest 10.0.17763.0 - CppAPISample + CpprestSample @@ -94,7 +94,6 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - pch.h Console @@ -104,17 +103,19 @@ - Use + NotUsing Level3 Disabled true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WINSOCK_DEPRECATED_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - pch.h + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) Console true + D:\Projects\vcpkg\installed\x64-windows\lib + libeay32.lib;ssleay32.lib;cpprest_2_10.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -127,7 +128,6 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - pch.h Console @@ -138,49 +138,33 @@ - Use + NotUsing Level3 MaxSpeed true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WINSOCK_DEPRECATED_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - pch.h + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) Console true true true + D:\Projects\vcpkg\installed\x64-windows\lib + libeay32.lib;ssleay32.lib;cpprest_2_10.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Create - Create - Create - Create - - + - + - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CppApiSample/CppApiSample.vcxproj.user b/C++/Sample/Cli Sample/CpprestSample/CpprestSample.vcxproj.user similarity index 100% rename from C++/Sample/Cli Sample/CppApiSample/CppApiSample.vcxproj.user rename to C++/Sample/Cli Sample/CpprestSample/CpprestSample.vcxproj.user diff --git a/C++/Sample/Cli Sample/CpprestSample/PhantasmaAPI.h b/C++/Sample/Cli Sample/CpprestSample/PhantasmaAPI.h new file mode 100644 index 0000000..03cfe05 --- /dev/null +++ b/C++/Sample/Cli Sample/CpprestSample/PhantasmaAPI.h @@ -0,0 +1,2033 @@ +#pragma once +//------------------------------------------------------------------------------ +// Low-level API +//------------------------------------------------------------------------------ +// The PhantasmaJsonAPI namespace can construct JSON requests and parse JSON responses, +// but you are responsible for sending/receiving these messages via HTTP on your own. +// You can call PhantasmaJsonAPI::Uri() to determine where to send them. +// +// void PhantasmaJsonAPI::Make{Message}Request(JSONBuilder&, {Parameters}); +// bool PhantasmaJsonAPI::Parse{Message}Response(const JSONValue&, {Output}); +// +//------------------------------------------------------------------------------ +// High-level API +//------------------------------------------------------------------------------ +// If you have defined PHANTASMA_HTTPCLIENT, then you can construct a PhantasmaAPI object, +// which provides a simplified API that hides the internal JSON messaging. +// +// PhantasmaAPI phantasmaAPI(httpClient); +// {Output} phantasmaAPI->{Message}({Parameters}); +// +//------------------------------------------------------------------------------ +// API configuration +//------------------------------------------------------------------------------ +// As different C++ projects may use different primitive types, you can use the +// following #defines (BEFORE including phantasma.h) to override the default types. +// +// #define | typedef | Default | Notes +// PHANTASMA_INT32 | phantasma::Int32 | int32_t | +// PHANTASMA_UINT32 | phantasma::UInt32 | uint32_t | +// PHANTASMA_CHAR | phantasma::Char | char | See Unicode section +// PHANTASMA_STRING | phantasma::String | std::string | Must support construction from `const phantasma::Char*` +// PHANTASMA_VECTOR | | std::vector | Must support `push_back` and `size` members +// PHANTASMA_JSONVALUE | phantasma::JSONValue | std::string_view | See JSON section +// PHANTASMA_JSONARRAY | phantasma::JSONArray | JSONValue | See JSON section +// PHANTASMA_JSONDOCUMENT| phantasma::JSONDocument| std::string | See JSON section +// PHANTASMA_JSONBUILDER | phantasma::JSONBuilder | std::stringstream*| See JSON section +// PHANTASMA_HTTPCLIENT | phantasma::HttpClient | | See HTTP section +// +// The behavior of this header can further be modified by using the following +// #defines (BEFORE including phantasma.h) +// +// #define | Notes +// PHANTASMA_EXCEPTION(message) | See Exceptions section +// PHANTASMA_EXCEPTION_MESSAGE(message, String) | See Exceptions section +// PHANTASMA_LITERAL(x) | See Unicode section +// PHANTASMA_FUNCTION | See Integration section +// PHANTASMA_IMPLEMENTATION | See Integration section +// +//------------------------------------------------------------------------------ +// Integration +//------------------------------------------------------------------------------ +// This API is provided in the "single header" style to support simple and flexible +// integration into your project (see https://github.com/nothings/single_file_libs). +// The implementation of function bodies will be excluded unless you define +// PHANTASMA_IMPLEMENTATION before including phantasma.h. +// +// Typical linking: +// In one CPP file, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// +// Inline linking: +// In every CPP file that uses the API, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// #define PHANTASMA_FUNCTION inline +// +// Aside from PHANTASMA_IMPLEMENTATION / PHANTASMA_FUNCTION, you should take care +// to ensure that every other PHANTASMA_* macro is defined to the same value in +// all of yoru CPP files that use the phantasma API. +// +//------------------------------------------------------------------------------ +// Exceptions +//------------------------------------------------------------------------------ +// Support for C++ exceptions is opt-in. Define the following (or an alternative +// based on your own exception classes) before including phantasma.h: +// #define PHANTASMA_EXCEPTION(message) throw std::runtime_error(message) +// #define PHANTASMA_EXCEPTION_MESSAGE(message, string) throw std::runtime_error(string) +// +//------------------------------------------------------------------------------ +// Unicode +//------------------------------------------------------------------------------ +// To build a wide-character version of the API, define the following before +// including phantasma.h: +// #define PHANTASMA_CHAR wchar_t +// #define PHANTASMA_LITERAL(x) L ## x +// #define PHANTASMA_STRING std::wstring +// +// You should also provide a JSON and HTTP library with wide-character support. +// +//------------------------------------------------------------------------------ +// JSON +//------------------------------------------------------------------------------ +// This header contains JSON parsing and building code, but it is written to be +// as simple as possible (approx 200 lines of code) and is not high-performance +// or highly robust. +// +// It is recommended that you supply another JSON-parsing API, by defining the +// following macros before including phantasma.h: +// #define PHANTASMA_JSONVALUE Your_Json_Value_Type +// #define PHANTASMA_JSONARRAY Your_Json_Array_Type +// #define PHANTASMA_JSONDOCUMENT Your_JSON_Document_Type +// #define PHANTASMA_JSONBUILDER Your_Json_Serializer_Type +// +// Also, this header uses the following procedural API to interact with these types. +// If you have supplied your own JSON types, you must implement the following functions: +// +// namespace phantasma { namespace json { +// +// JSONValue Parse(const JSONDocument&); +// +// Int32 LookupInt32( const JSONValue&, const Char* field, bool& out_error); +// UInt32 LookupUInt32( const JSONValue&, const Char* field, bool& out_error); +// String LookupString( const JSONValue&, const Char* field, bool& out_error); +// JSONValue LookupValue( const JSONValue&, const Char* field, bool& out_error); +// JSONArray LookupArray( const JSONValue&, const Char* field, bool& out_error); +// bool HasField( const JSONValue&, const Char* field, bool& out_error); +// bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); +// +// Int32 AsInt32( const JSONValue&, bool& out_error); +// UInt32 AsUInt32( const JSONValue&, bool& out_error); +// String AsString( const JSONValue&, bool& out_error); +// JSONArray AsArray( const JSONValue&, bool& out_error); +// bool IsArray( const JSONValue&, bool& out_error); +// bool IsObject( const JSONValue&, bool& out_error); +// +// int ArraySize( const JSONArray&, bool& out_error); +// JSONValue IndexArray( const JSONArray&, int index, bool& out_error); +// +// void BeginObject(JSONBuilder&); +// void AddString (JSONBuilder&, const Char* key, const Char* value); +// template void AddArray (JSONBuilder&, const Char* key, Args...); +// void EndObject (JSONBuilder&); +// }} +// +//------------------------------------------------------------------------------ +// HTTP +//------------------------------------------------------------------------------ +// This header does not contain a HTTP client, nor a dependency on any specific +// HTTP client library. If you do not supply a HTTP client library, then only +// the Low-level phantasma API (PhantasmaJsonAPI) is available. +// +// To enable the PhantasmaAPI class, defining the following macro before +// including phantasma.h: +// #define PHANTASMA_HTTPCLIENT Your_HTTP_Client_Type +// +// Also, this header uses the following procedural API to interact with this type. +// If you have defined PHANTASMA_HTTPCLIENT, you must implement the following, +// function, which should perform a HTTP POST request and return the result: +// +// namespace phantasma { +// JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +// } +// +//------------------------------------------------------------------------------ + +#if !defined(PHANTASMA_STRING) || !defined(PHANTASMA_JSONDOCUMENT) || !defined(PHANTASMA_JSONVALUE) +#include +#endif + +#if !defined(PHANTASMA_JSONVALUE) && __cplusplus > 201402L +#include +#endif + +#if !defined(PHANTASMA_JSONBUILDER) +#include +#endif + +#if !defined(PHANTASMA_VECTOR) +#define PHANTASMA_VECTOR std::vector +#include +#endif + +#if !defined(PHANTASMA_S32) || !defined(PHANTASMA_U32) +#include +#endif + +#if !defined(PHANTASMA_EXCEPTION) +#define PHANTASMA_EXCEPTION(literal) +#define PHANTASMA_EXCEPTION_MESSAGE(literal, string) +#endif + +#if !defined(PHANTASMA_LITERAL) +#define PHANTASMA_LITERAL(x) x +#endif + +#if !defined(PHANTASMA_FUNCTION) +#define PHANTASMA_FUNCTION +#endif + +namespace phantasma +{ +#ifdef PHANTASMA_CHAR +typedef PHANTASMA_CHAR Char; +#else +typedef char Char; +#endif + +#ifdef PHANTASMA_INT32 +typedef PHANTASMA_INT32 Int32; +#else +typedef int32_t Int32; +#endif + +#ifdef PHANTASMA_UINT32 +typedef PHANTASMA_UINT32 UInt32; +#else +typedef uint32_t UInt32; +#endif + +#ifdef PHANTASMA_STRING +typedef PHANTASMA_STRING String; +#else +typedef std::string String; +#endif + +#ifdef PHANTASMA_JSONVALUE +typedef PHANTASMA_JSONVALUE JSONValue; +#elif __cplusplus > 201402L +typedef std::string_view JSONValue; +#else +typedef std::string JSONValue; +#endif + +#ifdef PHANTASMA_JSONARRAY +typedef PHANTASMA_JSONARRAY JSONArray; +#else +typedef JSONValue JSONArray; +#endif + +#ifdef PHANTASMA_JSONDOCUMENT +typedef PHANTASMA_JSONDOCUMENT JSONDocument; +#else +typedef std::string JSONDocument; +#endif + + +#ifdef PHANTASMA_JSONBUILDER +typedef PHANTASMA_JSONBUILDER JSONBuilder; +#else +struct JSONBuilder // A VERY simple json string builder. Highly recommended that you provide a real JSON library instead! +{ + std::stringstream s; + bool empty = true; + operator std::stringstream&() { return s; } + void AddKey(const Char* key) { if(!empty) { s << ", "; } empty = false; s << '"' << key << "\": "; } + void AddValues() {} + void AddValues(const char* arg) { s << '"' << arg << '"'; } + template void AddValues(T arg) { s << arg; } + template void AddValues(T arg0, Args... args) { AddValues(arg0); s << ", "; AddValues(args...); } + + void BeginObject() { s << "{"; } + void AddString(const Char* key, const Char* value) { AddKey(key); s << '"' << value << '"'; } + template void AddArray(const Char* key, Args... args) { AddKey(key); s << '['; AddValues(args...); s << ']'; } + void EndObject() { s << "}"; } +}; +#endif + +#ifdef PHANTASMA_HTTPCLIENT +typedef PHANTASMA_HTTPCLIENT HttpClient; +//JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +#endif + +//If providing a JSON library (highly recommended that you do!), then you must provide these functions yourself: +namespace json +{ +#ifndef PHANTASMA_JSONBUILDER + JSONValue Parse(const JSONDocument&); + Int32 LookupInt32(const JSONValue&, const Char* field, bool& out_error); + UInt32 LookupUInt32(const JSONValue&, const Char* field, bool& out_error); + String LookupString(const JSONValue&, const Char* field, bool& out_error); + JSONValue LookupValue(const JSONValue&, const Char* field, bool& out_error); + JSONArray LookupArray(const JSONValue&, const Char* field, bool& out_error); + bool HasField(const JSONValue&, const Char* field, bool& out_error); + bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); + Int32 AsInt32(const JSONValue&, bool& out_error); + UInt32 AsUInt32(const JSONValue&, bool& out_error); + String AsString(const JSONValue&, bool& out_error); + JSONArray AsArray(const JSONValue&, bool& out_error); + bool IsArray(const JSONValue&, bool& out_error); + bool IsObject(const JSONValue&, bool& out_error); + + int ArraySize(const JSONArray&, bool& out_error); + JSONValue IndexArray(const JSONArray&, int index, bool& out_error); + + void BeginObject(JSONBuilder&); + void AddString(JSONBuilder&, const Char* key, const Char* value); + template + void AddArray(JSONBuilder&, const Char* key, Args... args); + void EndObject(JSONBuilder&); +#endif +} + + +struct Balance +{ + String chain;// + String amount;// + String symbol;// + UInt32 decimals;// + PHANTASMA_VECTOR ids;// +}; + +struct Account +{ + String address;// + String name;// + PHANTASMA_VECTOR balances;// +}; + +struct Chain +{ + String name;// + String address;// + String parentAddress;// + UInt32 height;// +}; + +struct App +{ + String id;// + String title;// + String url;// + String description;// + String icon;// +}; + +struct Event +{ + String address;// + String kind;// + String data;// +}; + +struct Transaction +{ + String hash;// + String chainAddress;// + UInt32 timestamp;// + Int32 confirmations;// + UInt32 blockHeight;// + String blockHash;// + String script;// + PHANTASMA_VECTOR events;// + String result;// +}; + +struct AccountTransactions +{ + String address;// + PHANTASMA_VECTOR txs;// +}; + +struct Paginated +{ + UInt32 page;// + UInt32 pageSize;// + UInt32 total;// + UInt32 totalPages;// + JSONValue result;// +}; + +struct Block +{ + String hash;// + String previousHash;// + UInt32 timestamp;// + UInt32 height;// + String chainAddress;// + String payload;// + PHANTASMA_VECTOR txs;// + String validatorAddress;// + String reward;// +}; + +struct TokenMetadata +{ + String key;// + String value;// +}; + +struct Token +{ + String symbol;// + String name;// + Int32 decimals;// + String currentSupply;// + String maxSupply;// + String ownerAddress;// + PHANTASMA_VECTOR metadataList;// + String flags;// +}; + +struct TokenData +{ + String ID;// + String chainAddress;// + String ownerAddress;// + String ram;// + String rom;// + bool forSale;// +}; + +struct SendRawTx +{ + String hash;// + String error;// +}; + +struct Auction +{ + String creatorAddress;// + UInt32 startDate;// + UInt32 endDate;// + String baseSymbol;// + String quoteSymbol;// + String tokenId;// + String price;// +}; + +struct Script +{ + PHANTASMA_VECTOR events;// + String result;// +}; + + +class PhantasmaJsonAPI +{ +public: + static const Char* Uri() { return PHANTASMA_LITERAL("/rpc"); } + + // Returns the account name and balance of given address. + static void MakeGetAccountRequest(JSONBuilder&, const Char* addressText); + static bool ParseGetAccountResponse(const JSONValue&, Account& out); + // Returns the address that owns a given name. + static void MakeLookUpNameRequest(JSONBuilder&, const Char* name); + static bool ParseLookUpNameResponse(const JSONValue&, String& out); + // Returns the height of a chain. + static void MakeGetBlockHeightRequest(JSONBuilder&, const Char* chainInput); + static bool ParseGetBlockHeightResponse(const JSONValue&, Int32& out); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + static void MakeGetBlockTransactionCountByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockTransactionCountByHashResponse(const JSONValue&, Int32& out); + // Returns information about a block by hash. + static void MakeGetBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockByHashResponse(const JSONValue&, Block& out); + // Returns a serialized string, containing information about a block by hash. + static void MakeGetRawBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetRawBlockByHashResponse(const JSONValue&, String& out); + // Returns information about a block by height and chain. + static void MakeGetBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetBlockByHeightResponse(const JSONValue&, Block& out); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + static void MakeGetRawBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetRawBlockByHeightResponse(const JSONValue&, String& out); + // Returns the information about a transaction requested by a block hash and transaction index. + static void MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder&, const Char* blockHash, Int32 index); + static bool ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue&, Transaction& out); + // Returns last X transactions of given address. (paginated call) + static void MakeGetAddressTransactionsRequest(JSONBuilder&, const Char* addressText, UInt32 page, UInt32 pageSize); + static bool ParseGetAddressTransactionsResponse(const JSONValue&, AccountTransactions& out); + // Get number of transactions in a specific address and chain + static void MakeGetAddressTransactionCountRequest(JSONBuilder&, const Char* addressText, const Char* chainInput); + static bool ParseGetAddressTransactionCountResponse(const JSONValue&, Int32& out); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + static void MakeSendRawTransactionRequest(JSONBuilder&, const Char* txData); + static bool ParseSendRawTransactionResponse(const JSONValue&, String& out); + // Allows to invoke script based on network state, without state changes. + static void MakeInvokeRawScriptRequest(JSONBuilder&, const Char* chainInput, const Char* scriptData); + static bool ParseInvokeRawScriptResponse(const JSONValue&, Script& out); + // Returns information about a transaction by hash. + static void MakeGetTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseGetTransactionResponse(const JSONValue&, Transaction& out); + // Removes a pending transaction from the mempool. + static void MakeCancelTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseCancelTransactionResponse(const JSONValue&, String& out); + // Returns an array of all chains deployed in Phantasma. + static void MakeGetChainsRequest(JSONBuilder&); + static bool ParseGetChainsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns an array of tokens deployed in Phantasma. + static void MakeGetTokensRequest(JSONBuilder&); + static bool ParseGetTokensResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns info about a specific token deployed in Phantasma. + static void MakeGetTokenRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetTokenResponse(const JSONValue&, Token& out); + // Returns data of a non-fungible token, in hexadecimal format. + static void MakeGetTokenDataRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetTokenDataResponse(const JSONValue&, TokenData& out); + // Returns an array of apps deployed in Phantasma. + static void MakeGetAppsRequest(JSONBuilder&); + static bool ParseGetAppsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns last X transactions of given token. (paginated call) + static void MakeGetTokenTransfersRequest(JSONBuilder&, const Char* tokenSymbol, UInt32 page, UInt32 pageSize); + static bool ParseGetTokenTransfersResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the number of transaction of a given token. + static void MakeGetTokenTransferCountRequest(JSONBuilder&, const Char* tokenSymbol); + static bool ParseGetTokenTransferCountResponse(const JSONValue&, Int32& out); + // Returns the balance for a specific token and chain, given an address. + static void MakeGetTokenBalanceRequest(JSONBuilder&, const Char* addressText, const Char* tokenSymbol, const Char* chainInput); + static bool ParseGetTokenBalanceResponse(const JSONValue&, Balance& out); + // Returns the number of active auctions. + static void MakeGetAuctionsCountRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetAuctionsCountResponse(const JSONValue&, Int32& out); + // Returns the auctions available in the market. (paginated call) + static void MakeGetAuctionsRequest(JSONBuilder&, const Char* symbol, UInt32 page, UInt32 pageSize); + static bool ParseGetAuctionsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the auction for a specific token. + static void MakeGetAuctionRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetAuctionResponse(const JSONValue&, Auction& out); + + +private: + static JSONValue CheckResponse(JSONValue response, bool& out_error); + static Balance DeserializeBalance(const JSONValue& json, bool& out_error); + static Account DeserializeAccount(const JSONValue& json, bool& out_error); + static Chain DeserializeChain(const JSONValue& json, bool& out_error); + static App DeserializeApp(const JSONValue& json, bool& out_error); + static Event DeserializeEvent(const JSONValue& json, bool& out_error); + static Transaction DeserializeTransaction(const JSONValue& json, bool& out_error); + static AccountTransactions DeserializeAccountTransactions(const JSONValue& json, bool& out_error); + static Paginated DeserializePaginated(const JSONValue& json, bool& out_error); + static Block DeserializeBlock(const JSONValue& json, bool& out_error); + static TokenMetadata DeserializeTokenMetadata(const JSONValue& json, bool& out_error); + static Token DeserializeToken(const JSONValue& json, bool& out_error); + static TokenData DeserializeTokenData(const JSONValue& json, bool& out_error); + static SendRawTx DeserializeSendRawTx(const JSONValue& json, bool& out_error); + static Auction DeserializeAuction(const JSONValue& json, bool& out_error); + static Script DeserializeScript(const JSONValue& json, bool& out_error); + +}; + +#if defined(PHANTASMA_HTTPCLIENT) +class PhantasmaAPI +{ +public: + PhantasmaAPI(HttpClient& client) // client must have a longer lifetime than this API object + : m_httpClient(client) + {} + + // Returns the account name and balance of given address. + Account GetAccount(const Char* addressText, bool* out_error = nullptr); + // Returns the address that owns a given name. + String LookUpName(const Char* name, bool* out_error = nullptr); + // Returns the height of a chain. + Int32 GetBlockHeight(const Char* chainInput, bool* out_error = nullptr); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + Int32 GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by hash. + Block GetBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns a serialized string, containing information about a block by hash. + String GetRawBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by height and chain. + Block GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + String GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns the information about a transaction requested by a block hash and transaction index. + Transaction GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error = nullptr); + // Returns last X transactions of given address. (paginated call) + AccountTransactions GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Get number of transactions in a specific address and chain + Int32 GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error = nullptr); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + String SendRawTransaction(const Char* txData, bool* out_error = nullptr); + // Allows to invoke script based on network state, without state changes. + Script InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error = nullptr); + // Returns information about a transaction by hash. + Transaction GetTransaction(const Char* hashText, bool* out_error = nullptr); + // Removes a pending transaction from the mempool. + String CancelTransaction(const Char* hashText, bool* out_error = nullptr); + // Returns an array of all chains deployed in Phantasma. + PHANTASMA_VECTOR GetChains(bool* out_error = nullptr); + // Returns an array of tokens deployed in Phantasma. + PHANTASMA_VECTOR GetTokens(bool* out_error = nullptr); + // Returns info about a specific token deployed in Phantasma. + Token GetToken(const Char* symbol, bool* out_error = nullptr); + // Returns data of a non-fungible token, in hexadecimal format. + TokenData GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + // Returns an array of apps deployed in Phantasma. + PHANTASMA_VECTOR GetApps(bool* out_error = nullptr); + // Returns last X transactions of given token. (paginated call) + PHANTASMA_VECTOR GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the number of transaction of a given token. + Int32 GetTokenTransferCount(const Char* tokenSymbol, bool* out_error = nullptr); + // Returns the balance for a specific token and chain, given an address. + Balance GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error = nullptr); + // Returns the number of active auctions. + Int32 GetAuctionsCount(const Char* symbol, bool* out_error = nullptr); + // Returns the auctions available in the market. (paginated call) + PHANTASMA_VECTOR GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the auction for a specific token. + Auction GetAuction(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + +private: + HttpClient& m_httpClient; +}; +#endif + +#if defined(PHANTASMA_IMPLEMENTATION) + +PHANTASMA_FUNCTION Balance PhantasmaJsonAPI::DeserializeBalance(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR idsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("ids"), err)) + { + const JSONArray& idsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("ids"), err); + int size = json::ArraySize(idsJsonArray, err); + idsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + idsVector.push_back(json::AsString(json::IndexArray(idsJsonArray, i, err), err)); + } + } + return Balance { + json::LookupString(value, PHANTASMA_LITERAL("chain"), err), + json::LookupString(value, PHANTASMA_LITERAL("amount"), err), + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("decimals"), err), + idsVector + }; +} + +PHANTASMA_FUNCTION Account PhantasmaJsonAPI::DeserializeAccount(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR balancesVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("balances"), err)) + { + const JSONArray& balancesJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("balances"), err); + int size = json::ArraySize(balancesJsonArray, err); + balancesVector.reserve(size); + for(int i = 0; i < size; ++i) + { + balancesVector.push_back(DeserializeBalance(json::IndexArray(balancesJsonArray, i, err), err)); + } + } + return Account { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + balancesVector + }; +} + +PHANTASMA_FUNCTION Chain PhantasmaJsonAPI::DeserializeChain(const JSONValue& value, bool& err) +{ + return Chain { + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("parentAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err) + }; +} + +PHANTASMA_FUNCTION App PhantasmaJsonAPI::DeserializeApp(const JSONValue& value, bool& err) +{ + return App { + json::LookupString(value, PHANTASMA_LITERAL("id"), err), + json::LookupString(value, PHANTASMA_LITERAL("title"), err), + json::LookupString(value, PHANTASMA_LITERAL("url"), err), + json::LookupString(value, PHANTASMA_LITERAL("description"), err), + json::LookupString(value, PHANTASMA_LITERAL("icon"), err) + }; +} + +PHANTASMA_FUNCTION Event PhantasmaJsonAPI::DeserializeEvent(const JSONValue& value, bool& err) +{ + return Event { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("kind"), err), + json::LookupString(value, PHANTASMA_LITERAL("data"), err) + }; +} + +PHANTASMA_FUNCTION Transaction PhantasmaJsonAPI::DeserializeTransaction(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Transaction { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("confirmations"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("blockHeight"), err), + json::LookupString(value, PHANTASMA_LITERAL("blockHash"), err), + json::LookupString(value, PHANTASMA_LITERAL("script"), err), + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaJsonAPI::DeserializeAccountTransactions(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return AccountTransactions { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + txsVector + }; +} + +PHANTASMA_FUNCTION Paginated PhantasmaJsonAPI::DeserializePaginated(const JSONValue& value, bool& err) +{ + return Paginated { + json::LookupUInt32(value, PHANTASMA_LITERAL("page"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("pageSize"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("total"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("totalPages"), err), + json::LookupValue(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION Block PhantasmaJsonAPI::DeserializeBlock(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return Block { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("previousHash"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("payload"), err), + txsVector, + json::LookupString(value, PHANTASMA_LITERAL("validatorAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("reward"), err) + }; +} + +PHANTASMA_FUNCTION TokenMetadata PhantasmaJsonAPI::DeserializeTokenMetadata(const JSONValue& value, bool& err) +{ + return TokenMetadata { + json::LookupString(value, PHANTASMA_LITERAL("key"), err), + json::LookupString(value, PHANTASMA_LITERAL("value"), err) + }; +} + +PHANTASMA_FUNCTION Token PhantasmaJsonAPI::DeserializeToken(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR metadataListVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("metadataList"), err)) + { + const JSONArray& metadataListJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("metadataList"), err); + int size = json::ArraySize(metadataListJsonArray, err); + metadataListVector.reserve(size); + for(int i = 0; i < size; ++i) + { + metadataListVector.push_back(DeserializeTokenMetadata(json::IndexArray(metadataListJsonArray, i, err), err)); + } + } + return Token { + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("decimals"), err), + json::LookupString(value, PHANTASMA_LITERAL("currentSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("maxSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + metadataListVector, + json::LookupString(value, PHANTASMA_LITERAL("flags"), err) + }; +} + +PHANTASMA_FUNCTION TokenData PhantasmaJsonAPI::DeserializeTokenData(const JSONValue& value, bool& err) +{ + return TokenData { + json::LookupString(value, PHANTASMA_LITERAL("ID"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ram"), err), + json::LookupString(value, PHANTASMA_LITERAL("rom"), err), + (err=true, "Variable type Boolean isnt currently handled by the template system") + }; +} + +PHANTASMA_FUNCTION SendRawTx PhantasmaJsonAPI::DeserializeSendRawTx(const JSONValue& value, bool& err) +{ + return SendRawTx { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("error"), err) + }; +} + +PHANTASMA_FUNCTION Auction PhantasmaJsonAPI::DeserializeAuction(const JSONValue& value, bool& err) +{ + return Auction { + json::LookupString(value, PHANTASMA_LITERAL("creatorAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("startDate"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("endDate"), err), + json::LookupString(value, PHANTASMA_LITERAL("baseSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("quoteSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("tokenId"), err), + json::LookupString(value, PHANTASMA_LITERAL("price"), err) + }; +} + +PHANTASMA_FUNCTION Script PhantasmaJsonAPI::DeserializeScript(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Script { + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + + + +PHANTASMA_FUNCTION JSONValue PhantasmaJsonAPI::CheckResponse(JSONValue response, bool& out_error) +{ + if( !json::IsObject(response, out_error) ) + { + PHANTASMA_EXCEPTION("Failed to parse JSON"); + out_error = true; + return response; + } + if( json::HasField(response, PHANTASMA_LITERAL("error"), out_error) ) + { + String msg = json::LookupString(response, PHANTASMA_LITERAL("error"), out_error); + PHANTASMA_EXCEPTION_MESSAGE("Server returned error: %s", msg); + out_error = true; + return response; + } + if( !json::HasField(response, PHANTASMA_LITERAL("result"), out_error) ) + { + PHANTASMA_EXCEPTION("Malformed response: No \"result\" node on the JSON body"); + out_error = true; + return response; + } + return json::LookupValue(response, PHANTASMA_LITERAL("result"), out_error); +} + + +// Returns the account name and balance of given address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAccountRequest(JSONBuilder& request, const Char* addressText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAccount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAccountResponse(const JSONValue& _jsonResponse, Account& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAccount(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the address that owns a given name. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeLookUpNameRequest(JSONBuilder& request, const Char* name) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("lookUpName")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), name); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseLookUpNameResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the height of a chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockHeightRequest(JSONBuilder& request, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockHeightResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the number of transactions of given block hash or error if given hash is invalid or is not found. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockTransactionCountByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHashResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, containing information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHeightResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, in hex format, containing information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the information about a transaction requested by a block hash and transaction index. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder& request, const Char* blockHash, Int32 index) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransactionByBlockHashAndIndex")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash, index); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns last X transactions of given address. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(JSONBuilder& request, const Char* addressText, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(const JSONValue& _jsonResponse, AccountTransactions& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + output = DeserializeAccountTransactions(pageStruct.result, err); + return !err; +} + +// Get number of transactions in a specific address and chain +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(JSONBuilder& request, const Char* addressText, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactionCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Allows to broadcast a signed operation on the network, but it's required to build it manually. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeSendRawTransactionRequest(JSONBuilder& request, const Char* txData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("sendRawTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), txData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseSendRawTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Allows to invoke script based on network state, without state changes. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeInvokeRawScriptRequest(JSONBuilder& request, const Char* chainInput, const Char* scriptData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("invokeRawScript")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, scriptData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseInvokeRawScriptResponse(const JSONValue& _jsonResponse, Script& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeScript(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns information about a transaction by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Removes a pending transaction from the mempool. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeCancelTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("cancelTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseCancelTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns an array of all chains deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetChainsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getChains")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetChainsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeChain(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns an array of tokens deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokensRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokens")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokensResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeToken(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns info about a specific token deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getToken")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenResponse(const JSONValue& _jsonResponse, Token& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeToken(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns data of a non-fungible token, in hexadecimal format. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenDataRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenData")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenDataResponse(const JSONValue& _jsonResponse, TokenData& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTokenData(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns an array of apps deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAppsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getApps")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAppsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeApp(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns last X transactions of given token. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransfersRequest(JSONBuilder& request, const Char* tokenSymbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransfers")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransfersResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeTransaction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the number of transaction of a given token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(JSONBuilder& request, const Char* tokenSymbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransferCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the balance for a specific token and chain, given an address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenBalanceRequest(JSONBuilder& request, const Char* addressText, const Char* tokenSymbol, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenBalance")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, tokenSymbol, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenBalanceResponse(const JSONValue& _jsonResponse, Balance& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBalance(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the number of active auctions. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsCountRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctionsCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the auctions available in the market. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsRequest(JSONBuilder& request, const Char* symbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeAuction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the auction for a specific token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionResponse(const JSONValue& _jsonResponse, Auction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAuction(jsonResponse, err); + if( err ) return false; + return !err; +} + + + +#if defined(PHANTASMA_HTTPCLIENT) + +PHANTASMA_FUNCTION Account PhantasmaAPI::GetAccount(const Char* addressText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAccountRequest(request, addressText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Account output; + bool success = PhantasmaJsonAPI::ParseGetAccountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::LookUpName(const Char* name, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeLookUpNameRequest(request, name); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseLookUpNameResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockHeight(const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockHeightRequest(request, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(request, blockHash, index); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaAPI::GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(request, addressText, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + AccountTransactions output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(request, addressText, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::SendRawTransaction(const Char* txData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeSendRawTransactionRequest(request, txData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseSendRawTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Script PhantasmaAPI::InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeInvokeRawScriptRequest(request, chainInput, scriptData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Script output; + bool success = PhantasmaJsonAPI::ParseInvokeRawScriptResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::CancelTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeCancelTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseCancelTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetChains(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetChainsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetChainsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokens(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokensRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokensResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Token PhantasmaAPI::GetToken(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Token output; + bool success = PhantasmaJsonAPI::ParseGetTokenResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION TokenData PhantasmaAPI::GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenDataRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + TokenData output; + bool success = PhantasmaJsonAPI::ParseGetTokenDataResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetApps(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAppsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAppsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransfersRequest(request, tokenSymbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransfersResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetTokenTransferCount(const Char* tokenSymbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(request, tokenSymbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Balance PhantasmaAPI::GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenBalanceRequest(request, addressText, tokenSymbol, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Balance output; + bool success = PhantasmaJsonAPI::ParseGetTokenBalanceResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAuctionsCount(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsCountRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsRequest(request, symbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Auction PhantasmaAPI::GetAuction(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Auction output; + bool success = PhantasmaJsonAPI::ParseGetAuctionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +#endif + +namespace json +{ +#ifndef PHANTASMA_JSONVALUE + JSONValue Parse(const JSONDocument& doc) { return doc; } + + inline size_t SkipNumber(const JSONValue& v, size_t i, bool& out_error) + { + size_t j = v.find_first_not_of("+-0123456789.eE", i); + if( i==j ) { PHANTASMA_EXCEPTION("Invalid Number"); out_error = true; return i+1; } + return j; + } + inline size_t SkipString(const JSONValue& v, size_t i, bool& out_error) + { + if( v[i] != '"' ) { PHANTASMA_EXCEPTION("Invalid String"); out_error = true; return i+1; } + for(++i; i + void AddArray(JSONBuilder& b, const Char* key, Args... args) { b.AddArray(key, args...); } + PHANTASMA_FUNCTION void EndObject(JSONBuilder& b) { b.EndObject(); } +#endif +} +#endif +} diff --git a/C++/Sample/Cli Sample/CpprestSample/cpprest_PhantasmaAPI.h b/C++/Sample/Cli Sample/CpprestSample/cpprest_PhantasmaAPI.h new file mode 100644 index 0000000..24462c9 --- /dev/null +++ b/C++/Sample/Cli Sample/CpprestSample/cpprest_PhantasmaAPI.h @@ -0,0 +1,75 @@ +#pragma once +//------------------------------------------------------------------------------ +// This header supplies the Phantasma API with HTTP and JSON features provided +// by the cpprest library (https://github.com/Microsoft/cpprestsdk). +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include + +namespace phantasma { + namespace json { + inline web::json::value Parse(const web::json::value& d) { return d; } + + inline int32_t LookupInt32( const web::json::value& v, const wchar_t* field, bool& out_error) { return v.at(field).as_integer(); } + inline uint32_t LookupUInt32( const web::json::value& v, const wchar_t* field, bool& out_error) { return (uint32_t)v.at(field).as_integer(); } + inline std::wstring LookupString( const web::json::value& v, const wchar_t* field, bool& out_error) { return v.at(field).as_string(); } + inline web::json::value LookupValue( const web::json::value& v, const wchar_t* field, bool& out_error) { return v.at(field); } + inline web::json::array LookupArray( const web::json::value& v, const wchar_t* field, bool& out_error) { return v.at(field).as_array(); } + inline bool HasField( const web::json::value& v, const wchar_t* field, bool& out_error) { return v.has_field(field); } + inline bool HasArrayField(const web::json::value& v, const wchar_t* field, bool& out_error) { return v.has_array_field(field); } + inline int32_t AsInt32( const web::json::value& v, bool& out_error) { return v.as_integer(); } + inline uint32_t AsUInt32( const web::json::value& v, bool& out_error) { return (uint32_t)v.as_integer(); } + inline std::wstring AsString( const web::json::value& v, bool& out_error) { return v.as_string(); } + inline web::json::array AsArray( const web::json::value& v, bool& out_error) { return v.as_array(); } + inline bool IsArray( const web::json::value& v, bool& out_error) { return v.is_array(); } + inline bool IsObject( const web::json::value& v, bool& out_error) { return v.is_object(); } + inline int ArraySize( const web::json::array& a, bool& out_error) { return (int)a.size(); } + inline web::json::value IndexArray( const web::json::array& a, int index, bool& out_error) { return a.at((size_t)index); } + + inline void BeginObject(web::json::value&) {} + inline void EndObject(web::json::value&){} + inline void AddString(web::json::value& root, const wchar_t* key, const wchar_t* value) { root[key] = web::json::value::string(value); } + inline void AddValues(int idx, web::json::value& ar) {} + inline void AddValues(int idx, web::json::value& ar, const wchar_t* arg) { ar[idx] = web::json::value::string(arg); } + template void AddValues(int idx, web::json::value& ar, T arg) { ar[idx] = web::json::value::number(arg); } + template void AddValues(int idx, web::json::value& ar, T arg0, Args... args) + { + AddValues(idx, ar, arg0); + AddValues(idx+1, ar, args...); + } + template void AddArray(web::json::value& root, const wchar_t* key, Args... args) + { + web::json::value& ar = (root[key] = web::json::value::array()); + AddValues(0, ar, args...); + } + } + + inline web::json::value HttpPost(web::http::client::http_client& client, const wchar_t* uri, const web::json::value& data) + { + web::uri_builder builder(uri); + return client.request(web::http::methods::POST, builder.to_string(), data) + .then([&](web::http::http_response response) -> web::json::value + { + const auto statusCode = response.status_code(); + if (statusCode != 200) + throw web::http::http_exception("Malformed RPC request or endpoint: response status = " + statusCode); + return response.content_ready().get().extract_json(true).get(); + }).get(); + } +} + +#define PHANTASMA_JSONVALUE web::json::value +#define PHANTASMA_JSONARRAY web::json::array +#define PHANTASMA_JSONDOCUMENT web::json::value +#define PHANTASMA_JSONBUILDER web::json::value +#define PHANTASMA_HTTPCLIENT web::http::client::http_client +#define PHANTASMA_CHAR wchar_t +#define PHANTASMA_LITERAL(x) L ## x +#define PHANTASMA_STRING std::wstring +#define PHANTASMA_EXCEPTION(message) throw std::runtime_error(message) +#define PHANTASMA_EXCEPTION_MESSAGE(message, string) throw std::runtime_error(std::wstring_convert, wchar_t>().to_bytes(string)) +#include "PhantasmaAPI.h" diff --git a/C++/Sample/Cli Sample/CpprestSample/main.cpp b/C++/Sample/Cli Sample/CpprestSample/main.cpp new file mode 100644 index 0000000..74f5c95 --- /dev/null +++ b/C++/Sample/Cli Sample/CpprestSample/main.cpp @@ -0,0 +1,31 @@ + +#define PHANTASMA_IMPLEMENTATION +#include "cpprest_PhantasmaAPI.h" + +int main() +{ + std::wstring host = L"http://localhost:7077"; + web::http::client::http_client http(host); + phantasma::PhantasmaAPI api(http); + + //std::wstring address = L"P2f7ZFuj6NfZ76ymNMnG3xRBT5hAMicDrQRHE4S7SoxEr"; //genesis address + //std::wstring address = L"NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; //nft address + + const wchar_t* wif = L"NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; + + try + { + phantasma::Account account = api.GetAccount(wif); + + std::wcout << L"Balance description for address " << wif << std::endl; + + for (int i = 0; i < account.balances.size(); i++) + { + std::wcout << account.balances[i].amount << " " << account.balances[i].symbol << " tokens available on " << account.balances[i].chain << " chain" << std::endl; + } + } + catch(std::exception& e) + { + std::wcout << e.what(); + } +} diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.filters b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.filters new file mode 100644 index 0000000..606e74d --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.user b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.user new file mode 100644 index 0000000..2c3e185 --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.user @@ -0,0 +1,6 @@ + + + + WindowsLocalDebugger + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj new file mode 100644 index 0000000..e64f194 --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {080A680E-5B2B-4FBA-B5EF-629C6284B55A} + Win32Proj + CSpookTest + 10.0.17763.0 + CurlRapidjsonSample + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(IncludePath) + $(ExecutablePath) + $(LibraryPath) + + + true + + + false + + + false + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + %(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _WINSOCK_DEPRECATED_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) + + + Console + true + D:\Projects\vcpkg\installed\x64-windows\lib + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + _WINSOCK_DEPRECATED_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Projects\vcpkg\installed\x64-windows\lib + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj.user b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/CurlRapidjsonSample.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/PhantasmaAPI.h b/C++/Sample/Cli Sample/CurlRapidjsonSample/PhantasmaAPI.h new file mode 100644 index 0000000..03cfe05 --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/PhantasmaAPI.h @@ -0,0 +1,2033 @@ +#pragma once +//------------------------------------------------------------------------------ +// Low-level API +//------------------------------------------------------------------------------ +// The PhantasmaJsonAPI namespace can construct JSON requests and parse JSON responses, +// but you are responsible for sending/receiving these messages via HTTP on your own. +// You can call PhantasmaJsonAPI::Uri() to determine where to send them. +// +// void PhantasmaJsonAPI::Make{Message}Request(JSONBuilder&, {Parameters}); +// bool PhantasmaJsonAPI::Parse{Message}Response(const JSONValue&, {Output}); +// +//------------------------------------------------------------------------------ +// High-level API +//------------------------------------------------------------------------------ +// If you have defined PHANTASMA_HTTPCLIENT, then you can construct a PhantasmaAPI object, +// which provides a simplified API that hides the internal JSON messaging. +// +// PhantasmaAPI phantasmaAPI(httpClient); +// {Output} phantasmaAPI->{Message}({Parameters}); +// +//------------------------------------------------------------------------------ +// API configuration +//------------------------------------------------------------------------------ +// As different C++ projects may use different primitive types, you can use the +// following #defines (BEFORE including phantasma.h) to override the default types. +// +// #define | typedef | Default | Notes +// PHANTASMA_INT32 | phantasma::Int32 | int32_t | +// PHANTASMA_UINT32 | phantasma::UInt32 | uint32_t | +// PHANTASMA_CHAR | phantasma::Char | char | See Unicode section +// PHANTASMA_STRING | phantasma::String | std::string | Must support construction from `const phantasma::Char*` +// PHANTASMA_VECTOR | | std::vector | Must support `push_back` and `size` members +// PHANTASMA_JSONVALUE | phantasma::JSONValue | std::string_view | See JSON section +// PHANTASMA_JSONARRAY | phantasma::JSONArray | JSONValue | See JSON section +// PHANTASMA_JSONDOCUMENT| phantasma::JSONDocument| std::string | See JSON section +// PHANTASMA_JSONBUILDER | phantasma::JSONBuilder | std::stringstream*| See JSON section +// PHANTASMA_HTTPCLIENT | phantasma::HttpClient | | See HTTP section +// +// The behavior of this header can further be modified by using the following +// #defines (BEFORE including phantasma.h) +// +// #define | Notes +// PHANTASMA_EXCEPTION(message) | See Exceptions section +// PHANTASMA_EXCEPTION_MESSAGE(message, String) | See Exceptions section +// PHANTASMA_LITERAL(x) | See Unicode section +// PHANTASMA_FUNCTION | See Integration section +// PHANTASMA_IMPLEMENTATION | See Integration section +// +//------------------------------------------------------------------------------ +// Integration +//------------------------------------------------------------------------------ +// This API is provided in the "single header" style to support simple and flexible +// integration into your project (see https://github.com/nothings/single_file_libs). +// The implementation of function bodies will be excluded unless you define +// PHANTASMA_IMPLEMENTATION before including phantasma.h. +// +// Typical linking: +// In one CPP file, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// +// Inline linking: +// In every CPP file that uses the API, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// #define PHANTASMA_FUNCTION inline +// +// Aside from PHANTASMA_IMPLEMENTATION / PHANTASMA_FUNCTION, you should take care +// to ensure that every other PHANTASMA_* macro is defined to the same value in +// all of yoru CPP files that use the phantasma API. +// +//------------------------------------------------------------------------------ +// Exceptions +//------------------------------------------------------------------------------ +// Support for C++ exceptions is opt-in. Define the following (or an alternative +// based on your own exception classes) before including phantasma.h: +// #define PHANTASMA_EXCEPTION(message) throw std::runtime_error(message) +// #define PHANTASMA_EXCEPTION_MESSAGE(message, string) throw std::runtime_error(string) +// +//------------------------------------------------------------------------------ +// Unicode +//------------------------------------------------------------------------------ +// To build a wide-character version of the API, define the following before +// including phantasma.h: +// #define PHANTASMA_CHAR wchar_t +// #define PHANTASMA_LITERAL(x) L ## x +// #define PHANTASMA_STRING std::wstring +// +// You should also provide a JSON and HTTP library with wide-character support. +// +//------------------------------------------------------------------------------ +// JSON +//------------------------------------------------------------------------------ +// This header contains JSON parsing and building code, but it is written to be +// as simple as possible (approx 200 lines of code) and is not high-performance +// or highly robust. +// +// It is recommended that you supply another JSON-parsing API, by defining the +// following macros before including phantasma.h: +// #define PHANTASMA_JSONVALUE Your_Json_Value_Type +// #define PHANTASMA_JSONARRAY Your_Json_Array_Type +// #define PHANTASMA_JSONDOCUMENT Your_JSON_Document_Type +// #define PHANTASMA_JSONBUILDER Your_Json_Serializer_Type +// +// Also, this header uses the following procedural API to interact with these types. +// If you have supplied your own JSON types, you must implement the following functions: +// +// namespace phantasma { namespace json { +// +// JSONValue Parse(const JSONDocument&); +// +// Int32 LookupInt32( const JSONValue&, const Char* field, bool& out_error); +// UInt32 LookupUInt32( const JSONValue&, const Char* field, bool& out_error); +// String LookupString( const JSONValue&, const Char* field, bool& out_error); +// JSONValue LookupValue( const JSONValue&, const Char* field, bool& out_error); +// JSONArray LookupArray( const JSONValue&, const Char* field, bool& out_error); +// bool HasField( const JSONValue&, const Char* field, bool& out_error); +// bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); +// +// Int32 AsInt32( const JSONValue&, bool& out_error); +// UInt32 AsUInt32( const JSONValue&, bool& out_error); +// String AsString( const JSONValue&, bool& out_error); +// JSONArray AsArray( const JSONValue&, bool& out_error); +// bool IsArray( const JSONValue&, bool& out_error); +// bool IsObject( const JSONValue&, bool& out_error); +// +// int ArraySize( const JSONArray&, bool& out_error); +// JSONValue IndexArray( const JSONArray&, int index, bool& out_error); +// +// void BeginObject(JSONBuilder&); +// void AddString (JSONBuilder&, const Char* key, const Char* value); +// template void AddArray (JSONBuilder&, const Char* key, Args...); +// void EndObject (JSONBuilder&); +// }} +// +//------------------------------------------------------------------------------ +// HTTP +//------------------------------------------------------------------------------ +// This header does not contain a HTTP client, nor a dependency on any specific +// HTTP client library. If you do not supply a HTTP client library, then only +// the Low-level phantasma API (PhantasmaJsonAPI) is available. +// +// To enable the PhantasmaAPI class, defining the following macro before +// including phantasma.h: +// #define PHANTASMA_HTTPCLIENT Your_HTTP_Client_Type +// +// Also, this header uses the following procedural API to interact with this type. +// If you have defined PHANTASMA_HTTPCLIENT, you must implement the following, +// function, which should perform a HTTP POST request and return the result: +// +// namespace phantasma { +// JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +// } +// +//------------------------------------------------------------------------------ + +#if !defined(PHANTASMA_STRING) || !defined(PHANTASMA_JSONDOCUMENT) || !defined(PHANTASMA_JSONVALUE) +#include +#endif + +#if !defined(PHANTASMA_JSONVALUE) && __cplusplus > 201402L +#include +#endif + +#if !defined(PHANTASMA_JSONBUILDER) +#include +#endif + +#if !defined(PHANTASMA_VECTOR) +#define PHANTASMA_VECTOR std::vector +#include +#endif + +#if !defined(PHANTASMA_S32) || !defined(PHANTASMA_U32) +#include +#endif + +#if !defined(PHANTASMA_EXCEPTION) +#define PHANTASMA_EXCEPTION(literal) +#define PHANTASMA_EXCEPTION_MESSAGE(literal, string) +#endif + +#if !defined(PHANTASMA_LITERAL) +#define PHANTASMA_LITERAL(x) x +#endif + +#if !defined(PHANTASMA_FUNCTION) +#define PHANTASMA_FUNCTION +#endif + +namespace phantasma +{ +#ifdef PHANTASMA_CHAR +typedef PHANTASMA_CHAR Char; +#else +typedef char Char; +#endif + +#ifdef PHANTASMA_INT32 +typedef PHANTASMA_INT32 Int32; +#else +typedef int32_t Int32; +#endif + +#ifdef PHANTASMA_UINT32 +typedef PHANTASMA_UINT32 UInt32; +#else +typedef uint32_t UInt32; +#endif + +#ifdef PHANTASMA_STRING +typedef PHANTASMA_STRING String; +#else +typedef std::string String; +#endif + +#ifdef PHANTASMA_JSONVALUE +typedef PHANTASMA_JSONVALUE JSONValue; +#elif __cplusplus > 201402L +typedef std::string_view JSONValue; +#else +typedef std::string JSONValue; +#endif + +#ifdef PHANTASMA_JSONARRAY +typedef PHANTASMA_JSONARRAY JSONArray; +#else +typedef JSONValue JSONArray; +#endif + +#ifdef PHANTASMA_JSONDOCUMENT +typedef PHANTASMA_JSONDOCUMENT JSONDocument; +#else +typedef std::string JSONDocument; +#endif + + +#ifdef PHANTASMA_JSONBUILDER +typedef PHANTASMA_JSONBUILDER JSONBuilder; +#else +struct JSONBuilder // A VERY simple json string builder. Highly recommended that you provide a real JSON library instead! +{ + std::stringstream s; + bool empty = true; + operator std::stringstream&() { return s; } + void AddKey(const Char* key) { if(!empty) { s << ", "; } empty = false; s << '"' << key << "\": "; } + void AddValues() {} + void AddValues(const char* arg) { s << '"' << arg << '"'; } + template void AddValues(T arg) { s << arg; } + template void AddValues(T arg0, Args... args) { AddValues(arg0); s << ", "; AddValues(args...); } + + void BeginObject() { s << "{"; } + void AddString(const Char* key, const Char* value) { AddKey(key); s << '"' << value << '"'; } + template void AddArray(const Char* key, Args... args) { AddKey(key); s << '['; AddValues(args...); s << ']'; } + void EndObject() { s << "}"; } +}; +#endif + +#ifdef PHANTASMA_HTTPCLIENT +typedef PHANTASMA_HTTPCLIENT HttpClient; +//JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +#endif + +//If providing a JSON library (highly recommended that you do!), then you must provide these functions yourself: +namespace json +{ +#ifndef PHANTASMA_JSONBUILDER + JSONValue Parse(const JSONDocument&); + Int32 LookupInt32(const JSONValue&, const Char* field, bool& out_error); + UInt32 LookupUInt32(const JSONValue&, const Char* field, bool& out_error); + String LookupString(const JSONValue&, const Char* field, bool& out_error); + JSONValue LookupValue(const JSONValue&, const Char* field, bool& out_error); + JSONArray LookupArray(const JSONValue&, const Char* field, bool& out_error); + bool HasField(const JSONValue&, const Char* field, bool& out_error); + bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); + Int32 AsInt32(const JSONValue&, bool& out_error); + UInt32 AsUInt32(const JSONValue&, bool& out_error); + String AsString(const JSONValue&, bool& out_error); + JSONArray AsArray(const JSONValue&, bool& out_error); + bool IsArray(const JSONValue&, bool& out_error); + bool IsObject(const JSONValue&, bool& out_error); + + int ArraySize(const JSONArray&, bool& out_error); + JSONValue IndexArray(const JSONArray&, int index, bool& out_error); + + void BeginObject(JSONBuilder&); + void AddString(JSONBuilder&, const Char* key, const Char* value); + template + void AddArray(JSONBuilder&, const Char* key, Args... args); + void EndObject(JSONBuilder&); +#endif +} + + +struct Balance +{ + String chain;// + String amount;// + String symbol;// + UInt32 decimals;// + PHANTASMA_VECTOR ids;// +}; + +struct Account +{ + String address;// + String name;// + PHANTASMA_VECTOR balances;// +}; + +struct Chain +{ + String name;// + String address;// + String parentAddress;// + UInt32 height;// +}; + +struct App +{ + String id;// + String title;// + String url;// + String description;// + String icon;// +}; + +struct Event +{ + String address;// + String kind;// + String data;// +}; + +struct Transaction +{ + String hash;// + String chainAddress;// + UInt32 timestamp;// + Int32 confirmations;// + UInt32 blockHeight;// + String blockHash;// + String script;// + PHANTASMA_VECTOR events;// + String result;// +}; + +struct AccountTransactions +{ + String address;// + PHANTASMA_VECTOR txs;// +}; + +struct Paginated +{ + UInt32 page;// + UInt32 pageSize;// + UInt32 total;// + UInt32 totalPages;// + JSONValue result;// +}; + +struct Block +{ + String hash;// + String previousHash;// + UInt32 timestamp;// + UInt32 height;// + String chainAddress;// + String payload;// + PHANTASMA_VECTOR txs;// + String validatorAddress;// + String reward;// +}; + +struct TokenMetadata +{ + String key;// + String value;// +}; + +struct Token +{ + String symbol;// + String name;// + Int32 decimals;// + String currentSupply;// + String maxSupply;// + String ownerAddress;// + PHANTASMA_VECTOR metadataList;// + String flags;// +}; + +struct TokenData +{ + String ID;// + String chainAddress;// + String ownerAddress;// + String ram;// + String rom;// + bool forSale;// +}; + +struct SendRawTx +{ + String hash;// + String error;// +}; + +struct Auction +{ + String creatorAddress;// + UInt32 startDate;// + UInt32 endDate;// + String baseSymbol;// + String quoteSymbol;// + String tokenId;// + String price;// +}; + +struct Script +{ + PHANTASMA_VECTOR events;// + String result;// +}; + + +class PhantasmaJsonAPI +{ +public: + static const Char* Uri() { return PHANTASMA_LITERAL("/rpc"); } + + // Returns the account name and balance of given address. + static void MakeGetAccountRequest(JSONBuilder&, const Char* addressText); + static bool ParseGetAccountResponse(const JSONValue&, Account& out); + // Returns the address that owns a given name. + static void MakeLookUpNameRequest(JSONBuilder&, const Char* name); + static bool ParseLookUpNameResponse(const JSONValue&, String& out); + // Returns the height of a chain. + static void MakeGetBlockHeightRequest(JSONBuilder&, const Char* chainInput); + static bool ParseGetBlockHeightResponse(const JSONValue&, Int32& out); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + static void MakeGetBlockTransactionCountByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockTransactionCountByHashResponse(const JSONValue&, Int32& out); + // Returns information about a block by hash. + static void MakeGetBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockByHashResponse(const JSONValue&, Block& out); + // Returns a serialized string, containing information about a block by hash. + static void MakeGetRawBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetRawBlockByHashResponse(const JSONValue&, String& out); + // Returns information about a block by height and chain. + static void MakeGetBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetBlockByHeightResponse(const JSONValue&, Block& out); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + static void MakeGetRawBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetRawBlockByHeightResponse(const JSONValue&, String& out); + // Returns the information about a transaction requested by a block hash and transaction index. + static void MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder&, const Char* blockHash, Int32 index); + static bool ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue&, Transaction& out); + // Returns last X transactions of given address. (paginated call) + static void MakeGetAddressTransactionsRequest(JSONBuilder&, const Char* addressText, UInt32 page, UInt32 pageSize); + static bool ParseGetAddressTransactionsResponse(const JSONValue&, AccountTransactions& out); + // Get number of transactions in a specific address and chain + static void MakeGetAddressTransactionCountRequest(JSONBuilder&, const Char* addressText, const Char* chainInput); + static bool ParseGetAddressTransactionCountResponse(const JSONValue&, Int32& out); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + static void MakeSendRawTransactionRequest(JSONBuilder&, const Char* txData); + static bool ParseSendRawTransactionResponse(const JSONValue&, String& out); + // Allows to invoke script based on network state, without state changes. + static void MakeInvokeRawScriptRequest(JSONBuilder&, const Char* chainInput, const Char* scriptData); + static bool ParseInvokeRawScriptResponse(const JSONValue&, Script& out); + // Returns information about a transaction by hash. + static void MakeGetTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseGetTransactionResponse(const JSONValue&, Transaction& out); + // Removes a pending transaction from the mempool. + static void MakeCancelTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseCancelTransactionResponse(const JSONValue&, String& out); + // Returns an array of all chains deployed in Phantasma. + static void MakeGetChainsRequest(JSONBuilder&); + static bool ParseGetChainsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns an array of tokens deployed in Phantasma. + static void MakeGetTokensRequest(JSONBuilder&); + static bool ParseGetTokensResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns info about a specific token deployed in Phantasma. + static void MakeGetTokenRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetTokenResponse(const JSONValue&, Token& out); + // Returns data of a non-fungible token, in hexadecimal format. + static void MakeGetTokenDataRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetTokenDataResponse(const JSONValue&, TokenData& out); + // Returns an array of apps deployed in Phantasma. + static void MakeGetAppsRequest(JSONBuilder&); + static bool ParseGetAppsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns last X transactions of given token. (paginated call) + static void MakeGetTokenTransfersRequest(JSONBuilder&, const Char* tokenSymbol, UInt32 page, UInt32 pageSize); + static bool ParseGetTokenTransfersResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the number of transaction of a given token. + static void MakeGetTokenTransferCountRequest(JSONBuilder&, const Char* tokenSymbol); + static bool ParseGetTokenTransferCountResponse(const JSONValue&, Int32& out); + // Returns the balance for a specific token and chain, given an address. + static void MakeGetTokenBalanceRequest(JSONBuilder&, const Char* addressText, const Char* tokenSymbol, const Char* chainInput); + static bool ParseGetTokenBalanceResponse(const JSONValue&, Balance& out); + // Returns the number of active auctions. + static void MakeGetAuctionsCountRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetAuctionsCountResponse(const JSONValue&, Int32& out); + // Returns the auctions available in the market. (paginated call) + static void MakeGetAuctionsRequest(JSONBuilder&, const Char* symbol, UInt32 page, UInt32 pageSize); + static bool ParseGetAuctionsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the auction for a specific token. + static void MakeGetAuctionRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetAuctionResponse(const JSONValue&, Auction& out); + + +private: + static JSONValue CheckResponse(JSONValue response, bool& out_error); + static Balance DeserializeBalance(const JSONValue& json, bool& out_error); + static Account DeserializeAccount(const JSONValue& json, bool& out_error); + static Chain DeserializeChain(const JSONValue& json, bool& out_error); + static App DeserializeApp(const JSONValue& json, bool& out_error); + static Event DeserializeEvent(const JSONValue& json, bool& out_error); + static Transaction DeserializeTransaction(const JSONValue& json, bool& out_error); + static AccountTransactions DeserializeAccountTransactions(const JSONValue& json, bool& out_error); + static Paginated DeserializePaginated(const JSONValue& json, bool& out_error); + static Block DeserializeBlock(const JSONValue& json, bool& out_error); + static TokenMetadata DeserializeTokenMetadata(const JSONValue& json, bool& out_error); + static Token DeserializeToken(const JSONValue& json, bool& out_error); + static TokenData DeserializeTokenData(const JSONValue& json, bool& out_error); + static SendRawTx DeserializeSendRawTx(const JSONValue& json, bool& out_error); + static Auction DeserializeAuction(const JSONValue& json, bool& out_error); + static Script DeserializeScript(const JSONValue& json, bool& out_error); + +}; + +#if defined(PHANTASMA_HTTPCLIENT) +class PhantasmaAPI +{ +public: + PhantasmaAPI(HttpClient& client) // client must have a longer lifetime than this API object + : m_httpClient(client) + {} + + // Returns the account name and balance of given address. + Account GetAccount(const Char* addressText, bool* out_error = nullptr); + // Returns the address that owns a given name. + String LookUpName(const Char* name, bool* out_error = nullptr); + // Returns the height of a chain. + Int32 GetBlockHeight(const Char* chainInput, bool* out_error = nullptr); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + Int32 GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by hash. + Block GetBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns a serialized string, containing information about a block by hash. + String GetRawBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by height and chain. + Block GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + String GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns the information about a transaction requested by a block hash and transaction index. + Transaction GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error = nullptr); + // Returns last X transactions of given address. (paginated call) + AccountTransactions GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Get number of transactions in a specific address and chain + Int32 GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error = nullptr); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + String SendRawTransaction(const Char* txData, bool* out_error = nullptr); + // Allows to invoke script based on network state, without state changes. + Script InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error = nullptr); + // Returns information about a transaction by hash. + Transaction GetTransaction(const Char* hashText, bool* out_error = nullptr); + // Removes a pending transaction from the mempool. + String CancelTransaction(const Char* hashText, bool* out_error = nullptr); + // Returns an array of all chains deployed in Phantasma. + PHANTASMA_VECTOR GetChains(bool* out_error = nullptr); + // Returns an array of tokens deployed in Phantasma. + PHANTASMA_VECTOR GetTokens(bool* out_error = nullptr); + // Returns info about a specific token deployed in Phantasma. + Token GetToken(const Char* symbol, bool* out_error = nullptr); + // Returns data of a non-fungible token, in hexadecimal format. + TokenData GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + // Returns an array of apps deployed in Phantasma. + PHANTASMA_VECTOR GetApps(bool* out_error = nullptr); + // Returns last X transactions of given token. (paginated call) + PHANTASMA_VECTOR GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the number of transaction of a given token. + Int32 GetTokenTransferCount(const Char* tokenSymbol, bool* out_error = nullptr); + // Returns the balance for a specific token and chain, given an address. + Balance GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error = nullptr); + // Returns the number of active auctions. + Int32 GetAuctionsCount(const Char* symbol, bool* out_error = nullptr); + // Returns the auctions available in the market. (paginated call) + PHANTASMA_VECTOR GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the auction for a specific token. + Auction GetAuction(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + +private: + HttpClient& m_httpClient; +}; +#endif + +#if defined(PHANTASMA_IMPLEMENTATION) + +PHANTASMA_FUNCTION Balance PhantasmaJsonAPI::DeserializeBalance(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR idsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("ids"), err)) + { + const JSONArray& idsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("ids"), err); + int size = json::ArraySize(idsJsonArray, err); + idsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + idsVector.push_back(json::AsString(json::IndexArray(idsJsonArray, i, err), err)); + } + } + return Balance { + json::LookupString(value, PHANTASMA_LITERAL("chain"), err), + json::LookupString(value, PHANTASMA_LITERAL("amount"), err), + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("decimals"), err), + idsVector + }; +} + +PHANTASMA_FUNCTION Account PhantasmaJsonAPI::DeserializeAccount(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR balancesVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("balances"), err)) + { + const JSONArray& balancesJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("balances"), err); + int size = json::ArraySize(balancesJsonArray, err); + balancesVector.reserve(size); + for(int i = 0; i < size; ++i) + { + balancesVector.push_back(DeserializeBalance(json::IndexArray(balancesJsonArray, i, err), err)); + } + } + return Account { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + balancesVector + }; +} + +PHANTASMA_FUNCTION Chain PhantasmaJsonAPI::DeserializeChain(const JSONValue& value, bool& err) +{ + return Chain { + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("parentAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err) + }; +} + +PHANTASMA_FUNCTION App PhantasmaJsonAPI::DeserializeApp(const JSONValue& value, bool& err) +{ + return App { + json::LookupString(value, PHANTASMA_LITERAL("id"), err), + json::LookupString(value, PHANTASMA_LITERAL("title"), err), + json::LookupString(value, PHANTASMA_LITERAL("url"), err), + json::LookupString(value, PHANTASMA_LITERAL("description"), err), + json::LookupString(value, PHANTASMA_LITERAL("icon"), err) + }; +} + +PHANTASMA_FUNCTION Event PhantasmaJsonAPI::DeserializeEvent(const JSONValue& value, bool& err) +{ + return Event { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("kind"), err), + json::LookupString(value, PHANTASMA_LITERAL("data"), err) + }; +} + +PHANTASMA_FUNCTION Transaction PhantasmaJsonAPI::DeserializeTransaction(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Transaction { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("confirmations"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("blockHeight"), err), + json::LookupString(value, PHANTASMA_LITERAL("blockHash"), err), + json::LookupString(value, PHANTASMA_LITERAL("script"), err), + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaJsonAPI::DeserializeAccountTransactions(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return AccountTransactions { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + txsVector + }; +} + +PHANTASMA_FUNCTION Paginated PhantasmaJsonAPI::DeserializePaginated(const JSONValue& value, bool& err) +{ + return Paginated { + json::LookupUInt32(value, PHANTASMA_LITERAL("page"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("pageSize"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("total"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("totalPages"), err), + json::LookupValue(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION Block PhantasmaJsonAPI::DeserializeBlock(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return Block { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("previousHash"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("payload"), err), + txsVector, + json::LookupString(value, PHANTASMA_LITERAL("validatorAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("reward"), err) + }; +} + +PHANTASMA_FUNCTION TokenMetadata PhantasmaJsonAPI::DeserializeTokenMetadata(const JSONValue& value, bool& err) +{ + return TokenMetadata { + json::LookupString(value, PHANTASMA_LITERAL("key"), err), + json::LookupString(value, PHANTASMA_LITERAL("value"), err) + }; +} + +PHANTASMA_FUNCTION Token PhantasmaJsonAPI::DeserializeToken(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR metadataListVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("metadataList"), err)) + { + const JSONArray& metadataListJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("metadataList"), err); + int size = json::ArraySize(metadataListJsonArray, err); + metadataListVector.reserve(size); + for(int i = 0; i < size; ++i) + { + metadataListVector.push_back(DeserializeTokenMetadata(json::IndexArray(metadataListJsonArray, i, err), err)); + } + } + return Token { + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("decimals"), err), + json::LookupString(value, PHANTASMA_LITERAL("currentSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("maxSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + metadataListVector, + json::LookupString(value, PHANTASMA_LITERAL("flags"), err) + }; +} + +PHANTASMA_FUNCTION TokenData PhantasmaJsonAPI::DeserializeTokenData(const JSONValue& value, bool& err) +{ + return TokenData { + json::LookupString(value, PHANTASMA_LITERAL("ID"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ram"), err), + json::LookupString(value, PHANTASMA_LITERAL("rom"), err), + (err=true, "Variable type Boolean isnt currently handled by the template system") + }; +} + +PHANTASMA_FUNCTION SendRawTx PhantasmaJsonAPI::DeserializeSendRawTx(const JSONValue& value, bool& err) +{ + return SendRawTx { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("error"), err) + }; +} + +PHANTASMA_FUNCTION Auction PhantasmaJsonAPI::DeserializeAuction(const JSONValue& value, bool& err) +{ + return Auction { + json::LookupString(value, PHANTASMA_LITERAL("creatorAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("startDate"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("endDate"), err), + json::LookupString(value, PHANTASMA_LITERAL("baseSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("quoteSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("tokenId"), err), + json::LookupString(value, PHANTASMA_LITERAL("price"), err) + }; +} + +PHANTASMA_FUNCTION Script PhantasmaJsonAPI::DeserializeScript(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Script { + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + + + +PHANTASMA_FUNCTION JSONValue PhantasmaJsonAPI::CheckResponse(JSONValue response, bool& out_error) +{ + if( !json::IsObject(response, out_error) ) + { + PHANTASMA_EXCEPTION("Failed to parse JSON"); + out_error = true; + return response; + } + if( json::HasField(response, PHANTASMA_LITERAL("error"), out_error) ) + { + String msg = json::LookupString(response, PHANTASMA_LITERAL("error"), out_error); + PHANTASMA_EXCEPTION_MESSAGE("Server returned error: %s", msg); + out_error = true; + return response; + } + if( !json::HasField(response, PHANTASMA_LITERAL("result"), out_error) ) + { + PHANTASMA_EXCEPTION("Malformed response: No \"result\" node on the JSON body"); + out_error = true; + return response; + } + return json::LookupValue(response, PHANTASMA_LITERAL("result"), out_error); +} + + +// Returns the account name and balance of given address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAccountRequest(JSONBuilder& request, const Char* addressText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAccount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAccountResponse(const JSONValue& _jsonResponse, Account& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAccount(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the address that owns a given name. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeLookUpNameRequest(JSONBuilder& request, const Char* name) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("lookUpName")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), name); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseLookUpNameResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the height of a chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockHeightRequest(JSONBuilder& request, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockHeightResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the number of transactions of given block hash or error if given hash is invalid or is not found. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockTransactionCountByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHashResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, containing information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHeightResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, in hex format, containing information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the information about a transaction requested by a block hash and transaction index. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder& request, const Char* blockHash, Int32 index) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransactionByBlockHashAndIndex")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash, index); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns last X transactions of given address. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(JSONBuilder& request, const Char* addressText, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(const JSONValue& _jsonResponse, AccountTransactions& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + output = DeserializeAccountTransactions(pageStruct.result, err); + return !err; +} + +// Get number of transactions in a specific address and chain +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(JSONBuilder& request, const Char* addressText, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactionCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Allows to broadcast a signed operation on the network, but it's required to build it manually. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeSendRawTransactionRequest(JSONBuilder& request, const Char* txData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("sendRawTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), txData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseSendRawTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Allows to invoke script based on network state, without state changes. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeInvokeRawScriptRequest(JSONBuilder& request, const Char* chainInput, const Char* scriptData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("invokeRawScript")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, scriptData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseInvokeRawScriptResponse(const JSONValue& _jsonResponse, Script& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeScript(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns information about a transaction by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Removes a pending transaction from the mempool. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeCancelTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("cancelTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseCancelTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns an array of all chains deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetChainsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getChains")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetChainsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeChain(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns an array of tokens deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokensRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokens")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokensResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeToken(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns info about a specific token deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getToken")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenResponse(const JSONValue& _jsonResponse, Token& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeToken(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns data of a non-fungible token, in hexadecimal format. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenDataRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenData")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenDataResponse(const JSONValue& _jsonResponse, TokenData& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTokenData(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns an array of apps deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAppsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getApps")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAppsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeApp(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns last X transactions of given token. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransfersRequest(JSONBuilder& request, const Char* tokenSymbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransfers")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransfersResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeTransaction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the number of transaction of a given token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(JSONBuilder& request, const Char* tokenSymbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransferCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the balance for a specific token and chain, given an address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenBalanceRequest(JSONBuilder& request, const Char* addressText, const Char* tokenSymbol, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenBalance")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, tokenSymbol, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenBalanceResponse(const JSONValue& _jsonResponse, Balance& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBalance(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the number of active auctions. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsCountRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctionsCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the auctions available in the market. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsRequest(JSONBuilder& request, const Char* symbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeAuction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the auction for a specific token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionResponse(const JSONValue& _jsonResponse, Auction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAuction(jsonResponse, err); + if( err ) return false; + return !err; +} + + + +#if defined(PHANTASMA_HTTPCLIENT) + +PHANTASMA_FUNCTION Account PhantasmaAPI::GetAccount(const Char* addressText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAccountRequest(request, addressText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Account output; + bool success = PhantasmaJsonAPI::ParseGetAccountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::LookUpName(const Char* name, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeLookUpNameRequest(request, name); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseLookUpNameResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockHeight(const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockHeightRequest(request, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(request, blockHash, index); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaAPI::GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(request, addressText, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + AccountTransactions output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(request, addressText, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::SendRawTransaction(const Char* txData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeSendRawTransactionRequest(request, txData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseSendRawTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Script PhantasmaAPI::InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeInvokeRawScriptRequest(request, chainInput, scriptData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Script output; + bool success = PhantasmaJsonAPI::ParseInvokeRawScriptResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::CancelTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeCancelTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseCancelTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetChains(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetChainsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetChainsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokens(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokensRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokensResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Token PhantasmaAPI::GetToken(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Token output; + bool success = PhantasmaJsonAPI::ParseGetTokenResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION TokenData PhantasmaAPI::GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenDataRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + TokenData output; + bool success = PhantasmaJsonAPI::ParseGetTokenDataResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetApps(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAppsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAppsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransfersRequest(request, tokenSymbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransfersResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetTokenTransferCount(const Char* tokenSymbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(request, tokenSymbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Balance PhantasmaAPI::GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenBalanceRequest(request, addressText, tokenSymbol, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Balance output; + bool success = PhantasmaJsonAPI::ParseGetTokenBalanceResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAuctionsCount(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsCountRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsRequest(request, symbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Auction PhantasmaAPI::GetAuction(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Auction output; + bool success = PhantasmaJsonAPI::ParseGetAuctionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +#endif + +namespace json +{ +#ifndef PHANTASMA_JSONVALUE + JSONValue Parse(const JSONDocument& doc) { return doc; } + + inline size_t SkipNumber(const JSONValue& v, size_t i, bool& out_error) + { + size_t j = v.find_first_not_of("+-0123456789.eE", i); + if( i==j ) { PHANTASMA_EXCEPTION("Invalid Number"); out_error = true; return i+1; } + return j; + } + inline size_t SkipString(const JSONValue& v, size_t i, bool& out_error) + { + if( v[i] != '"' ) { PHANTASMA_EXCEPTION("Invalid String"); out_error = true; return i+1; } + for(++i; i + void AddArray(JSONBuilder& b, const Char* key, Args... args) { b.AddArray(key, args...); } + PHANTASMA_FUNCTION void EndObject(JSONBuilder& b) { b.EndObject(); } +#endif +} +#endif +} diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/curl_rapidjson_PhantasmaAPI.h b/C++/Sample/Cli Sample/CurlRapidjsonSample/curl_rapidjson_PhantasmaAPI.h new file mode 100644 index 0000000..5fc3eae --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/curl_rapidjson_PhantasmaAPI.h @@ -0,0 +1,146 @@ +#pragma once +//------------------------------------------------------------------------------ +// This header supplies the Phantasma API with JSON features provided by the +// rapidjson library (http://rapidjson.org/) and HTTP features provided by the +// CURL library (https://curl.haxx.se/) +//------------------------------------------------------------------------------ +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include "curl/curl.h" +#include "curl/easy.h" + +#ifndef PHANTASMA_STRING +#include +#define PHANTASMA_STRING std::string +#endif + +class ReallocBuffer // buffer class for CURL to write responses into +{ +public: + ReallocBuffer(size_t initialCapacity = 1024) + : memory((char*)malloc(initialCapacity)) + , size(0), capactiy(initialCapacity) {} + ~ReallocBuffer() { free(memory); } + void clear() { size = 0; } + char* begin() { return memory; } + char* end() { return memory + size; } + size_t bytes() const { return size; } + size_t capacity() const { return capactiy; } + void append(const void* data, size_t dataSize) + { + size_t newCapacity = size + dataSize; + if (newCapacity > capactiy) + memory = (char*)realloc(memory, capactiy = newCapacity); + memcpy(end(), data, dataSize); + size += dataSize; + } + static size_t CurlWrite(void *contents, size_t size, size_t nmemb, void *userp) + { + size_t realsize = size * nmemb; + ReallocBuffer* mem = (ReallocBuffer*)userp; + mem->append(contents, realsize); + return realsize; + } +private: + char* memory; + size_t size; + size_t capactiy; +}; + +class CurlClient // Very simple wrapper around CURL +{ + void* m_curl = 0; +public: + rapidjson::Document doc; + ReallocBuffer result; + const std::string host = "http://localhost:7077"; + + CurlClient() + { + m_curl = curl_easy_init(); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, ReallocBuffer::CurlWrite); + } + ~CurlClient() + { + curl_easy_cleanup(m_curl); + } + CURLcode Post(const char* data, size_t dataLen, const char* url) + { + result.clear(); + std::string fullUrl = host + url; + curl_easy_setopt(m_curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, (void*)&result); + curl_easy_setopt(m_curl, CURLOPT_POST, 1); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, dataLen); + CURLcode result = curl_easy_perform(m_curl); + return result; + } +}; + +struct RapidJsonBufferWriter +{ + rapidjson::StringBuffer buf; + rapidjson::Writer w; + RapidJsonBufferWriter() : w(buf) {} +}; + +namespace phantasma { + namespace json { + inline const rapidjson::Value& Parse(const rapidjson::Document& d) { return d; } + inline int32_t LookupInt32( const rapidjson::Value& v, const char* field, bool& out_error) { return v[field].GetInt(); } + inline uint32_t LookupUInt32( const rapidjson::Value& v, const char* field, bool& out_error) { return (uint32_t)v[field].GetInt(); } + inline PHANTASMA_STRING LookupString( const rapidjson::Value& v, const char* field, bool& out_error) { return (PHANTASMA_STRING)(v[field].GetString()); } + inline const rapidjson::Value& LookupValue( const rapidjson::Value& v, const char* field, bool& out_error) { return v[field]; } + inline const rapidjson::Value& LookupArray( const rapidjson::Value& v, const char* field, bool& out_error) { return v[field]; } + inline bool HasField( const rapidjson::Value& v, const char* field, bool& out_error) { return v.HasMember(field); } + inline bool HasArrayField(const rapidjson::Value& v, const char* field, bool& out_error) { return v[field].IsArray(); } + inline int32_t AsInt32( const rapidjson::Value& v, bool& out_error) { return v.GetInt(); } + inline uint32_t AsUInt32( const rapidjson::Value& v, bool& out_error) { return (uint32_t)v.GetInt(); } + inline PHANTASMA_STRING AsString( const rapidjson::Value& v, bool& out_error) { return (PHANTASMA_STRING)(v.GetString()); } + inline const rapidjson::Value& AsArray( const rapidjson::Value& v, bool& out_error) { return v; } + inline bool IsArray( const rapidjson::Value& v, bool& out_error) { return v.IsArray(); } + inline bool IsObject( const rapidjson::Value& v, bool& out_error) { return v.IsObject(); } + + inline int ArraySize( const rapidjson::Value& v, bool& out_error) { return v.Size(); } + inline const rapidjson::Value& IndexArray(const rapidjson::Value& v, int index, bool& out_error) { return v[index]; } + + typedef RapidJsonBufferWriter Builder; + inline void BeginObject(Builder& b) { b.w.StartObject(); } + inline void EndObject(Builder& b) { b.w.EndObject();} + inline void AddString(Builder& b, const char* key, const char* value) { b.w.String(key); b.w.String(value); } + inline void AddValues(Builder& ar) {} + inline void AddValues(Builder& b, const char* arg) { b.w.String(arg); } + inline void AddValues(Builder& b, int32_t arg) { b.w.Int(arg); } + inline void AddValues(Builder& b, uint32_t arg) { b.w.Int(arg); } + template void AddValues(Builder& b, T arg0, Args... args) + { + AddValues(b, arg0); + AddValues(b, args...); + } + template void AddArray(Builder& b, const char* key, Args... args) + { + b.w.String(key); + b.w.StartArray(); + AddValues(b, args...); + b.w.EndArray(); + } + } + static rapidjson::Document& HttpPost(CurlClient& client, const char* uri, const RapidJsonBufferWriter& data) + { + std::string url = client.host + uri; + const char* request = data.buf.GetString(); + client.Post(request, strlen(request), url.c_str()); + client.result.append("\0", 1); + return client.doc.ParseInsitu<0>(client.result.begin()); + } +} + +typedef const rapidjson::Value& RapidJsonValueRef; +#define PHANTASMA_JSONVALUE RapidJsonValueRef +#define PHANTASMA_JSONARRAY rapidjson::Value +#define PHANTASMA_JSONDOCUMENT rapidjson::Document +#define PHANTASMA_JSONBUILDER RapidJsonBufferWriter +#define PHANTASMA_HTTPCLIENT CurlClient +#include "PhantasmaAPI.h" diff --git a/C++/Sample/Cli Sample/CurlRapidjsonSample/main.cpp b/C++/Sample/Cli Sample/CurlRapidjsonSample/main.cpp new file mode 100644 index 0000000..65a0d6f --- /dev/null +++ b/C++/Sample/Cli Sample/CurlRapidjsonSample/main.cpp @@ -0,0 +1,22 @@ +#define PHANTASMA_IMPLEMENTATION +#include "curl_rapidjson_PhantasmaAPI.h" +#include + +int main() +{ + //std::string address = "P2f7ZFuj6NfZ76ymNMnG3xRBT5hAMicDrQRHE4S7SoxEr"; //genesis address + //std::string address = "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; //nft address + + const char* wif = "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; + + CurlClient http; + phantasma::PhantasmaAPI phantasmaAPI(http); + phantasma::Account account = phantasmaAPI.GetAccount(wif); + + std::cout << "Balance description for address " << wif << std::endl; + + for (int i = 0; i < account.balances.size(); i++) + { + std::cout << account.balances[i].amount << " " << account.balances[i].symbol << " tokens available on " << account.balances[i].chain << " chain" << std::endl; + } +} diff --git a/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.filters b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.filters new file mode 100644 index 0000000..abc99fb --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.user b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.user new file mode 100644 index 0000000..2c3e185 --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.user @@ -0,0 +1,6 @@ + + + + WindowsLocalDebugger + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj new file mode 100644 index 0000000..42a3b40 --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {4F3FA074-DD64-48BE-B226-241225052279} + Win32Proj + CSpookTest + 10.0.17763.0 + LowLevelSample + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(IncludePath) + $(ExecutablePath) + $(LibraryPath) + + + true + + + false + + + false + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + %(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _WINSOCK_DEPRECATED_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) + + + Console + true + D:\Projects\vcpkg\installed\x64-windows\lib + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + _WINSOCK_DEPRECATED_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + D:\Projects\vcpkg\installed\x64-windows\include%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Projects\vcpkg\installed\x64-windows\lib + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj.user b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/LowLevelSample.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/C++/Sample/Cli Sample/LowLevelSample/PhantasmaAPI.h b/C++/Sample/Cli Sample/LowLevelSample/PhantasmaAPI.h new file mode 100644 index 0000000..03cfe05 --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/PhantasmaAPI.h @@ -0,0 +1,2033 @@ +#pragma once +//------------------------------------------------------------------------------ +// Low-level API +//------------------------------------------------------------------------------ +// The PhantasmaJsonAPI namespace can construct JSON requests and parse JSON responses, +// but you are responsible for sending/receiving these messages via HTTP on your own. +// You can call PhantasmaJsonAPI::Uri() to determine where to send them. +// +// void PhantasmaJsonAPI::Make{Message}Request(JSONBuilder&, {Parameters}); +// bool PhantasmaJsonAPI::Parse{Message}Response(const JSONValue&, {Output}); +// +//------------------------------------------------------------------------------ +// High-level API +//------------------------------------------------------------------------------ +// If you have defined PHANTASMA_HTTPCLIENT, then you can construct a PhantasmaAPI object, +// which provides a simplified API that hides the internal JSON messaging. +// +// PhantasmaAPI phantasmaAPI(httpClient); +// {Output} phantasmaAPI->{Message}({Parameters}); +// +//------------------------------------------------------------------------------ +// API configuration +//------------------------------------------------------------------------------ +// As different C++ projects may use different primitive types, you can use the +// following #defines (BEFORE including phantasma.h) to override the default types. +// +// #define | typedef | Default | Notes +// PHANTASMA_INT32 | phantasma::Int32 | int32_t | +// PHANTASMA_UINT32 | phantasma::UInt32 | uint32_t | +// PHANTASMA_CHAR | phantasma::Char | char | See Unicode section +// PHANTASMA_STRING | phantasma::String | std::string | Must support construction from `const phantasma::Char*` +// PHANTASMA_VECTOR | | std::vector | Must support `push_back` and `size` members +// PHANTASMA_JSONVALUE | phantasma::JSONValue | std::string_view | See JSON section +// PHANTASMA_JSONARRAY | phantasma::JSONArray | JSONValue | See JSON section +// PHANTASMA_JSONDOCUMENT| phantasma::JSONDocument| std::string | See JSON section +// PHANTASMA_JSONBUILDER | phantasma::JSONBuilder | std::stringstream*| See JSON section +// PHANTASMA_HTTPCLIENT | phantasma::HttpClient | | See HTTP section +// +// The behavior of this header can further be modified by using the following +// #defines (BEFORE including phantasma.h) +// +// #define | Notes +// PHANTASMA_EXCEPTION(message) | See Exceptions section +// PHANTASMA_EXCEPTION_MESSAGE(message, String) | See Exceptions section +// PHANTASMA_LITERAL(x) | See Unicode section +// PHANTASMA_FUNCTION | See Integration section +// PHANTASMA_IMPLEMENTATION | See Integration section +// +//------------------------------------------------------------------------------ +// Integration +//------------------------------------------------------------------------------ +// This API is provided in the "single header" style to support simple and flexible +// integration into your project (see https://github.com/nothings/single_file_libs). +// The implementation of function bodies will be excluded unless you define +// PHANTASMA_IMPLEMENTATION before including phantasma.h. +// +// Typical linking: +// In one CPP file, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// +// Inline linking: +// In every CPP file that uses the API, before including phantasma.h: +// #define PHANTASMA_IMPLEMENTATION +// #define PHANTASMA_FUNCTION inline +// +// Aside from PHANTASMA_IMPLEMENTATION / PHANTASMA_FUNCTION, you should take care +// to ensure that every other PHANTASMA_* macro is defined to the same value in +// all of yoru CPP files that use the phantasma API. +// +//------------------------------------------------------------------------------ +// Exceptions +//------------------------------------------------------------------------------ +// Support for C++ exceptions is opt-in. Define the following (or an alternative +// based on your own exception classes) before including phantasma.h: +// #define PHANTASMA_EXCEPTION(message) throw std::runtime_error(message) +// #define PHANTASMA_EXCEPTION_MESSAGE(message, string) throw std::runtime_error(string) +// +//------------------------------------------------------------------------------ +// Unicode +//------------------------------------------------------------------------------ +// To build a wide-character version of the API, define the following before +// including phantasma.h: +// #define PHANTASMA_CHAR wchar_t +// #define PHANTASMA_LITERAL(x) L ## x +// #define PHANTASMA_STRING std::wstring +// +// You should also provide a JSON and HTTP library with wide-character support. +// +//------------------------------------------------------------------------------ +// JSON +//------------------------------------------------------------------------------ +// This header contains JSON parsing and building code, but it is written to be +// as simple as possible (approx 200 lines of code) and is not high-performance +// or highly robust. +// +// It is recommended that you supply another JSON-parsing API, by defining the +// following macros before including phantasma.h: +// #define PHANTASMA_JSONVALUE Your_Json_Value_Type +// #define PHANTASMA_JSONARRAY Your_Json_Array_Type +// #define PHANTASMA_JSONDOCUMENT Your_JSON_Document_Type +// #define PHANTASMA_JSONBUILDER Your_Json_Serializer_Type +// +// Also, this header uses the following procedural API to interact with these types. +// If you have supplied your own JSON types, you must implement the following functions: +// +// namespace phantasma { namespace json { +// +// JSONValue Parse(const JSONDocument&); +// +// Int32 LookupInt32( const JSONValue&, const Char* field, bool& out_error); +// UInt32 LookupUInt32( const JSONValue&, const Char* field, bool& out_error); +// String LookupString( const JSONValue&, const Char* field, bool& out_error); +// JSONValue LookupValue( const JSONValue&, const Char* field, bool& out_error); +// JSONArray LookupArray( const JSONValue&, const Char* field, bool& out_error); +// bool HasField( const JSONValue&, const Char* field, bool& out_error); +// bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); +// +// Int32 AsInt32( const JSONValue&, bool& out_error); +// UInt32 AsUInt32( const JSONValue&, bool& out_error); +// String AsString( const JSONValue&, bool& out_error); +// JSONArray AsArray( const JSONValue&, bool& out_error); +// bool IsArray( const JSONValue&, bool& out_error); +// bool IsObject( const JSONValue&, bool& out_error); +// +// int ArraySize( const JSONArray&, bool& out_error); +// JSONValue IndexArray( const JSONArray&, int index, bool& out_error); +// +// void BeginObject(JSONBuilder&); +// void AddString (JSONBuilder&, const Char* key, const Char* value); +// template void AddArray (JSONBuilder&, const Char* key, Args...); +// void EndObject (JSONBuilder&); +// }} +// +//------------------------------------------------------------------------------ +// HTTP +//------------------------------------------------------------------------------ +// This header does not contain a HTTP client, nor a dependency on any specific +// HTTP client library. If you do not supply a HTTP client library, then only +// the Low-level phantasma API (PhantasmaJsonAPI) is available. +// +// To enable the PhantasmaAPI class, defining the following macro before +// including phantasma.h: +// #define PHANTASMA_HTTPCLIENT Your_HTTP_Client_Type +// +// Also, this header uses the following procedural API to interact with this type. +// If you have defined PHANTASMA_HTTPCLIENT, you must implement the following, +// function, which should perform a HTTP POST request and return the result: +// +// namespace phantasma { +// JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +// } +// +//------------------------------------------------------------------------------ + +#if !defined(PHANTASMA_STRING) || !defined(PHANTASMA_JSONDOCUMENT) || !defined(PHANTASMA_JSONVALUE) +#include +#endif + +#if !defined(PHANTASMA_JSONVALUE) && __cplusplus > 201402L +#include +#endif + +#if !defined(PHANTASMA_JSONBUILDER) +#include +#endif + +#if !defined(PHANTASMA_VECTOR) +#define PHANTASMA_VECTOR std::vector +#include +#endif + +#if !defined(PHANTASMA_S32) || !defined(PHANTASMA_U32) +#include +#endif + +#if !defined(PHANTASMA_EXCEPTION) +#define PHANTASMA_EXCEPTION(literal) +#define PHANTASMA_EXCEPTION_MESSAGE(literal, string) +#endif + +#if !defined(PHANTASMA_LITERAL) +#define PHANTASMA_LITERAL(x) x +#endif + +#if !defined(PHANTASMA_FUNCTION) +#define PHANTASMA_FUNCTION +#endif + +namespace phantasma +{ +#ifdef PHANTASMA_CHAR +typedef PHANTASMA_CHAR Char; +#else +typedef char Char; +#endif + +#ifdef PHANTASMA_INT32 +typedef PHANTASMA_INT32 Int32; +#else +typedef int32_t Int32; +#endif + +#ifdef PHANTASMA_UINT32 +typedef PHANTASMA_UINT32 UInt32; +#else +typedef uint32_t UInt32; +#endif + +#ifdef PHANTASMA_STRING +typedef PHANTASMA_STRING String; +#else +typedef std::string String; +#endif + +#ifdef PHANTASMA_JSONVALUE +typedef PHANTASMA_JSONVALUE JSONValue; +#elif __cplusplus > 201402L +typedef std::string_view JSONValue; +#else +typedef std::string JSONValue; +#endif + +#ifdef PHANTASMA_JSONARRAY +typedef PHANTASMA_JSONARRAY JSONArray; +#else +typedef JSONValue JSONArray; +#endif + +#ifdef PHANTASMA_JSONDOCUMENT +typedef PHANTASMA_JSONDOCUMENT JSONDocument; +#else +typedef std::string JSONDocument; +#endif + + +#ifdef PHANTASMA_JSONBUILDER +typedef PHANTASMA_JSONBUILDER JSONBuilder; +#else +struct JSONBuilder // A VERY simple json string builder. Highly recommended that you provide a real JSON library instead! +{ + std::stringstream s; + bool empty = true; + operator std::stringstream&() { return s; } + void AddKey(const Char* key) { if(!empty) { s << ", "; } empty = false; s << '"' << key << "\": "; } + void AddValues() {} + void AddValues(const char* arg) { s << '"' << arg << '"'; } + template void AddValues(T arg) { s << arg; } + template void AddValues(T arg0, Args... args) { AddValues(arg0); s << ", "; AddValues(args...); } + + void BeginObject() { s << "{"; } + void AddString(const Char* key, const Char* value) { AddKey(key); s << '"' << value << '"'; } + template void AddArray(const Char* key, Args... args) { AddKey(key); s << '['; AddValues(args...); s << ']'; } + void EndObject() { s << "}"; } +}; +#endif + +#ifdef PHANTASMA_HTTPCLIENT +typedef PHANTASMA_HTTPCLIENT HttpClient; +//JSONDocument HttpPost(HttpClient&, const Char* uri, const JSONBuilder&); +#endif + +//If providing a JSON library (highly recommended that you do!), then you must provide these functions yourself: +namespace json +{ +#ifndef PHANTASMA_JSONBUILDER + JSONValue Parse(const JSONDocument&); + Int32 LookupInt32(const JSONValue&, const Char* field, bool& out_error); + UInt32 LookupUInt32(const JSONValue&, const Char* field, bool& out_error); + String LookupString(const JSONValue&, const Char* field, bool& out_error); + JSONValue LookupValue(const JSONValue&, const Char* field, bool& out_error); + JSONArray LookupArray(const JSONValue&, const Char* field, bool& out_error); + bool HasField(const JSONValue&, const Char* field, bool& out_error); + bool HasArrayField(const JSONValue&, const Char* field, bool& out_error); + Int32 AsInt32(const JSONValue&, bool& out_error); + UInt32 AsUInt32(const JSONValue&, bool& out_error); + String AsString(const JSONValue&, bool& out_error); + JSONArray AsArray(const JSONValue&, bool& out_error); + bool IsArray(const JSONValue&, bool& out_error); + bool IsObject(const JSONValue&, bool& out_error); + + int ArraySize(const JSONArray&, bool& out_error); + JSONValue IndexArray(const JSONArray&, int index, bool& out_error); + + void BeginObject(JSONBuilder&); + void AddString(JSONBuilder&, const Char* key, const Char* value); + template + void AddArray(JSONBuilder&, const Char* key, Args... args); + void EndObject(JSONBuilder&); +#endif +} + + +struct Balance +{ + String chain;// + String amount;// + String symbol;// + UInt32 decimals;// + PHANTASMA_VECTOR ids;// +}; + +struct Account +{ + String address;// + String name;// + PHANTASMA_VECTOR balances;// +}; + +struct Chain +{ + String name;// + String address;// + String parentAddress;// + UInt32 height;// +}; + +struct App +{ + String id;// + String title;// + String url;// + String description;// + String icon;// +}; + +struct Event +{ + String address;// + String kind;// + String data;// +}; + +struct Transaction +{ + String hash;// + String chainAddress;// + UInt32 timestamp;// + Int32 confirmations;// + UInt32 blockHeight;// + String blockHash;// + String script;// + PHANTASMA_VECTOR events;// + String result;// +}; + +struct AccountTransactions +{ + String address;// + PHANTASMA_VECTOR txs;// +}; + +struct Paginated +{ + UInt32 page;// + UInt32 pageSize;// + UInt32 total;// + UInt32 totalPages;// + JSONValue result;// +}; + +struct Block +{ + String hash;// + String previousHash;// + UInt32 timestamp;// + UInt32 height;// + String chainAddress;// + String payload;// + PHANTASMA_VECTOR txs;// + String validatorAddress;// + String reward;// +}; + +struct TokenMetadata +{ + String key;// + String value;// +}; + +struct Token +{ + String symbol;// + String name;// + Int32 decimals;// + String currentSupply;// + String maxSupply;// + String ownerAddress;// + PHANTASMA_VECTOR metadataList;// + String flags;// +}; + +struct TokenData +{ + String ID;// + String chainAddress;// + String ownerAddress;// + String ram;// + String rom;// + bool forSale;// +}; + +struct SendRawTx +{ + String hash;// + String error;// +}; + +struct Auction +{ + String creatorAddress;// + UInt32 startDate;// + UInt32 endDate;// + String baseSymbol;// + String quoteSymbol;// + String tokenId;// + String price;// +}; + +struct Script +{ + PHANTASMA_VECTOR events;// + String result;// +}; + + +class PhantasmaJsonAPI +{ +public: + static const Char* Uri() { return PHANTASMA_LITERAL("/rpc"); } + + // Returns the account name and balance of given address. + static void MakeGetAccountRequest(JSONBuilder&, const Char* addressText); + static bool ParseGetAccountResponse(const JSONValue&, Account& out); + // Returns the address that owns a given name. + static void MakeLookUpNameRequest(JSONBuilder&, const Char* name); + static bool ParseLookUpNameResponse(const JSONValue&, String& out); + // Returns the height of a chain. + static void MakeGetBlockHeightRequest(JSONBuilder&, const Char* chainInput); + static bool ParseGetBlockHeightResponse(const JSONValue&, Int32& out); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + static void MakeGetBlockTransactionCountByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockTransactionCountByHashResponse(const JSONValue&, Int32& out); + // Returns information about a block by hash. + static void MakeGetBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetBlockByHashResponse(const JSONValue&, Block& out); + // Returns a serialized string, containing information about a block by hash. + static void MakeGetRawBlockByHashRequest(JSONBuilder&, const Char* blockHash); + static bool ParseGetRawBlockByHashResponse(const JSONValue&, String& out); + // Returns information about a block by height and chain. + static void MakeGetBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetBlockByHeightResponse(const JSONValue&, Block& out); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + static void MakeGetRawBlockByHeightRequest(JSONBuilder&, const Char* chainInput, UInt32 height); + static bool ParseGetRawBlockByHeightResponse(const JSONValue&, String& out); + // Returns the information about a transaction requested by a block hash and transaction index. + static void MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder&, const Char* blockHash, Int32 index); + static bool ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue&, Transaction& out); + // Returns last X transactions of given address. (paginated call) + static void MakeGetAddressTransactionsRequest(JSONBuilder&, const Char* addressText, UInt32 page, UInt32 pageSize); + static bool ParseGetAddressTransactionsResponse(const JSONValue&, AccountTransactions& out); + // Get number of transactions in a specific address and chain + static void MakeGetAddressTransactionCountRequest(JSONBuilder&, const Char* addressText, const Char* chainInput); + static bool ParseGetAddressTransactionCountResponse(const JSONValue&, Int32& out); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + static void MakeSendRawTransactionRequest(JSONBuilder&, const Char* txData); + static bool ParseSendRawTransactionResponse(const JSONValue&, String& out); + // Allows to invoke script based on network state, without state changes. + static void MakeInvokeRawScriptRequest(JSONBuilder&, const Char* chainInput, const Char* scriptData); + static bool ParseInvokeRawScriptResponse(const JSONValue&, Script& out); + // Returns information about a transaction by hash. + static void MakeGetTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseGetTransactionResponse(const JSONValue&, Transaction& out); + // Removes a pending transaction from the mempool. + static void MakeCancelTransactionRequest(JSONBuilder&, const Char* hashText); + static bool ParseCancelTransactionResponse(const JSONValue&, String& out); + // Returns an array of all chains deployed in Phantasma. + static void MakeGetChainsRequest(JSONBuilder&); + static bool ParseGetChainsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns an array of tokens deployed in Phantasma. + static void MakeGetTokensRequest(JSONBuilder&); + static bool ParseGetTokensResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns info about a specific token deployed in Phantasma. + static void MakeGetTokenRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetTokenResponse(const JSONValue&, Token& out); + // Returns data of a non-fungible token, in hexadecimal format. + static void MakeGetTokenDataRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetTokenDataResponse(const JSONValue&, TokenData& out); + // Returns an array of apps deployed in Phantasma. + static void MakeGetAppsRequest(JSONBuilder&); + static bool ParseGetAppsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns last X transactions of given token. (paginated call) + static void MakeGetTokenTransfersRequest(JSONBuilder&, const Char* tokenSymbol, UInt32 page, UInt32 pageSize); + static bool ParseGetTokenTransfersResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the number of transaction of a given token. + static void MakeGetTokenTransferCountRequest(JSONBuilder&, const Char* tokenSymbol); + static bool ParseGetTokenTransferCountResponse(const JSONValue&, Int32& out); + // Returns the balance for a specific token and chain, given an address. + static void MakeGetTokenBalanceRequest(JSONBuilder&, const Char* addressText, const Char* tokenSymbol, const Char* chainInput); + static bool ParseGetTokenBalanceResponse(const JSONValue&, Balance& out); + // Returns the number of active auctions. + static void MakeGetAuctionsCountRequest(JSONBuilder&, const Char* symbol); + static bool ParseGetAuctionsCountResponse(const JSONValue&, Int32& out); + // Returns the auctions available in the market. (paginated call) + static void MakeGetAuctionsRequest(JSONBuilder&, const Char* symbol, UInt32 page, UInt32 pageSize); + static bool ParseGetAuctionsResponse(const JSONValue&, PHANTASMA_VECTOR& out); + // Returns the auction for a specific token. + static void MakeGetAuctionRequest(JSONBuilder&, const Char* symbol, const Char* IDtext); + static bool ParseGetAuctionResponse(const JSONValue&, Auction& out); + + +private: + static JSONValue CheckResponse(JSONValue response, bool& out_error); + static Balance DeserializeBalance(const JSONValue& json, bool& out_error); + static Account DeserializeAccount(const JSONValue& json, bool& out_error); + static Chain DeserializeChain(const JSONValue& json, bool& out_error); + static App DeserializeApp(const JSONValue& json, bool& out_error); + static Event DeserializeEvent(const JSONValue& json, bool& out_error); + static Transaction DeserializeTransaction(const JSONValue& json, bool& out_error); + static AccountTransactions DeserializeAccountTransactions(const JSONValue& json, bool& out_error); + static Paginated DeserializePaginated(const JSONValue& json, bool& out_error); + static Block DeserializeBlock(const JSONValue& json, bool& out_error); + static TokenMetadata DeserializeTokenMetadata(const JSONValue& json, bool& out_error); + static Token DeserializeToken(const JSONValue& json, bool& out_error); + static TokenData DeserializeTokenData(const JSONValue& json, bool& out_error); + static SendRawTx DeserializeSendRawTx(const JSONValue& json, bool& out_error); + static Auction DeserializeAuction(const JSONValue& json, bool& out_error); + static Script DeserializeScript(const JSONValue& json, bool& out_error); + +}; + +#if defined(PHANTASMA_HTTPCLIENT) +class PhantasmaAPI +{ +public: + PhantasmaAPI(HttpClient& client) // client must have a longer lifetime than this API object + : m_httpClient(client) + {} + + // Returns the account name and balance of given address. + Account GetAccount(const Char* addressText, bool* out_error = nullptr); + // Returns the address that owns a given name. + String LookUpName(const Char* name, bool* out_error = nullptr); + // Returns the height of a chain. + Int32 GetBlockHeight(const Char* chainInput, bool* out_error = nullptr); + // Returns the number of transactions of given block hash or error if given hash is invalid or is not found. + Int32 GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by hash. + Block GetBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns a serialized string, containing information about a block by hash. + String GetRawBlockByHash(const Char* blockHash, bool* out_error = nullptr); + // Returns information about a block by height and chain. + Block GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns a serialized string, in hex format, containing information about a block by height and chain. + String GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error = nullptr); + // Returns the information about a transaction requested by a block hash and transaction index. + Transaction GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error = nullptr); + // Returns last X transactions of given address. (paginated call) + AccountTransactions GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Get number of transactions in a specific address and chain + Int32 GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error = nullptr); + // Allows to broadcast a signed operation on the network, but it's required to build it manually. + String SendRawTransaction(const Char* txData, bool* out_error = nullptr); + // Allows to invoke script based on network state, without state changes. + Script InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error = nullptr); + // Returns information about a transaction by hash. + Transaction GetTransaction(const Char* hashText, bool* out_error = nullptr); + // Removes a pending transaction from the mempool. + String CancelTransaction(const Char* hashText, bool* out_error = nullptr); + // Returns an array of all chains deployed in Phantasma. + PHANTASMA_VECTOR GetChains(bool* out_error = nullptr); + // Returns an array of tokens deployed in Phantasma. + PHANTASMA_VECTOR GetTokens(bool* out_error = nullptr); + // Returns info about a specific token deployed in Phantasma. + Token GetToken(const Char* symbol, bool* out_error = nullptr); + // Returns data of a non-fungible token, in hexadecimal format. + TokenData GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + // Returns an array of apps deployed in Phantasma. + PHANTASMA_VECTOR GetApps(bool* out_error = nullptr); + // Returns last X transactions of given token. (paginated call) + PHANTASMA_VECTOR GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the number of transaction of a given token. + Int32 GetTokenTransferCount(const Char* tokenSymbol, bool* out_error = nullptr); + // Returns the balance for a specific token and chain, given an address. + Balance GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error = nullptr); + // Returns the number of active auctions. + Int32 GetAuctionsCount(const Char* symbol, bool* out_error = nullptr); + // Returns the auctions available in the market. (paginated call) + PHANTASMA_VECTOR GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error = nullptr); + // Returns the auction for a specific token. + Auction GetAuction(const Char* symbol, const Char* IDtext, bool* out_error = nullptr); + +private: + HttpClient& m_httpClient; +}; +#endif + +#if defined(PHANTASMA_IMPLEMENTATION) + +PHANTASMA_FUNCTION Balance PhantasmaJsonAPI::DeserializeBalance(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR idsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("ids"), err)) + { + const JSONArray& idsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("ids"), err); + int size = json::ArraySize(idsJsonArray, err); + idsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + idsVector.push_back(json::AsString(json::IndexArray(idsJsonArray, i, err), err)); + } + } + return Balance { + json::LookupString(value, PHANTASMA_LITERAL("chain"), err), + json::LookupString(value, PHANTASMA_LITERAL("amount"), err), + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("decimals"), err), + idsVector + }; +} + +PHANTASMA_FUNCTION Account PhantasmaJsonAPI::DeserializeAccount(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR balancesVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("balances"), err)) + { + const JSONArray& balancesJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("balances"), err); + int size = json::ArraySize(balancesJsonArray, err); + balancesVector.reserve(size); + for(int i = 0; i < size; ++i) + { + balancesVector.push_back(DeserializeBalance(json::IndexArray(balancesJsonArray, i, err), err)); + } + } + return Account { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + balancesVector + }; +} + +PHANTASMA_FUNCTION Chain PhantasmaJsonAPI::DeserializeChain(const JSONValue& value, bool& err) +{ + return Chain { + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("parentAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err) + }; +} + +PHANTASMA_FUNCTION App PhantasmaJsonAPI::DeserializeApp(const JSONValue& value, bool& err) +{ + return App { + json::LookupString(value, PHANTASMA_LITERAL("id"), err), + json::LookupString(value, PHANTASMA_LITERAL("title"), err), + json::LookupString(value, PHANTASMA_LITERAL("url"), err), + json::LookupString(value, PHANTASMA_LITERAL("description"), err), + json::LookupString(value, PHANTASMA_LITERAL("icon"), err) + }; +} + +PHANTASMA_FUNCTION Event PhantasmaJsonAPI::DeserializeEvent(const JSONValue& value, bool& err) +{ + return Event { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + json::LookupString(value, PHANTASMA_LITERAL("kind"), err), + json::LookupString(value, PHANTASMA_LITERAL("data"), err) + }; +} + +PHANTASMA_FUNCTION Transaction PhantasmaJsonAPI::DeserializeTransaction(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Transaction { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("confirmations"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("blockHeight"), err), + json::LookupString(value, PHANTASMA_LITERAL("blockHash"), err), + json::LookupString(value, PHANTASMA_LITERAL("script"), err), + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaJsonAPI::DeserializeAccountTransactions(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return AccountTransactions { + json::LookupString(value, PHANTASMA_LITERAL("address"), err), + txsVector + }; +} + +PHANTASMA_FUNCTION Paginated PhantasmaJsonAPI::DeserializePaginated(const JSONValue& value, bool& err) +{ + return Paginated { + json::LookupUInt32(value, PHANTASMA_LITERAL("page"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("pageSize"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("total"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("totalPages"), err), + json::LookupValue(value, PHANTASMA_LITERAL("result"), err) + }; +} + +PHANTASMA_FUNCTION Block PhantasmaJsonAPI::DeserializeBlock(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR txsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("txs"), err)) + { + const JSONArray& txsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("txs"), err); + int size = json::ArraySize(txsJsonArray, err); + txsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + txsVector.push_back(DeserializeTransaction(json::IndexArray(txsJsonArray, i, err), err)); + } + } + return Block { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("previousHash"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("timestamp"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("height"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("payload"), err), + txsVector, + json::LookupString(value, PHANTASMA_LITERAL("validatorAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("reward"), err) + }; +} + +PHANTASMA_FUNCTION TokenMetadata PhantasmaJsonAPI::DeserializeTokenMetadata(const JSONValue& value, bool& err) +{ + return TokenMetadata { + json::LookupString(value, PHANTASMA_LITERAL("key"), err), + json::LookupString(value, PHANTASMA_LITERAL("value"), err) + }; +} + +PHANTASMA_FUNCTION Token PhantasmaJsonAPI::DeserializeToken(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR metadataListVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("metadataList"), err)) + { + const JSONArray& metadataListJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("metadataList"), err); + int size = json::ArraySize(metadataListJsonArray, err); + metadataListVector.reserve(size); + for(int i = 0; i < size; ++i) + { + metadataListVector.push_back(DeserializeTokenMetadata(json::IndexArray(metadataListJsonArray, i, err), err)); + } + } + return Token { + json::LookupString(value, PHANTASMA_LITERAL("symbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("name"), err), + json::LookupInt32(value, PHANTASMA_LITERAL("decimals"), err), + json::LookupString(value, PHANTASMA_LITERAL("currentSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("maxSupply"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + metadataListVector, + json::LookupString(value, PHANTASMA_LITERAL("flags"), err) + }; +} + +PHANTASMA_FUNCTION TokenData PhantasmaJsonAPI::DeserializeTokenData(const JSONValue& value, bool& err) +{ + return TokenData { + json::LookupString(value, PHANTASMA_LITERAL("ID"), err), + json::LookupString(value, PHANTASMA_LITERAL("chainAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ownerAddress"), err), + json::LookupString(value, PHANTASMA_LITERAL("ram"), err), + json::LookupString(value, PHANTASMA_LITERAL("rom"), err), + (err=true, "Variable type Boolean isnt currently handled by the template system") + }; +} + +PHANTASMA_FUNCTION SendRawTx PhantasmaJsonAPI::DeserializeSendRawTx(const JSONValue& value, bool& err) +{ + return SendRawTx { + json::LookupString(value, PHANTASMA_LITERAL("hash"), err), + json::LookupString(value, PHANTASMA_LITERAL("error"), err) + }; +} + +PHANTASMA_FUNCTION Auction PhantasmaJsonAPI::DeserializeAuction(const JSONValue& value, bool& err) +{ + return Auction { + json::LookupString(value, PHANTASMA_LITERAL("creatorAddress"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("startDate"), err), + json::LookupUInt32(value, PHANTASMA_LITERAL("endDate"), err), + json::LookupString(value, PHANTASMA_LITERAL("baseSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("quoteSymbol"), err), + json::LookupString(value, PHANTASMA_LITERAL("tokenId"), err), + json::LookupString(value, PHANTASMA_LITERAL("price"), err) + }; +} + +PHANTASMA_FUNCTION Script PhantasmaJsonAPI::DeserializeScript(const JSONValue& value, bool& err) +{ + PHANTASMA_VECTOR eventsVector; + if(json::HasArrayField(value, PHANTASMA_LITERAL("events"), err)) + { + const JSONArray& eventsJsonArray = json::LookupArray(value, PHANTASMA_LITERAL("events"), err); + int size = json::ArraySize(eventsJsonArray, err); + eventsVector.reserve(size); + for(int i = 0; i < size; ++i) + { + eventsVector.push_back(DeserializeEvent(json::IndexArray(eventsJsonArray, i, err), err)); + } + } + return Script { + eventsVector, + json::LookupString(value, PHANTASMA_LITERAL("result"), err) + }; +} + + + +PHANTASMA_FUNCTION JSONValue PhantasmaJsonAPI::CheckResponse(JSONValue response, bool& out_error) +{ + if( !json::IsObject(response, out_error) ) + { + PHANTASMA_EXCEPTION("Failed to parse JSON"); + out_error = true; + return response; + } + if( json::HasField(response, PHANTASMA_LITERAL("error"), out_error) ) + { + String msg = json::LookupString(response, PHANTASMA_LITERAL("error"), out_error); + PHANTASMA_EXCEPTION_MESSAGE("Server returned error: %s", msg); + out_error = true; + return response; + } + if( !json::HasField(response, PHANTASMA_LITERAL("result"), out_error) ) + { + PHANTASMA_EXCEPTION("Malformed response: No \"result\" node on the JSON body"); + out_error = true; + return response; + } + return json::LookupValue(response, PHANTASMA_LITERAL("result"), out_error); +} + + +// Returns the account name and balance of given address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAccountRequest(JSONBuilder& request, const Char* addressText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAccount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAccountResponse(const JSONValue& _jsonResponse, Account& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAccount(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the address that owns a given name. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeLookUpNameRequest(JSONBuilder& request, const Char* name) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("lookUpName")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), name); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseLookUpNameResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the height of a chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockHeightRequest(JSONBuilder& request, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockHeightResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the number of transactions of given block hash or error if given hash is invalid or is not found. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockTransactionCountByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHashResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, containing information about a block by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(JSONBuilder& request, const Char* blockHash) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHash")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetBlockByHeightResponse(const JSONValue& _jsonResponse, Block& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBlock(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns a serialized string, in hex format, containing information about a block by height and chain. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(JSONBuilder& request, const Char* chainInput, UInt32 height) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getRawBlockByHeight")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, height); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns the information about a transaction requested by a block hash and transaction index. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(JSONBuilder& request, const Char* blockHash, Int32 index) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransactionByBlockHashAndIndex")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), blockHash, index); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns last X transactions of given address. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(JSONBuilder& request, const Char* addressText, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(const JSONValue& _jsonResponse, AccountTransactions& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + output = DeserializeAccountTransactions(pageStruct.result, err); + return !err; +} + +// Get number of transactions in a specific address and chain +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(JSONBuilder& request, const Char* addressText, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAddressTransactionCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Allows to broadcast a signed operation on the network, but it's required to build it manually. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeSendRawTransactionRequest(JSONBuilder& request, const Char* txData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("sendRawTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), txData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseSendRawTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Allows to invoke script based on network state, without state changes. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeInvokeRawScriptRequest(JSONBuilder& request, const Char* chainInput, const Char* scriptData) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("invokeRawScript")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), chainInput, scriptData); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseInvokeRawScriptResponse(const JSONValue& _jsonResponse, Script& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeScript(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns information about a transaction by hash. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTransactionResponse(const JSONValue& _jsonResponse, Transaction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTransaction(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Removes a pending transaction from the mempool. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeCancelTransactionRequest(JSONBuilder& request, const Char* hashText) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("cancelTransaction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), hashText); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseCancelTransactionResponse(const JSONValue& _jsonResponse, String& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsString(jsonResponse, err); + return !err; +} + + +// Returns an array of all chains deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetChainsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getChains")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetChainsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeChain(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns an array of tokens deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokensRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokens")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokensResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeToken(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns info about a specific token deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getToken")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenResponse(const JSONValue& _jsonResponse, Token& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeToken(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns data of a non-fungible token, in hexadecimal format. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenDataRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenData")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenDataResponse(const JSONValue& _jsonResponse, TokenData& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeTokenData(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns an array of apps deployed in Phantasma. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAppsRequest(JSONBuilder& request) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getApps")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params")); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAppsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + if (!json::IsArray(jsonResponse, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + + const JSONArray& resultArray = json::AsArray(jsonResponse, err); + int resultArraySize = json::ArraySize(resultArray, err); + output.reserve(resultArraySize); + for(int i = 0; i < resultArraySize; ++i) + { + output.push_back(DeserializeApp(json::IndexArray(resultArray, i, err), err)); + if( err ) return false; + } + return !err; +} + + +// Returns last X transactions of given token. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransfersRequest(JSONBuilder& request, const Char* tokenSymbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransfers")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransfersResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeTransaction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the number of transaction of a given token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(JSONBuilder& request, const Char* tokenSymbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenTransferCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), tokenSymbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the balance for a specific token and chain, given an address. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetTokenBalanceRequest(JSONBuilder& request, const Char* addressText, const Char* tokenSymbol, const Char* chainInput) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getTokenBalance")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), addressText, tokenSymbol, chainInput); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetTokenBalanceResponse(const JSONValue& _jsonResponse, Balance& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeBalance(jsonResponse, err); + if( err ) return false; + return !err; +} + + +// Returns the number of active auctions. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsCountRequest(JSONBuilder& request, const Char* symbol) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctionsCount")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsCountResponse(const JSONValue& _jsonResponse, Int32& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = json::AsInt32(jsonResponse, err); + return !err; +} + + +// Returns the auctions available in the market. (Paginated) +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionsRequest(JSONBuilder& request, const Char* symbol, UInt32 page, UInt32 pageSize) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuctions")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, page, pageSize); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionsResponse(const JSONValue& _jsonResponse, PHANTASMA_VECTOR& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + Paginated pageStruct = DeserializePaginated(jsonResponse, err); + if(!json::IsArray(pageStruct.result, err)) + { + PHANTASMA_EXCEPTION("Malformed response: No JSON array on the \"result\" node"); + return false; + } + const JSONArray& pages = json::AsArray(pageStruct.result, err); + int size = json::ArraySize(pages, err); + output.reserve(size); + for(int i = 0; i < size; ++i) + { + output.push_back(DeserializeAuction(json::IndexArray(pages, i, err), err)); + } + return !err; +} + +// Returns the auction for a specific token. +PHANTASMA_FUNCTION void PhantasmaJsonAPI::MakeGetAuctionRequest(JSONBuilder& request, const Char* symbol, const Char* IDtext) +{ + json::BeginObject(request); + json::AddString(request, PHANTASMA_LITERAL("jsonrpc"), PHANTASMA_LITERAL("2.0")); + json::AddString(request, PHANTASMA_LITERAL("method"), PHANTASMA_LITERAL("getAuction")); + json::AddString(request, PHANTASMA_LITERAL("id"), PHANTASMA_LITERAL("1")); + json::AddArray(request, PHANTASMA_LITERAL("params"), symbol, IDtext); + json::EndObject(request); +} + +PHANTASMA_FUNCTION bool PhantasmaJsonAPI::ParseGetAuctionResponse(const JSONValue& _jsonResponse, Auction& output) +{ + bool err = false; + JSONValue jsonResponse = PhantasmaJsonAPI::CheckResponse(_jsonResponse, err); + if( err ) + return false; + output = DeserializeAuction(jsonResponse, err); + if( err ) return false; + return !err; +} + + + +#if defined(PHANTASMA_HTTPCLIENT) + +PHANTASMA_FUNCTION Account PhantasmaAPI::GetAccount(const Char* addressText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAccountRequest(request, addressText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Account output; + bool success = PhantasmaJsonAPI::ParseGetAccountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::LookUpName(const Char* name, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeLookUpNameRequest(request, name); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseLookUpNameResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockHeight(const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockHeightRequest(request, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetBlockTransactionCountByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockTransactionCountByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetBlockTransactionCountByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHash(const Char* blockHash, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHashRequest(request, blockHash); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHashResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Block PhantasmaAPI::GetBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Block output; + bool success = PhantasmaJsonAPI::ParseGetBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::GetRawBlockByHeight(const Char* chainInput, UInt32 height, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetRawBlockByHeightRequest(request, chainInput, height); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseGetRawBlockByHeightResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransactionByBlockHashAndIndex(const Char* blockHash, Int32 index, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionByBlockHashAndIndexRequest(request, blockHash, index); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionByBlockHashAndIndexResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION AccountTransactions PhantasmaAPI::GetAddressTransactions(const Char* addressText, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionsRequest(request, addressText, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + AccountTransactions output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAddressTransactionCount(const Char* addressText, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAddressTransactionCountRequest(request, addressText, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAddressTransactionCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::SendRawTransaction(const Char* txData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeSendRawTransactionRequest(request, txData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseSendRawTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Script PhantasmaAPI::InvokeRawScript(const Char* chainInput, const Char* scriptData, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeInvokeRawScriptRequest(request, chainInput, scriptData); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Script output; + bool success = PhantasmaJsonAPI::ParseInvokeRawScriptResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Transaction PhantasmaAPI::GetTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Transaction output; + bool success = PhantasmaJsonAPI::ParseGetTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION String PhantasmaAPI::CancelTransaction(const Char* hashText, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeCancelTransactionRequest(request, hashText); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + String output; + bool success = PhantasmaJsonAPI::ParseCancelTransactionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetChains(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetChainsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetChainsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokens(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokensRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokensResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Token PhantasmaAPI::GetToken(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Token output; + bool success = PhantasmaJsonAPI::ParseGetTokenResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION TokenData PhantasmaAPI::GetTokenData(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenDataRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + TokenData output; + bool success = PhantasmaJsonAPI::ParseGetTokenDataResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetApps(bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAppsRequest(request); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAppsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetTokenTransfers(const Char* tokenSymbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransfersRequest(request, tokenSymbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransfersResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetTokenTransferCount(const Char* tokenSymbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenTransferCountRequest(request, tokenSymbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetTokenTransferCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Balance PhantasmaAPI::GetTokenBalance(const Char* addressText, const Char* tokenSymbol, const Char* chainInput, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetTokenBalanceRequest(request, addressText, tokenSymbol, chainInput); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Balance output; + bool success = PhantasmaJsonAPI::ParseGetTokenBalanceResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Int32 PhantasmaAPI::GetAuctionsCount(const Char* symbol, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsCountRequest(request, symbol); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Int32 output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsCountResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION PHANTASMA_VECTOR PhantasmaAPI::GetAuctions(const Char* symbol, UInt32 page, UInt32 pageSize, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionsRequest(request, symbol, page, pageSize); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + PHANTASMA_VECTOR output; + bool success = PhantasmaJsonAPI::ParseGetAuctionsResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +PHANTASMA_FUNCTION Auction PhantasmaAPI::GetAuction(const Char* symbol, const Char* IDtext, bool* out_error) +{ + JSONBuilder request; + PhantasmaJsonAPI::MakeGetAuctionRequest(request, symbol, IDtext); + const JSONDocument& response = HttpPost(m_httpClient, PhantasmaJsonAPI::Uri(), request); + Auction output; + bool success = PhantasmaJsonAPI::ParseGetAuctionResponse(json::Parse(response), output); + if( !success && out_error ) + *out_error = true; + return output; +} + +#endif + +namespace json +{ +#ifndef PHANTASMA_JSONVALUE + JSONValue Parse(const JSONDocument& doc) { return doc; } + + inline size_t SkipNumber(const JSONValue& v, size_t i, bool& out_error) + { + size_t j = v.find_first_not_of("+-0123456789.eE", i); + if( i==j ) { PHANTASMA_EXCEPTION("Invalid Number"); out_error = true; return i+1; } + return j; + } + inline size_t SkipString(const JSONValue& v, size_t i, bool& out_error) + { + if( v[i] != '"' ) { PHANTASMA_EXCEPTION("Invalid String"); out_error = true; return i+1; } + for(++i; i + void AddArray(JSONBuilder& b, const Char* key, Args... args) { b.AddArray(key, args...); } + PHANTASMA_FUNCTION void EndObject(JSONBuilder& b) { b.EndObject(); } +#endif +} +#endif +} diff --git a/C++/Sample/Cli Sample/LowLevelSample/main.cpp b/C++/Sample/Cli Sample/LowLevelSample/main.cpp new file mode 100644 index 0000000..afea261 --- /dev/null +++ b/C++/Sample/Cli Sample/LowLevelSample/main.cpp @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// This sample does NOT actually communicate with the network/chain. It only +// serves to demonstrate how to use the low-level JSON API, allowing you to +// perform HTTP requests yourself. +//------------------------------------------------------------------------------ + +#define PHANTASMA_IMPLEMENTATION +#include "PhantasmaAPI.h" +#include + +const char* DoHttpPost( const char* uri, const std::string& request ) +{ + //This is where you'd perform the HTTP POST request... + //Hard-coded response: + return R"({"jsonrpc": "2.0", "result": {"address" : "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE","name" : "anonymous","balances" : [{"chain" : "main","amount" : "208000046079","symbol" : "SOUL","decimals" : 10},{"chain" : "main","amount" : "5000000000000","symbol" : "NEOSOUL","decimals" : 8},{"chain" : "main","amount" : "6","symbol" : "NACHO","decimals" : 0,"ids" : ["101","102","103","104","105","106"]}]}, "id": 1})"; +} + +int main() +{ + //std::string address = "P2f7ZFuj6NfZ76ymNMnG3xRBT5hAMicDrQRHE4S7SoxEr"; //genesis address + //std::string address = "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; //nft address + + const char* wif = "NztsEZP7dtrzRBagogUYVp6mgEFbhjZfvHMVkd2bYWJfE"; + + phantasma::JSONBuilder json; + phantasma::PhantasmaJsonAPI::MakeGetAccountRequest(json, wif); + + phantasma::JSONValue response = DoHttpPost(phantasma::PhantasmaJsonAPI::Uri(), json.s.str()); + + phantasma::Account account; + phantasma::PhantasmaJsonAPI::ParseGetAccountResponse(response, account); + + std::cout << "Balance description for address " << wif << std::endl; + + for (int i = 0; i < account.balances.size(); i++) + { + std::cout << account.balances[i].amount << " " << account.balances[i].symbol << " tokens available on " << account.balances[i].chain << " chain" << std::endl; + } +} diff --git a/SDK.Builder/SDK.Builder/Program.cs b/SDK.Builder/SDK.Builder/Program.cs index 063ddde..ebd2191 100644 --- a/SDK.Builder/SDK.Builder/Program.cs +++ b/SDK.Builder/SDK.Builder/Program.cs @@ -191,6 +191,7 @@ static void GenerateBindings(string inputPath, string outputPath) string replacementFile = inputPath + "language.ini"; var replacements = new Dictionary(); + var replacementsRef = new Dictionary(); if (File.Exists(replacementFile)) { var lines = File.ReadAllLines(replacementFile); @@ -199,14 +200,26 @@ static void GenerateBindings(string inputPath, string outputPath) if (line.Contains(",")) { var temp = line.Split(new[] { ',' }, 2); - replacements[temp[0]] = temp[1]; + if( temp[0].StartsWith("@") ) + { + temp[0] = temp[0].Substring(1); + replacementsRef[temp[0]] = temp[1]; + } + else + replacements[temp[0]] = temp[1]; } } } var nexus = new Nexus(); var api = new NexusAPI(nexus); - + foreach (var v in replacements) + { + if (!replacementsRef.ContainsKey(v.Key)) + { + replacementsRef.Add(v.Key, v.Value); + } + } var typeDic = new Dictionary>(); var apiTypes = api.GetType().Assembly.GetTypes().Where(x => !x.IsInterface && x != typeof(SingleResult) && x != typeof(ArrayResult) && x != typeof(ErrorResult) && typeof(IAPIResult).IsAssignableFrom(x)).ToList(); foreach (var entry in apiTypes) @@ -217,6 +230,7 @@ static void GenerateBindings(string inputPath, string outputPath) var compiler = new Compiler(); compiler.ParseNewLines = true; compiler.RegisterCaseTags(); + compiler.RegisterTag("fix-ref", (doc, x) => new FixTypeNode(doc, x, replacementsRef)); compiler.RegisterTag("fix-type", (doc, x) => new FixTypeNode(doc, x, replacements)); compiler.RegisterTag("fix-array", (doc, x) => new FixArrayNode(doc, x));