chedder
Version:
290 lines • 11.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.delete_account = exports.call = exports.ONE_NEAR = exports.ONE_TGAS = exports.BN_ZERO = exports.send = exports.sendYoctos = exports.broadcast_tx_commit_actions = exports.broadcast_tx_commit_signed = exports.getValidators = exports.getGenesisConfig = exports.getStatus = exports.block = exports.latestBlock = exports.view = exports.viewRaw = exports.access_key = exports.queryAccount = exports.ytonb = exports.yton = exports.ntoy = exports.decodeJsonFromResult = exports.bufferToHex = exports.lastBlockHeightSeen = exports.lastBlockHashSeen = void 0;
const json_rpc_js_1 = require("./utils/json-rpc.js");
const naclUtil = __importStar(require("./tweetnacl/util.js"));
const valid_js_1 = require("./utils/valid.js");
const key_pair_js_1 = require("./utils/key-pair.js");
const serialize_js_1 = require("./utils/serialize.js");
const TX = __importStar(require("./transaction.js"));
const bs58 = __importStar(require("./utils/bs58.js"));
const sha256 = __importStar(require("./utils/sha256.js"));
const BN = require("bn.js");
//---------------------------
//-- NEAR PROTOCOL RPC CALLS
//---------------------------
//--helper fn
let last_block_hash;
function lastBlockHashSeen() {
return last_block_hash;
}
exports.lastBlockHashSeen = lastBlockHashSeen;
let last_block_height;
function lastBlockHeightSeen() {
return last_block_height;
}
exports.lastBlockHeightSeen = lastBlockHeightSeen;
//--helper fn
function bufferToHex(buffer) {
return [...new Uint8Array(buffer)]
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
exports.bufferToHex = bufferToHex;
//--helper fn
function decodeJsonFromResult(result) {
let text = naclUtil.encodeUTF8(result);
if (text == "null")
return ""; //I strongly prefer "" as alias to null (ORACLE style)
try {
return JSON.parse(text);
}
catch (ex) {
throw Error("ERR at JSON.parse: " + text);
}
}
exports.decodeJsonFromResult = decodeJsonFromResult;
/**
* convert nears expressed as a js-number with MAX 4 decimals into a yoctos-string
* @param n amount in near MAX 6 DECIMALS
*/
function ntoy(n) {
let by1e6 = Math.round(n * 1e6).toString(); // near * 1e6 - round
let yoctosText = by1e6 + "0".repeat(18); // mul by 1e18 => yoctos = near * 1e(6+18)
return yoctosText;
}
exports.ntoy = ntoy;
/**
* returns amount truncated to 4 decimal places
* @param yoctos amount expressed in yoctos
*/
function yton(yoctos) {
if (yoctos.indexOf(".") !== -1)
throw new Error("a yocto string can't have a decimal point: " + yoctos);
let negative = false;
if (yoctos.startsWith("-")) {
negative = true;
yoctos = yoctos.slice(1);
}
let padded = yoctos.padStart(25, "0"); //at least 0.xxx
let nearsText = padded.slice(0, -24) + "." + padded.slice(-24, -20); //add decimal point. Equivalent to near=yoctos/1e24 and truncate to 4 dec places
return Number(nearsText) * (negative ? -1 : 1);
}
exports.yton = yton;
function ytonb(yoctos) {
return yton(yoctos.toString());
}
exports.ytonb = ytonb;
/*
near.state example result
result: {
amount: "27101097909936818225912322116"
block_hash: "DoTW1Tpp3TpC9egBe1xFJbbEb6vYxbT33g9GHepiYL5a"
block_height: 20046823
code_hash: "11111111111111111111111111111111"
locked: "0"
storage_paid_at: 0
storage_usage: 2080
}
*/
async function queryAccount(accountId) {
try {
return await json_rpc_js_1.jsonRpcQuery("account/" + accountId);
}
catch (ex) {
//intercept and make err message better for "account not found"
const reason = ex.message.replace("while viewing", "");
throw Error(reason);
}
}
exports.queryAccount = queryAccount;
;
//-------------------------------
function access_key(accountId, publicKey) {
return json_rpc_js_1.jsonRpcQuery(`access_key/${accountId}/${publicKey}`);
}
exports.access_key = access_key;
;
//-------------------------------
function viewRaw(contractId, method, params) {
let encodedParams = undefined;
if (params)
encodedParams = bs58.encode(Buffer.from(JSON.stringify(params)));
return json_rpc_js_1.jsonRpcQuery("call/" + contractId + "/" + method, encodedParams);
}
exports.viewRaw = viewRaw;
async function view(contractId, method, params) {
const data = await viewRaw(contractId, method, params);
if (data && data.block_height)
last_block_height = data.block_height;
return decodeJsonFromResult(data.result);
}
exports.view = view;
function latestBlock() {
return json_rpc_js_1.jsonRpc('block', { finality: "optimistic" });
}
exports.latestBlock = latestBlock;
;
function block(blockId) {
return json_rpc_js_1.jsonRpc('block', { block_id: blockId });
}
exports.block = block;
;
function getStatus() {
return json_rpc_js_1.jsonRpc('status', [null]);
}
exports.getStatus = getStatus;
;
function getGenesisConfig() {
return json_rpc_js_1.jsonRpc('EXPERIMENTAL_genesis_config', [null]);
}
exports.getGenesisConfig = getGenesisConfig;
;
//---------------------------------
//---- VALIDATORS & STAKING POOLS -
//---------------------------------
function getValidators() {
return json_rpc_js_1.jsonRpc('validators', [null]);
}
exports.getValidators = getValidators;
;
//-------------------------------
function broadcast_tx_commit_signed(signedTransaction) {
const borshEncoded = signedTransaction.encode();
const b64Encoded = Buffer.from(borshEncoded).toString('base64');
return json_rpc_js_1.jsonRpc('broadcast_tx_commit', [b64Encoded]);
}
exports.broadcast_tx_commit_signed = broadcast_tx_commit_signed;
;
//-------------------------------
async function broadcast_tx_commit_actions(actions, signerId, receiver, privateKey) {
const keyPair = key_pair_js_1.KeyPairEd25519.fromString(privateKey);
const publicKey = keyPair.getPublicKey();
const accessKey = await access_key(signerId, publicKey.toString());
if (accessKey.permission !== 'FullAccess')
throw Error(`The key is not full access for account '${signerId}'`);
// converts a recent block hash into an array of bytes
// this hash was retrieved earlier when creating the accessKey (Line 26)
// this is required to prove the tx was recently constructed (within 24hrs)
last_block_hash = serialize_js_1.base_decode(accessKey.block_hash);
last_block_height = accessKey.block_height;
// each transaction requires a unique number or nonce
// this is created by taking the current nonce and incrementing it
const nonce = ++accessKey.nonce;
const transaction = TX.createTransaction(signerId, publicKey, receiver, nonce, actions, last_block_hash);
const serializedTx = serialize_js_1.serialize(TX.SCHEMA, transaction);
const serializedTxHash = new Uint8Array(sha256.hash(serializedTx));
const signature = keyPair.sign(serializedTxHash);
const signedTransaction = new TX.SignedTransaction({
transaction: transaction,
signature: new TX.Signature({
keyType: transaction.publicKey.keyType,
data: signature.signature
})
});
const result = await broadcast_tx_commit_signed(signedTransaction);
if (result.status && result.status.Failure) {
console.error(JSON.stringify(result));
console.error(getLogsAndErrorsFromReceipts(result));
throw Error(json_rpc_js_1.formatJSONErr(result.status.Failure));
}
if (result.status && result.status.SuccessValue == "") { //returned "void"
return undefined; //void
}
if (result.status && result.status.SuccessValue) { //some json result value, can by a string|true/false|a number
const sv = naclUtil.encodeUTF8(naclUtil.decodeBase64(result.status.SuccessValue));
//console.log("result.status.SuccessValue:", sv)
return JSON.parse(sv);
// if (sv == "false") { //bool functions returning false does not mean an error
// console.error(JSON.stringify(result))
// throw Error()
// }
}
console.error(JSON.stringify(result));
throw Error("!result.status Failure or SuccessValue");
//return result
}
exports.broadcast_tx_commit_actions = broadcast_tx_commit_actions;
//-------------------------------
function getLogsAndErrorsFromReceipts(txResult) {
let result = [];
result.push("Transaction failed.");
try {
for (let ro of txResult.receipts_outcome) {
//get logs
for (let logLine of ro.outcome.logs) {
result.push(logLine);
}
//check status.Failure
if (ro.outcome.status.Failure) {
result.push(json_rpc_js_1.formatJSONErr(ro.outcome.status.Failure));
}
}
}
catch (ex) {
result.push("internal error parsing result outcome");
}
finally {
return result.join('\n');
}
}
//-------------------------------
function sendYoctos(sender, receiver, amountYoctos, privateKey) {
const actions = [TX.transfer(new BN(amountYoctos))];
return broadcast_tx_commit_actions(actions, sender, receiver, privateKey);
}
exports.sendYoctos = sendYoctos;
//-------------------------------
function send(sender, receiver, amountNear, privateKey) {
if (isNaN(amountNear) || amountNear <= 0)
throw Error("invalid amount");
const actions = [TX.transfer(new BN(ntoy(amountNear)))];
return broadcast_tx_commit_actions(actions, sender, receiver, privateKey);
}
exports.send = send;
//-------------------------------
// export function stake(stakingPoolId: string, amountNear: number, sender: string, privateKey: string): Promise<any> {
// if (isNaN(amountNear) || amountNear <= 0) throw Error("invalid amount")
// const actions = [TX.stake(new BN(ntoy(amountNear)), publicKey???which one?)]
// return broadcast_tx_commit_actions(actions, sender, stakingPoolId, privateKey)
// }
//-------------------------------
//-- CALL CONTRACT METHOD -------
//-------------------------------
exports.BN_ZERO = new BN("0");
exports.ONE_TGAS = new BN("1" + "0".repeat(12));
exports.ONE_NEAR = new BN("1" + "0".repeat(24));
function call(contractId, method, params, sender, privateKey, TGas, attachedYoctos) {
return broadcast_tx_commit_actions([TX.functionCall(method, params, new BN(TGas.toString() + "0".repeat(12)), new BN(attachedYoctos || "0"))], sender, contractId, privateKey);
}
exports.call = call;
//-------------------------------
function delete_account(accountToDelete, privateKey, beneficiary) {
if (!valid_js_1.isValidAccountID(accountToDelete))
throw Error("Delete account: invalid account name to delete");
if (!valid_js_1.isValidAccountID(beneficiary))
throw Error("Delete account: invalid beneficiary account name");
const actions = [TX.deleteAccount(beneficiary)];
return broadcast_tx_commit_actions(actions, accountToDelete, accountToDelete, privateKey);
}
exports.delete_account = delete_account;
//# sourceMappingURL=near-rpc.js.map