@cityofzion/neon-nep5
Version:
Neon-NEP5 Module
183 lines • 7.59 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { logging, rpc, sc, u } from "@cityofzion/neon-core";
import * as abi from "./abi";
const log = logging.default("nep5");
/**
* Workaround for contracts such as SWTH returning Integer instead of ByteArray.
*/
function NumberParser(item) {
switch (item.type) {
case "Integer":
return new u.Fixed8(item.value).div(100000000);
case "ByteArray":
return u.Fixed8.fromReverseHex(item.value);
default:
throw new Error(`Received invalid type ${item.type}`);
}
}
const parseTokenInfo = rpc.buildParser(rpc.StringParser, rpc.StringParser, rpc.IntegerParser, NumberParser);
const parseTokenInfoAndBalance = rpc.buildParser(rpc.StringParser, rpc.StringParser, rpc.IntegerParser, NumberParser, NumberParser);
/**
* Get the balance of a single token for a single address.
* @param url Url of the NEO node to query.
* @param scriptHash ScriptHash of the NEP5 contract.
* @param address the Address to query for the balance.
*/
export function getTokenBalance(url, scriptHash, address) {
return __awaiter(this, void 0, void 0, function* () {
const client = typeof url === "string" ? new rpc.RPCClient(url) : url;
const sb = new sc.ScriptBuilder();
abi.decimals(scriptHash)(sb);
abi.balanceOf(scriptHash, address)(sb);
const script = sb.str;
try {
const res = yield client.invokeScript(script);
const decimals = rpc.IntegerParser(res.stack[0]);
return NumberParser(res.stack[1]).mul(Math.pow(10, 8 - decimals));
}
catch (err) {
log.error(`getTokenBalance failed with : ${err.message}`);
throw err;
}
});
}
/**
* Get token balances for an address.
* @param url URL of the NEO node to query.
* @param scriptHashArray Array of contract scriptHashes.
* @param address Address to query for balance of tokens.
*/
export function getTokenBalances(url, scriptHashArray, address) {
return __awaiter(this, void 0, void 0, function* () {
const sb = new sc.ScriptBuilder();
scriptHashArray.forEach((scriptHash) => {
abi.symbol(scriptHash)(sb);
abi.decimals(scriptHash)(sb);
abi.balanceOf(scriptHash, address)(sb);
});
const client = typeof url === "string" ? new rpc.RPCClient(url) : url;
const res = yield client.invokeScript(sb.str);
const tokenList = {};
if (!res || !res.stack || res.stack.length !== 3 * scriptHashArray.length) {
throw new Error("Stack returned was invalid");
}
try {
for (let i = 0; i < res.stack.length; i += 3) {
try {
const symbol = rpc.StringParser(res.stack[i]);
const decimals = rpc.IntegerParser(res.stack[i + 1]);
tokenList[symbol] = NumberParser(res.stack[i + 2]).mul(Math.pow(10, 8 - decimals));
}
catch (e) {
log.error(`single call in getTokenBalances failed with : ${e.message}`);
throw e;
}
}
return tokenList;
}
catch (err) {
log.error(`getTokenBalances failed with : ${err.message}`);
throw err;
}
});
}
/**
* Retrieves the complete information about a token.
* @param url RPC Node url to query.
* @param scriptHash ScriptHash of the NEP5 contract.
* @param address Optional address to query the balance for. If provided, the returned object will include the balance property.
*/
export function getToken(url, scriptHash, address) {
return __awaiter(this, void 0, void 0, function* () {
const parser = address ? parseTokenInfoAndBalance : parseTokenInfo;
const sb = new sc.ScriptBuilder();
abi.name(scriptHash)(sb);
abi.symbol(scriptHash)(sb);
abi.decimals(scriptHash)(sb);
abi.totalSupply(scriptHash)(sb);
if (address) {
abi.balanceOf(scriptHash, address)(sb);
}
const script = sb.str;
try {
const client = typeof url === "string" ? new rpc.RPCClient(url) : url;
const res = parser(yield client.invokeScript(script));
const result = {
name: res[0],
symbol: res[1],
decimals: res[2],
totalSupply: res[3].mul(Math.pow(10, 8 - res[2])).toNumber(),
};
if (address) {
result.balance = res[4].mul(Math.pow(10, 8 - res[2]));
}
return result;
}
catch (err) {
log.error(`getToken failed with : ${err.message}`);
throw err;
}
});
}
/**
* Retrieves the complete information about a list of tokens.
* @param url RPC Node url to query.
* @param scriptHashArray Array of NEP5 contract scriptHashes.
* @param address Optional address to query the balance for. If provided, the returned object will include the balance property.
*/
export function getTokens(url, scriptHashArray, address) {
return __awaiter(this, void 0, void 0, function* () {
try {
const sb = new sc.ScriptBuilder();
scriptHashArray.forEach((scriptHash) => {
abi.name(scriptHash)(sb);
abi.symbol(scriptHash)(sb);
abi.decimals(scriptHash)(sb);
abi.totalSupply(scriptHash)(sb);
if (address) {
abi.balanceOf(scriptHash, address)(sb);
}
});
const client = typeof url === "string" ? new rpc.RPCClient(url) : url;
const res = yield client.invokeScript(sb.str);
const result = [];
const step = address ? 5 : 4;
for (let i = 0; i < res.stack.length; i += step) {
const name = rpc.StringParser(res.stack[i]);
const symbol = rpc.StringParser(res.stack[i + 1]);
const decimals = rpc.IntegerParser(res.stack[i + 2]);
const totalSupply = NumberParser(res.stack[i + 3])
.mul(Math.pow(10, 8 - decimals))
.toNumber();
const balance = address
? NumberParser(res.stack[i + 4]).mul(Math.pow(10, 8 - decimals))
: undefined;
const obj = {
name,
symbol,
decimals,
totalSupply,
balance,
};
if (!obj.balance) {
delete obj.balance;
}
result.push(obj);
}
return result;
}
catch (err) {
log.error(`getTokens failed with : ${err.message}`);
throw err;
}
});
}
//# sourceMappingURL=main.js.map