js-rpcapi-mineplex
Version:
897 lines (863 loc) • 30.6 kB
JavaScript
if (typeof XMLHttpRequest == "undefined") XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
//main.js
if (typeof require == "undefined") require = require("buffer/").Buffer;
const defaultProvider = "http://127.0.0.1:8732",
library = {
bs58check: require('bs58check'),
sodium: require('sodium-universal'),
bip39: require('bip39'),
pbkdf2: require('pbkdf2'),
},
prefix = {
mp1: new Uint8Array([5, 183, 099]),
mp2: new Uint8Array([5, 183, 102]),
mp3: new Uint8Array([5, 183, 104]),
KT: new Uint8Array([2,90,121]),
edpk: new Uint8Array([13, 15, 37, 217]),
edsk2: new Uint8Array([13, 15, 58, 7]),
spsk: new Uint8Array([17, 162, 224, 201]),
p2sk: new Uint8Array([16,81,238,189]),
sppk: new Uint8Array([3, 254, 226, 86]),
p2pk: new Uint8Array([3, 178, 139, 127]),
edsk: new Uint8Array([43, 246, 78, 7]),
edsig: new Uint8Array([9, 245, 205, 134, 18]),
spsig1: new Uint8Array([13, 115, 101, 19, 63]),
p2sig: new Uint8Array([54, 240, 44, 52]),
sig: new Uint8Array([4, 130, 43]),
Net: new Uint8Array([87, 82, 0]),
nce: new Uint8Array([69, 220, 169]),
b: new Uint8Array([1,52]),
o: new Uint8Array([5, 116]),
Lo: new Uint8Array([133, 233]),
LLo: new Uint8Array([29, 159, 109]),
P: new Uint8Array([2, 170]),
Co: new Uint8Array([79, 179]),
id: new Uint8Array([153, 103]),
},
watermark = {
block: new Uint8Array([1]),
endorsement: new Uint8Array([2]),
generic: new Uint8Array([3]),
},
utility = {
totez: m => parseInt(m) / 1000000,
mutez: function (mp) {
let r = Number(Number(mp.toFixed(6) * 1000000).toFixed());
if (r > 4294967296) r = r.toString();
return r;
},
b58cencode: function (payload, prefix) {
const n = new Uint8Array(prefix.length + payload.length);
n.set(prefix);
n.set(payload, prefix.length);
return library.bs58check.encode(new Buffer(n, 'hex'));
},
b58cdecode: (enc, prefix) => library.bs58check.decode(enc).slice(prefix.length),
buf2hex: function (buffer) {
const byteArray = new Uint8Array(buffer), hexParts = [];
for (let i = 0; i < byteArray.length; i++) {
let hex = byteArray[i].toString(16);
let paddedHex = ('00' + hex).slice(-2);
hexParts.push(paddedHex);
}
return hexParts.join('');
},
hex2buf : function(hex){
return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
}));
},
hexNonce: function (length) {
var chars = '0123456789abcedf';
var hex = '';
while (length--) hex += chars[(Math.random() * 16) | 0];
return hex;
},
mergebuf : function(b1,b2){
var r = new Uint8Array(b1.length+b2.length);
r.set(b1);
r.set(b2, b1.length);
return r;
},
sexp2mic: function me(mi) {
mi = mi.replace(/(?:@[a-z_]+)|(?:#.*$)/mg, '')
.replace(/\s+/g, ' ')
.trim();
if (mi.charAt(0) === "(") mi = mi.slice(1, -1);
let pl = 0;
let sopen = false;
let escaped = false;
let ret = {
prim: '',
args: []
};
let val = "";
for (let i = 0; i < mi.length; i++) {
if (escaped) {
val += mi[i];
escaped = false;
continue;
}
else if ((i === (mi.length - 1) && sopen === false) || (mi[i] === " " && pl === 0 && sopen === false)) {
if (i === (mi.length - 1)) val += mi[i];
if (val) {
if (val === parseInt(val).toString()) {
if (!ret.prim) return {"int": val};
else ret.args.push({"int": val});
} else if (ret.prim) {
ret.args.push(me(val));
} else {
ret.prim = val;
}
val = '';
}
continue;
}
else if (mi[i] === '"' && sopen) {
sopen = false;
if (!ret.prim) return {'string': val};
else ret.args.push({'string': val});
val = '';
continue;
}
else if (mi[i] === '"' && !sopen && pl === 0) {
sopen = true;
continue;
}
else if (mi[i] === '\\') escaped = true;
else if (mi[i] === "(") pl++;
else if (mi[i] === ")") pl--;
val += mi[i];
}
return ret;
},
mic2arr: function me2(s) {
let ret = [];
if (s.hasOwnProperty("prim")) {
if (s.prim === "Pair") {
ret.push(me2(s.args[0]));
ret = ret.concat(me2(s.args[1]));
} else if (s.prim === "Elt") {
ret = {
key: me2(s.args[0]),
val: me2(s.args[1])
};
} else if (s.prim === "True") {
ret = true
} else if (s.prim === "False") {
ret = false;
}
} else {
if (Array.isArray(s)) {
let sc = s.length;
for (let i = 0; i < sc; i++) {
let n = me2(s[i]);
if (typeof n.key !== 'undefined') {
if (Array.isArray(ret)) {
ret = {
keys: [],
vals: [],
};
}
ret.keys.push(n.key);
ret.vals.push(n.val);
} else {
ret.push(n);
}
}
} else if (s.hasOwnProperty("string")) {
ret = s.string;
} else if (s.hasOwnProperty("int")) {
ret = parseInt(s.int);
} else {
ret = s;
}
}
return ret;
},
ml2mic: function me(mi) {
let ret = [], inseq = false, seq = '', val = '', pl = 0, bl = 0, sopen = false, escaped = false;
for (let i = 0; i < mi.length; i++) {
if (val === "}" || val === ";") {
val = "";
}
if (inseq) {
if (mi[i] === "}") {
bl--;
} else if (mi[i] === "{") {
bl++;
}
if (bl === 0) {
let st = me(val);
ret.push({
prim: seq.trim(),
args: [st]
});
val = '';
bl = 0;
inseq = false;
}
}
else if (mi[i] === "{") {
bl++;
seq = val;
val = '';
inseq = true;
continue;
}
else if (escaped) {
val += mi[i];
escaped = false;
continue;
}
else if ((i === (mi.length - 1) && sopen === false) || (mi[i] === ";" && pl === 0 && sopen == false)) {
if (i === (mi.length - 1)) val += mi[i];
if (val.trim() === "" || val.trim() === "}" || val.trim() === ";") {
val = "";
continue;
}
ret.push(mpapi.utility.ml2mpjson(val));
val = '';
continue;
}
else if (mi[i] === '"' && sopen) sopen = false;
else if (mi[i] === '"' && !sopen) sopen = true;
else if (mi[i] === '\\') escaped = true;
else if (mi[i] === "(") pl++;
else if (mi[i] === ")") pl--;
val += mi[i];
}
return ret;
},
formatMoney: function (n, c, d, t) {
var c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d === undefined ? "." : d,
t = t === undefined ? "," : t,
s = n < 0 ? "-" : "",
i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
},
//TODO: Add p256 and secp256k1 cryptographay
crypto = {
extractKeys : function(sk){
const pref = sk.substr(0,4);
switch(pref){
case "edsk":
if (sk.length == 98){
const out = new Buffer(20);
library.sodium.crypto_generichash(out, utility.b58cdecode(sk, prefix.edsk).slice(32))
return {
pk : utility.b58cencode(utility.b58cdecode(sk, prefix.edsk).slice(32), prefix.edpk),
pkh : utility.b58cencode(out, prefix.mp1),
sk : sk
};
} else if (sk.length == 54) { //seed
const seed = utility.b58cdecode(sk, prefix.edsk2);
const privateKey = new Buffer(library.sodium.crypto_sign_SECRETKEYBYTES);
const publicKey = new Buffer(library.sodium.crypto_sign_PUBLICKEYBYTES);
library.sodium.crypto_sign_seed_keypair(publicKey, privateKey, seed);
const out = new Buffer(20);
library.sodium.crypto_generichash(out, publicKey)
return {
sk: utility.b58cencode(privateKey, prefix.edsk),
pk: utility.b58cencode(publicKey, prefix.edpk),
pkh: utility.b58cencode(out, prefix.mp1),
};
}
break;
default:
return false;
break;
}
},
generateMnemonic: () => library.bip39.generateMnemonic(160),
validateMnemonic: (m) => library.bip39.validateMnemonic(m),
checkAddress: function (a) {
try {
utility.b58cdecode(a, prefix.mp1);
return true;
}
catch (e) {
return false;
}
},
generateKeysNoSeed: function () {
const privateKey = new Buffer(library.sodium.crypto_sign_SECRETKEYBYTES);
const publicKey = new Buffer(library.sodium.crypto_sign_PUBLICKEYBYTES);
library.sodium.crypto_sign_keypair(publicKey, privateKey);
const out = new Buffer(20);
library.sodium.crypto_generichash(out, publicKey)
return {
sk: utility.b58cencode(privateKey, prefix.edsk),
pk: utility.b58cencode(publicKey, prefix.edpk),
pkh: utility.b58cencode(out, prefix.mp1),
};
},
generateKeys: function (m, p) {
const seed = library.bip39.mnemonicToSeedSync(m, p).slice(0, 32);
const privateKey = new Buffer(library.sodium.crypto_sign_SECRETKEYBYTES);
const publicKey = new Buffer(library.sodium.crypto_sign_PUBLICKEYBYTES);
library.sodium.crypto_sign_seed_keypair(publicKey, privateKey, seed);
const out = new Buffer(20);
library.sodium.crypto_generichash(out, publicKey);
return {
mnemonic: m,
passphrase: p,
sk: utility.b58cencode(privateKey, prefix.edsk),
pk: utility.b58cencode(publicKey, prefix.edpk),
pkh: utility.b58cencode(out, prefix.mp1),
};
},
generateKeysFromSeedMulti: function (m, p, n) {
n /= (256 ^ 2);
const s = library.bip39.mnemonicToSeedSync(m, library.pbkdf2.pbkdf2Sync(p, n.toString(36).slice(2), 0, 32, 'sha512').toString()).slice(0, 32);
const kp = library.sodium.crypto_sign_seed_keypair(s);
return {
mnemonic: m,
passphrase: p,
n: n,
sk: utility.b58cencode(kp.privateKey, prefix.edsk),
pk: utility.b58cencode(kp.publicKey, prefix.edpk),
pkh: utility.b58cencode(library.sodium.crypto_generichash(20, kp.publicKey), prefix.mp1),
};
},
sign: function (bytes, sk, wm) {
var bb = utility.hex2buf(bytes);
if (typeof wm != 'undefined') bb = utility.mergebuf(wm, bb);
const out = new Buffer(32);
library.sodium.crypto_generichash(out, bb)
const sig = new Buffer(library.sodium.crypto_sign_BYTES);
library.sodium.crypto_sign_detached(sig, out, utility.b58cdecode(sk, prefix.edsk));
const edsig = utility.b58cencode(sig, prefix.edsig);
const sbytes = bytes + utility.buf2hex(sig);
return {
bytes: bytes,
sig: sig,
edsig: edsig,
sbytes: sbytes,
}
},
verify: function (bytes, sig, pk) {
return library.sodium.crypto_sign_verify_detached(sig, utility.hex2buf(bytes), utility.b58cdecode(pk, prefix.edpk));
},
};
node = {
activeProvider: defaultProvider,
debugMode: false,
async: true,
setDebugMode: function (t) {
node.debugMode = t;
},
setProvider: function (u) {
node.activeProvider = u;
},
resetProvider: function () {
node.activeProvider = defaultProvider;
},
query: function (e, o, t) {
if (typeof o === 'undefined') {
if (typeof t === 'undefined') {
t = "GET";
} else
o = {};
} else {
if (typeof t === 'undefined')
t = 'POST';
}
return new Promise(function (resolve, reject) {
const http = new XMLHttpRequest();
http.open(t, node.activeProvider + e, node.async);
http.onload = function () {
if (http.status === 200) {
if (node.debugMode)
console.log(http.status, e, o, http.responseText);
if (http.responseText) {
let r = JSON.parse(http.responseText);
if (r === null)
resolve(r);
else if (typeof r.error !== 'undefined') {
reject(r.error);
} else {
if (typeof r.ok !== 'undefined') r = r.ok;
resolve(r);
}
} else {
reject("Empty response returned");
}
} else {
if (node.debugMode)
console.log(http.status, e, o, http.responseText);
reject(http.responseText);
}
};
http.onerror = function () {
reject(http.statusText);
};
if (t == 'POST'){
http.setRequestHeader("Content-Type", "application/json");
http.send(JSON.stringify(o));
} else {
http.send();
}
});
}
},
rpc = {
account: function (keys, amount, spendable, delegatable, delegate, fee) {
const operation = {
"kind": "origination",
"fee": fee.toString(),
"managerPubkey": keys.pkh,
"balance": utility.mutez(amount).toString(),
"spendable": (typeof spendable !== "undefined" ? spendable : true),
"delegatable": (typeof delegatable !== "undefined" ? delegatable : true),
"delegate": (typeof delegate !== "undefined" ? delegate : keys.pkh),
};
return rpc.sendOperation(keys.pkh, operation, keys);
},
getPlexBalance: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/contracts/${mp1}/balance`).then(function (r) {
return r;
});
},
getMineBalance: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/contracts/${mp1}/mine_balance`).then(function (r) {
return r;
});
},
getConstants: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/constants`).then(function(c){
if (c) return c;
return false;
}).catch(function(){return false});
},
getDelegate: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/contracts/${mp1}/delegate`).then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getDelegateInfo: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates/${mp1}`).then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getMempoolOperations: function () {
return node.query('/chains/main/mempool/pending_operations').then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getDelegatedAddresses: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates/${mp1}/delegated_contracts`).then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getOwnStakingMineBalance: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates/${mp1}/balance`).then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getDelegatedBalance: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates/${mp1}/delegated_balance`).then(function(r){
if (r) return r;
return false;
}).catch(function(){return false});
},
getStakingMineBalance: function (mp1, block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates/${mp1}/staking_balance`).then(function(staking_balance){
return staking_balance;
}).catch(function(){return false});
},
getAllActiveDelegates: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}/context/delegates?active=true`).then(function(delegates){
return delegates
}).catch(function(){ return false });
},
getBlockBakingRights: function (block = 'head', maxPriority = 999) {
return node.query(`/chains/main/blocks/head/helpers/baking_rights?level=${block}&max_priority=${maxPriority}`).then(function(info){
return info
}).catch(function(){ return false });
},
getBlockEndorsingRights: function (block = 'head') {
return node.query(`/chains/main/blocks/head/helpers/endorsing_rights?level=${block}`).then(function(info){
return info
}).catch(function(){ return false });
},
getCurrentCycle: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}/metadata`).then(function(info){
return info.level.cycle
}).catch(function(){ return false });
},
getLevelsInCurrentCycle: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}/helpers/levels_in_current_cycle`).then(function(info){
return info
}).catch(function(){ return false });
},
getHead: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}`);
},
getHeadHash: function (block = 'head') {
return node.query(`/chains/main/blocks/${block}/hash`);
},
call: function (e, d) {
return node.query(e, d);
},
findOperation : function(hash, countFoundBlocks = 1){
let c = 1;
return new Promise(function(resolve, reject) {
var repeater = function(blockPrevNumber){
rpc.getHead(`head-${blockPrevNumber}`).then(function(h) {
c++;
outer:
for(var i = 3, found = false; i >= 0; i--){
for(var j = 0; j < h.operations[i].length; j++){
if (h.operations[i][j].hash == hash){
found = true;
break outer;
}
}
}
if (found) resolve(h.hash)
else {
if (c > countFoundBlocks) {
reject("Not found");
} else {
repeater(blockPrevNumber + 1);
}
}
});
}
repeater(0);
});
},
awaitOperation : function(hash, interval = 30, timeout = 180){
if (timeout <= 0) throw "Timeout must be more than 0";
if (interval <= 0) throw "Interval must be more than 0";
var at = Math.ceil(timeout/interval) + 1, c = 0;;
return new Promise(function(resolve, reject){
var repeater = function(){
rpc.getHead().then(function(h) {
c++;
outer:
for(var i = 3, found = false; i >= 0; i--){
for(var j = 0; j < h.operations[i].length; j++){
if (h.operations[i][j].hash == hash){
found = true;
break outer;
}
}
}
if (found) resolve(h.hash)
else {
if (c >= at) {
reject("Timeout");
} else {
setTimeout(repeater, interval);
}
}
});
}
repeater();
});
},
buildOperation: function (from, operation, keys) {
var counter, opOb;
var promises = [], requiresReveal=false;
promises.push(node.query('/chains/main/blocks/head/header'));
let ops;
if (Array.isArray(operation)) {
ops = operation;
} else {
ops = [operation];
}
for(let i = 0; i < ops.length; i++){
if (['transaction','mine_transaction','origination','delegation'].indexOf(ops[i].kind) >= 0){
requiresReveal = true;
promises.push(node.query('/chains/main/blocks/head/context/contracts/' + from + '/counter'));
promises.push(node.query('/chains/main/blocks/head/context/contracts/' + from + '/manager_key'));
break;
}
}
return Promise.all(promises).then(function (f) {
head = f[0];
if (requiresReveal && f[2] === null){
ops.unshift({
kind : "reveal",
fee : 0,
gas_limit: utility.mutez(0.010307).toString(),
public_key : keys.pk,
source : keys.pkh,
});
}
counter = parseInt(f[1]) + 1;
for(let i = 0; i < ops.length; i++){
if (['proposals','ballot','transaction','mine_transaction','origination','delegation'].indexOf(ops[i].kind) >= 0){
if (typeof ops[i].source == 'undefined') ops[i].source = from;
}
if (['reveal', 'transaction','mine_transaction','origination','delegation'].indexOf(ops[i].kind) >= 0) {
if (typeof ops[i].gas_limit == 'undefined') ops[i].gas_limit = "0";
if (typeof ops[i].storage_limit == 'undefined') ops[i].storage_limit = "0";
ops[i].counter = (counter++).toString();
ops[i].fee = ops[i].fee.toString();
ops[i].gas_limit = ops[i].gas_limit.toString();
ops[i].storage_limit = ops[i].storage_limit.toString();
ops[i].counter = ops[i].counter.toString();
}
}
opOb = {
"branch": head.hash,
"contents": ops,
}
return node.query('/chains/'+head.chain_id+'/blocks/'+head.hash+'/helpers/forge/operations', opOb).then((opbytes) => {
return {
opbytes,
opOb
}
});
});
},
signOperation: function (opbytes, keys) {
var sopbytes;
var signed = crypto.sign(opbytes, keys.sk, watermark.generic);
sopbytes = signed.sbytes;
const out = new Buffer(32);
library.sodium.crypto_generichash(out, utility.hex2buf(sopbytes))
var oh = utility.b58cencode(out, prefix.o);
return { sopbytes, signature: signed.edsig };
},
validateOperation: function (opOb) {
return node.query('/chains/main/blocks/head/header').then((head) => {
return node.query('/chains/'+head.chain_id+'/blocks/'+head.hash+'/helpers/preapply/operations', [opOb]).then((returnedContracts) => {
var errors = [], opResponse = [];
if (!Array.isArray(returnedContracts)) throw {error: "RPC Fail", errors:[]};
for(var i = 0; i < returnedContracts.length; i++){
for(var j = 0; j < returnedContracts[i].contents.length; j++){
opResponse.push(returnedContracts[i].contents[j]);
if (typeof returnedContracts[i].contents[j].metadata.operation_result != 'undefined' && returnedContracts[i].contents[j].metadata.operation_result.status == "failed")
errors = errors.concat(returnedContracts[i].contents[j].metadata.operation_result.errors);
}
}
return { opResponse, errors };
});
});
},
broadcastOperation: function (sopbytes) {
return node.query('/injection/operation', sopbytes).then(function (f) {
return {
hash : f,
};
});
},
sendOperation: function (from, operation, keys) {
return rpc.buildOperation(from, operation, keys).then(({ opbytes, opOb }) => {
var { sopbytes, signature } = rpc.signOperation(opbytes, keys);
opOb.protocol = "Pt4xzupCszbuxgMSWE2WnReY4aryz1Te3pGN78YEkhjss7C1AMK";
opOb.signature = signature;
return rpc.validateOperation(opOb).then(({ errors, opResponse }) => {
if (errors.length) throw {error: "Operation Failed", errors:errors};
return rpc.broadcastOperation(sopbytes).then(({ hash }) => {
return {
hash,
opResponse,
}
})
})
})
},
plex_transfer: function (from, keys, to, amount, fee) {
var operation = {
"kind": "transaction",
"fee" : utility.mutez(fee).toString(),
"gas_limit": utility.mutez(0.010307).toString(),
"storage_limit": utility.mutez(0.000257).toString(),
"amount": utility.mutez(amount).toString(),
"destination": to
};
return rpc.sendOperation(from, operation, keys);
},
mine_transfer: function (from, keys, to, amount, fee) {
var operation = {
"kind": "mine_transaction",
"fee" : utility.mutez(fee).toString(),
"gas_limit": utility.mutez(0.010307).toString(),
"storage_limit": utility.mutez(0.000257).toString(),
"amount": utility.mutez(amount).toString(),
"destination": to
};
return rpc.sendOperation(from, operation, keys);
},
getPricePlexForOneMine: async (total_stake = 0, block = 'head') => {
const constants = await rpc.getConstants(block);
if (!constants)
throw new Error('error load constants');
const count_plex_per_block =
constants.endorsers_per_block * (
utility.totez(constants.baking_reward_per_endorsement[0]) +
utility.totez(constants.endorsement_reward[0])
);
// const delegates = await rpc.getAllActiveDelegates()
// const mine_balances = total_stake || await delegates.reduce(async (acc, delegate) =>
// await acc + utility.totez(await rpc.getStakingMineBalance(delegate)),
// 0
// );
return ((20 / 100) * (total_stake / count_plex_per_block)) / 43200;
},
getPriceMineForOnePlex: async (total_stake = 0, block = 'head') => {
return await rpc.getPricePlexForOneMine(total_stake, block) / 100;
},
activate: function (keys, pkh, secret) {
var operation = {
"kind": "activate_account",
"pkh" : pkh,
"secret": secret,
};
return rpc.sendOperation(keys.pkh, operation, keys);
},
originate: function (from, keys, amount, code, init, spendable, delegatable, delegate, fee) {
var _code = utility.ml2mic(code), script = {
code: _code,
storage: utility.sexp2mic(init)
}, operation = {
"kind": "origination",
"fee" : fee.toString(),
"gas_limit": "10000",
"storage_limit": "10000",
"managerPubkey": keys.pkh,
"balance": utility.mutez(amount).toString(),
"spendable": (typeof spendable != "undefined" ? spendable : false),
"delegatable": (typeof delegatable != "undefined" ? delegatable : false),
"delegate": (typeof delegate != "undefined" && delegate ? delegate : keys.pkh),
"script": script,
};
return rpc.sendOperation(from, operation, keys);
},
setDelegate(from, keys, delegate, fee) {
var operation = {
"kind": "delegation",
"fee" : utility.mutez(fee).toString(),
"gas_limit": utility.mutez(0.010307).toString(),
"delegate": delegate ? delegate : undefined,
};
return rpc.sendOperation(from, operation, keys);
},
registerDelegate(keys, fee) {
var operation = {
"kind": "delegation",
"fee" : fee.toString(),
"delegate": keys.pkh,
};
return rpc.sendOperation(keys.pkh, operation, keys);
},
typecheckCode(code) {
var _code = utility.ml2mic(code);
return node.query("/chains/main/blocks/head/helpers/scripts/typecheck_code", {program : _code, gas : "10000"});
},
typecheckData(data, type) {
var check = {
data: utility.sexp2mic(data),
type: utility.sexp2mic(type),
gas:"400000"
};
return node.query("/chains/main/blocks/head/helpers/scripts/typecheck_data", check);
},
hashData(data, type) {
var check = {
data: utility.sexp2mic(data),
type: utility.sexp2mic(type),
gas:"400000"
};
return node.query("/chains/main/blocks/head/helpers/scripts/hash_data", check);
},
runCode(from, code, amount, input, storage, trace) {
var ep = (trace ? 'trace_code' : 'run_code');
return node.query("/chains/main/blocks/head/helpers/scripts/" + ep, {
contract: from,
script: utility.ml2mic(code),
amount: utility.mutez(amount).toString(),
input: utility.sexp2mic(input),
storage: utility.sexp2mic(storage),
});
}
},
contract = {
hash : function(operationHash, ind){
var ob = utility.b58cdecode(operationHash, prefix.o), tt = [], i=0;
for(; i<ob.length; i++){
tt.push(ob[i]);
}
tt = tt.concat([
(ind & 0xff000000) >> 24,
(ind & 0x00ff0000) >> 16,
(ind & 0x0000ff00) >> 8,
(ind & 0x000000ff)
]);
return utility.b58cencode(library.sodium.crypto_generichash(20, new Uint8Array(tt)), prefix.MP);
},
originate: function (keys, amount, code, init, spendable, delegatable, delegate, fee) {
return rpc.originate(keys, amount, code, init, spendable, delegatable, delegate, fee);
},
storage: function (contract) {
return new Promise(function (resolve, reject) {
mpapi.node.query("/chains/main/blocks/head/context/contracts/" + contract +
"/storage").then(function (r) {
resolve(r);
}).catch(function (e) {
reject(e);
});
});
},
load: function (contract) {
return mpapi.node.query("/chains/main/blocks/head/context/contracts/" + contract);
},
watch: function (cc, timeout, cb) {
let storage = [];
const ct = function () {
contract.storage(cc).then(function (r) {
if (JSON.stringify(storage) != JSON.stringify(r)) {
storage = r;
cb(storage);
}
});
};
ct();
return setInterval(ct, timeout * 1000);
},
send: function (contract, from, keys, amount, parameter, fee) {
return mpapi.rpc.sendOperation(from, {
"kind": "transaction",
"fee" : fee.toString(),
"gas_limit": "200",
"amount": utility.mutez(amount).toString(),
"destination": contract,
"parameters": mpapi.utility.sexp2mic(parameter)
}, keys);
}
};
//Legacy commands
utility.ml2mpjson = utility.sexp2mic;
utility.mpjson2arr = utility.mic2arr;
utility.mlraw2json = utility.ml2mic;
utility.mintomp = utility.totez;
utility.mptomin = utility.mutez;
prefix.MP = new Uint8Array([2,90,121]);
//Expose library
const mpapi = {
library: library,
prefix: prefix,
watermark: watermark,
utility: utility,
crypto: crypto,
node: node,
rpc: rpc,
contract: contract,
};
module.exports = {
defaultProvider,
mpapi: mpapi,
};