You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@marigold-dev/deku-toolkit

Package Overview
Dependencies
Maintainers
4
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@marigold-dev/deku-toolkit - npm Package Compare versions

Comparing version
0.1.8
to
0.1.9
+5
-7
lib/core/block.d.ts

@@ -8,9 +8,7 @@ import { Level as LevelType } from "./level";

signature: string;
block: {
author: Address;
level: LevelType;
previous: string;
payload: Array<string>;
tezos_operations: Array<string>;
};
author: Address;
level: LevelType;
previous: string;
payload: string;
tezos_operations: Array<string>;
};

@@ -17,0 +15,0 @@ declare const _default: {

@@ -5,35 +5,6 @@ "use strict";

const ofDTO = (dto) => {
const key_str = dto.at("key").as_string();
const signature_str = dto.at("signature").as_string();
const block = dto.at("block");
const author_str = block.at("author").as_string();
const level = level_1.default.ofDTO(block.at("level"));
const previous_str = block.at("previous").as_string();
const payload_json = block.at("payload").as_string_array();
const tezos_operations = block.at("tezos_operations").as_string_array();
if (key_str === null)
return null;
if (signature_str === null)
return null;
if (author_str === null)
return null;
if (level === null)
return null;
if (previous_str === null)
return null;
if (payload_json === null)
return null;
if (tezos_operations === null)
return null;
return {
key: key_str,
signature: signature_str,
block: {
author: author_str,
level,
previous: previous_str,
payload: payload_json,
tezos_operations
}
};
const [block_str, payload] = dto.as_json();
const block = JSON.parse(block_str);
const level = level_1.default.ofDTO(block.level);
return Object.assign(Object.assign({}, block), { level, payload });
};

@@ -40,0 +11,0 @@ exports.default = {

@@ -1,1 +0,1 @@

{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/core/block.ts"],"names":[],"mappings":";;AAAA,mCAAmD;AAiBnD,MAAM,KAAK,GAAG,CAAC,GAAc,EAAgB,EAAE;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC;IAC1C,MAAM,aAAa,GAAG,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,SAAS,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;IAClD,MAAM,KAAK,GAAG,eAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;IACtD,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,eAAe,EAAE,CAAC;IAC3D,MAAM,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,eAAe,EAAE,CAAC;IAExE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,gBAAgB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE3C,OAAO;QACH,GAAG,EAAE,OAAO;QACZ,SAAS,EAAE,aAAa;QACxB,KAAK,EAAE;YACH,MAAM,EAAE,UAAU;YAClB,KAAK;YACL,QAAQ,EAAE,YAAY;YACtB,OAAO,EAAE,YAAY;YACrB,gBAAgB;SACnB;KACJ,CAAA;AACL,CAAC,CAAA;AAED,kBAAe;IACX,KAAK;CACR,CAAA"}
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/core/block.ts"],"names":[],"mappings":";;AAAA,mCAAmD;AAenD,MAAM,KAAK,GAAG,CAAC,GAAc,EAAgB,EAAE;IAC3C,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAAa,GAAG,CAAC,OAAO,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,eAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,uCAAW,KAAK,KAAE,KAAK,EAAE,OAAO,IAAC;AACrC,CAAC,CAAA;AAED,kBAAe;IACX,KAAK;CACR,CAAA"}
+337
-1078

@@ -1,1101 +0,360 @@

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@taquito/taquito'), require('blakejs'), require('bs58check')) :
typeof define === 'function' && define.amd ? define(['exports', '@taquito/taquito', 'blakejs', 'bs58check'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.dekuToolkit = {}, global.taquito, global.blake, global.bs58check));
})(this, (function (exports, taquito, blake, bs58check) { 'use strict';
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
"use strict";
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fromMemorySigner = exports.fromCustomSigner = exports.fromBeaconSigner = exports.DekuToolkit = void 0;
const taquito_1 = require("@taquito/taquito");
const consensus_1 = require("./contracts/consensus");
const nonce_1 = require("./core/nonce");
const operation_1 = require("./core/operation");
const ticket_id_1 = require("./core/ticket-id");
const network_1 = require("./network");
const hash_1 = require("./utils/hash");
const json_1 = require("./utils/json");
const urlJoin_1 = require("./utils/urlJoin");
class DekuToolkit {
constructor(setting) {
this.endpoints = (0, network_1.makeEndpoints)(setting.dekuRpc);
this._dekuSigner = setting.dekuSigner;
this.onBlockCallback = () => { return; }; // The callback is not provided by the user in the constructor
// FIXME: not working properly
//this.initializeStream(setting.dekuRpc)
// .catch(err => console.error(`error: ${err}`));
this.pendingOperations = {};
}
var blake__namespace = /*#__PURE__*/_interopNamespace(blake);
var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(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());
initializeStream(dekuRpc) {
return __awaiter(this, void 0, void 0, function* () {
const streamUri = (0, urlJoin_1.default)(dekuRpc, "/api/v1/chain/blocks/monitor");
const response = yield fetch(streamUri);
const body = response.body;
if (!body)
return null;
const reader = body.getReader();
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = yield reader.read();
if (done)
break;
const decoder = new TextDecoder("utf-8");
const json = json_1.default.of(JSON.parse(decoder.decode(value)));
const block_hash = json.as_string();
// Add parsing for a block hash
if (block_hash === null)
return null;
const block = yield this.getBlockByHash(block_hash);
this.handleBlock(block);
return null;
}
return;
});
}
class Consensus {
constructor(contract) {
this._contract = contract;
}
/**
* Retrieve the level of the chain from the consensus contract
* @returns the level of the chain
*/
level() {
return __awaiter(this, void 0, void 0, function* () {
const contract = yield this._contract();
const storage = yield contract.storage();
return storage.root_hash.current_block_level.c[0];
});
}
/**
* Returns the list of tezos address of all validators known by the consensus
* @returns a list of tezos address
*/
validators() {
return __awaiter(this, void 0, void 0, function* () {
const contract = yield this._contract();
const storage = yield contract.storage();
return storage.root_hash.current_validators;
});
}
/**
* Returns the address of the consensus contract
* @returns tezos address as string
*/
address() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._contract()).address;
});
}
/**
* Sets the deku signer
* @param wallet the wallet you want to use
* @returns deku toolkit
*/
setDekuSigner(signer) {
this._dekuSigner = signer;
return this;
}
/**
* Creates a new once
* @returns random number between 0 and 2**32
* Utils function that check if the deku signer is setup
* @returns void if the signer is set, otherwise the promise is rejected
*/
const rand = () => {
const maxInt32 = 2147483647;
const nonce = Math.floor(Math.random() * maxInt32);
return nonce;
};
const toDTO$3 = (nonce) => {
return nonce.toString();
};
const ofDTO$5 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
assertTzWallet() {
if (!this._dekuSigner) {
throw new Error("Tezos wallet required, see setTzWallet");
}
catch (_a) {
return null;
}
};
var Nonce = {
rand,
toDTO: toDTO$3,
ofDTO: ofDTO$5
};
const toDTO$2 = (amount) => {
return amount.toString();
};
const ofDTO$4 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
}
catch (_a) {
return null;
}
};
var Amount = {
toDTO: toDTO$2,
ofDTO: ofDTO$4
};
const toDTO$1 = (level) => {
return level.toString();
};
const ofDTO$3 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
}
catch (_a) {
return null;
}
};
var Level = {
toDTO: toDTO$1,
ofDTO: ofDTO$3
};
// Please, tell me there is a better JSON library that this one
class JSONValue {
constructor() {
this._json = null;
}
static of(json) {
const value = new JSONValue();
value._json = json;
return value;
}
null() {
return JSONValue.of(null);
}
at(field) {
if (this._json === null)
return this.null();
if (typeof this._json !== "object")
return this.null();
if (Array.isArray(this._json))
return this.null();
if (!(field in this._json))
return this.null();
const value = this._json[field];
return JSONValue.of(value);
}
as_string() {
if (this._json === null)
return null;
if (typeof this._json !== "string")
return null;
return this._json;
}
as_int() {
if (this._json === null)
return null;
if (typeof this._json !== "number")
return null;
return this._json;
}
as_array() {
if (this._json === null)
return null;
if (!Array.isArray(this._json))
return null;
return this._json.map(json => JSONValue.of(json));
}
as_string_array() {
if (this._json === null)
return null;
if (!Array.isArray(this._json))
return null;
const array = this._json.flatMap(elt => {
const element = JSONValue.of(elt).as_string();
if (element === null)
return [];
return [element];
});
return array.length === this._json.length ? array : null; // If the size of doesn't match it means there wasn't only strings in the array
}
as_json() {
return this._json;
}
return this._dekuSigner;
}
const createTransaction = (level, nonce, source, receiver, amount, ticketer, data) => {
const a = {
level,
nonce,
source,
type: "Transaction",
content: {
receiver,
ticket_id: ["Ticket_id", {
ticketer: ticketer,
data
}],
amount
}
};
return a;
};
const createVmOperation = (level, nonce, source, payload) => {
return {
level,
nonce,
source,
type: "Vm",
content: {
payload
}
};
};
const createWithdraw = (level, nonce, source, owner, amount, ticketer, data) => {
const a = {
level,
nonce,
source,
type: "Withdraw",
content: {
owner,
ticket_id: ["Ticket_id", {
ticketer: ticketer,
data
}],
amount
}
};
return a;
};
const toDTO = (operation) => {
const { level, nonce, source, type, content } = operation;
switch (type) {
case "Transaction": {
const { receiver, amount, ticket_id } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Ticket_transfer", { receiver, ticket_id, amount: Amount.toDTO(amount) }]
};
return JSONValue.of(dto);
}
case "Withdraw": {
const { owner, amount, ticket_id } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Tezos_withdraw", { owner: ["Implicit", owner], ticket_id, amount: Amount.toDTO(amount) }]
};
return JSONValue.of(dto);
}
case "Vm": {
const { payload } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Vm_transaction", { operation: payload, tickets: [] }]
};
return JSONValue.of(dto);
}
}
};
const signedToDTO = (signedOperation) => {
const { key, signature, operation } = signedOperation;
const op = toDTO(operation).as_json();
return {
key,
signature,
operation: op
};
};
// FIXME to update with ticket ids and withdraws
const ofDTO$2 = (json) => {
const level_json = json.at("level");
const nonce_json = json.at("nonce");
const source = json.at("source").as_string();
const content_array = json.at("content").as_array();
if (content_array === null || source === null)
return null;
const [type_str, payload] = content_array;
const type = type_str.as_string();
if (type === null)
return null;
const level = Level.ofDTO(level_json);
if (level === null)
return null;
const nonce = Nonce.ofDTO(nonce_json);
if (nonce === null)
return null;
switch (type) {
case "Transaction": {
const amount_json = payload.at("amount");
const receiver_str = payload.at("receiver").as_string();
if (receiver_str === null)
return null;
const amount = Amount.ofDTO(amount_json);
if (amount === null)
return null;
return createTransaction(level, nonce, source, receiver_str, amount, "error", "error");
}
case "Vm_transaction": {
const operation = payload.at("operation").as_string();
if (operation === null)
return null;
return createVmOperation(level, nonce, source, operation);
}
default:
return null;
}
};
var Operation = {
createTransaction,
createVmOperation,
createWithdraw,
toDTO,
ofDTO: ofDTO$2,
signedToDTO
};
const createTicketID = (ticketer, data) => {
return {
ticketer,
data
};
};
var TicketID = {
createTicketID
};
const ofDTO$1 = (dto) => {
const key_str = dto.at("key").as_string();
const signature_str = dto.at("signature").as_string();
const block = dto.at("block");
const author_str = block.at("author").as_string();
const level = Level.ofDTO(block.at("level"));
const previous_str = block.at("previous").as_string();
const payload_json = block.at("payload").as_string_array();
const tezos_operations = block.at("tezos_operations").as_string_array();
if (key_str === null)
return null;
if (signature_str === null)
return null;
if (author_str === null)
return null;
if (level === null)
return null;
if (previous_str === null)
return null;
if (payload_json === null)
return null;
if (tezos_operations === null)
return null;
return {
key: key_str,
signature: signature_str,
block: {
author: author_str,
level,
previous: previous_str,
payload: payload_json,
tezos_operations
}
};
};
var Block = {
ofDTO: ofDTO$1
};
const PREFIX = {
"Do": new Uint8Array([86, 124]),
"Db": new Uint8Array([85, 22]),
};
/**
* Hash the string representation of the payload, returns the b58 reprensentation starting with the given prefix
* @param prefix the prefix of your hash
* Sets ther tezos rpc node
* @param rpc the url of the tezos rpc,
* @returns
*/
const toB58Hash = (prefix) => (payload) => {
const payloadStr = JSON.stringify(payload.as_json());
const blakeHash = blake__namespace.blake2b(payloadStr, undefined, 32);
const tmp = new Uint8Array(prefix.length + blakeHash.length);
tmp.set(prefix);
tmp.set(blakeHash, prefix.length);
const b58 = bs58check__namespace.encode(Buffer.from(tmp));
return b58;
};
const fromB58Hash = (x) => {
const y = bs58check__namespace.decode(x);
const tmp = new Uint8Array(y.buffer).slice(0, 32 + 2);
return "0x" + Buffer.from(tmp.slice(2)).toString("hex");
};
const createOperationHash = toB58Hash(PREFIX.Do);
const hashOperation = (operation) => {
const json = Operation.toDTO(operation);
return createOperationHash(json);
};
const ofDTO = (json) => {
console.log(json.as_json());
const withdrawal_handles_hash = json.at("withdrawal_handles_hash").as_string();
const handle = json.at("handle");
const proof = json.at("proof").as_array();
if (proof === null)
return null;
const proof2 = proof.flatMap((x) => {
const y = x.as_array();
if (y === null) {
throw "nope";
}
return [y];
}).flat();
console.log(proof2);
const proof3 = proof2.flatMap((x) => {
const y = x.as_string();
if (y === null) {
console.log(y);
throw "Nope";
}
return [fromB58Hash(y)];
setTezosRpc(rpc) {
const tezos = new taquito_1.TezosToolkit(rpc);
// get the consensus and discovery address
const uri = this.endpoints["GET_CHAIN_INFO"];
const consensusContract = () => (0, network_1.get)(uri).then(({ consensus }) => tezos.contract.at(consensus));
// const discoveryContract = () => get(uri).then(({ discovery }) => tezos.contract.at(discovery));
this._consensus = new consensus_1.default(consensusContract);
// this._discovery = new Discovery(discoveryContract);
return this;
}
/**
* Sets the callback to call when a block is received
* @param callback the callback to be called when a new block arrived to the client
* Returns the deku updated toolkit
*/
onBlock(callback) {
this.onBlockCallback = callback;
return this;
}
/**
* Access the consensus contract to interact with it
* @return the consensus contract
*/
get consensus() {
return this._consensus;
}
/**
* Access the discovery contract to interact with it
* @return the consensus contract
*/
get discovery() {
throw "Not implemented";
// return this._discovery;
}
/**
* Returns the address of the consensus and discovery used by the deku chain
* @returns the consensus and discovery addresses
*/
info() {
return __awaiter(this, void 0, void 0, function* () {
const info = yield (0, network_1.get)(this.endpoints["GET_CHAIN_INFO"]);
return info;
});
const id = handle.at("id").as_int();
const owner = handle.at("owner").as_array();
const ticket_id = handle.at("ticket_id").as_array();
if (ticket_id === null)
return null;
const ticketer = ticket_id[1].at("ticketer").as_string();
const data = ticket_id[1].at("data").as_string();
const hash = handle.at("hash").as_string();
const amount = handle.at("amount").as_string();
if (withdrawal_handles_hash === null)
return null;
console.log("a");
if (proof === null)
return null;
console.log("b");
if (id === null)
return null;
console.log("c");
if (owner === null)
return null;
console.log("d");
if (ticketer === null)
return null;
console.log("e");
if (data === null)
return null;
console.log("f");
if (hash === null)
return null;
console.log("g");
if (amount === null)
return null;
console.log("h");
const address = owner[1].as_string();
if (address === null)
return null;
console.log("i");
return {
withdrawal_handles_hash: fromB58Hash(withdrawal_handles_hash),
handle: {
id,
owner: address,
ticket_id: {
ticketer,
data
},
hash,
amount
},
proof: proof3
};
};
var Proof = {
ofDTO
};
// https://github.com/jfromaniello/url-join
// MIT License
// Copyright (c) 2015 José F. Romaniello
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
function normalize(strArray) {
const resultArray = [];
if (strArray.length === 0) {
return '';
}
if (typeof strArray[0] !== 'string') {
throw new TypeError('Url must be a string. Received ' + strArray[0]);
}
// If the first part is a plain protocol, we combine it with the next part.
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
strArray[0] = strArray.shift() + strArray[0];
}
// There must be two or three slashes in the file protocol, two slashes in anything else.
if (strArray[0].match(/^file:\/\/\//)) {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
}
else {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
}
for (let i = 0; i < strArray.length; i++) {
let component = strArray[i];
if (typeof component !== 'string') {
throw new TypeError('Url must be a string. Received ' + component);
}
if (component === '') {
continue;
}
if (i > 0) {
// Removing the starting slashes for each component but the first.
component = component.replace(/^[\/]+/, '');
}
if (i < strArray.length - 1) {
// Removing the ending slashes for each component but the last.
component = component.replace(/[\/]+$/, '');
}
else {
// For the last component we will combine multiple slashes to a single one.
component = component.replace(/[\/]+$/, '/');
}
resultArray.push(component);
}
let str = resultArray.join('/');
// Each input component is now separated by a single slash except the possible first plain protocol part.
// remove trailing slash before parameters or hash
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
// replace ? in parameters with &
const parts = str.split('?');
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
return str;
}
function urlJoin(...args) {
const parts = Array.from(Array.isArray(args[0]) ? args[0] : args);
return normalize(parts);
/**
* Returns the current level of the chain
* @returns the level of the chain as a promise
*/
level() {
return __awaiter(this, void 0, void 0, function* () {
const level = yield (0, network_1.get)(this.endpoints["GET_CURRENT_LEVEL"]);
return level;
});
}
const VERSION = "/api/v1";
const makeEndpoints = (root) => ({
"GET_CHAIN_INFO": {
uri: urlJoin(root, `${VERSION}/chain/info`),
expectedStatus: 200,
parse: (json) => {
const consensus = json.at("consensus").as_string();
// const discovery = json.at("discovery").as_string();
if (consensus === null)
return null;
// if (discovery === null) return null;
return { consensus };
}
},
"GET_CURRENT_LEVEL": {
uri: urlJoin(root, `${VERSION}/chain/level`),
expectedStatus: 200,
parse: (json) => {
const level_json = json.at("level");
return Level.ofDTO(level_json);
}
},
"GET_BLOCK_BY_LEVEL": (level) => ({
uri: urlJoin(root, `${VERSION}/chain/blocks/${Level.toDTO(level)}`),
expectedStatus: 200,
parse: Block.ofDTO
}),
"GET_BLOCK_BY_HASH": (blockHash) => ({
uri: urlJoin(root, `${VERSION}/chain/blocks/${blockHash}`),
expectedStatus: 200,
parse: Block.ofDTO
}),
"GET_GENESIS": {
uri: urlJoin(root, `${VERSION}/chain/blocks/genesis`),
expectedStatus: 200,
parse: Block.ofDTO
},
"GET_CURRENT_BLOCK": {
uri: urlJoin(root, `${VERSION}/chain/blocks/genesis`),
expectedStatus: 200,
parse: Block.ofDTO
},
"GET_BALANCE": (address, ticket_id) => ({
uri: urlJoin(root, `${VERSION}/balance/${address}/${ticket_id.ticketer}/${ticket_id.data}`),
expectedStatus: 200,
parse: (json) => {
return json.at("balance").as_int();
}
}),
"GET_PROOF": (operation_hash) => ({
uri: urlJoin(root, `${VERSION}/proof/${operation_hash}`),
expectedStatus: 200,
parse: Proof.ofDTO
}),
"OPERATIONS": {
uri: urlJoin(root, `${VERSION}/operations`),
expectedStatus: 200,
parse: (json) => {
const hash = json.at("hash").as_string();
return hash;
}
},
});
const parse = (endpoint, status, json) => __awaiter(void 0, void 0, void 0, function* () {
if (status !== endpoint.expectedStatus) {
return Promise.reject(json);
}
const jsonValue = JSONValue.of(json);
const parsedResponse = endpoint.parse(jsonValue);
if (parsedResponse === null) {
return Promise.reject({ "type": "ERROR", "msg": "please contact the team" });
}
return parsedResponse;
});
const get = (endpoint) => __awaiter(void 0, void 0, void 0, function* () {
const uri = endpoint.uri;
const response = yield fetch(uri);
const status = response.status;
const json = yield response.json();
return parse(endpoint, status, json);
});
const post = (endpoint, content) => __awaiter(void 0, void 0, void 0, function* () {
const uri = endpoint.uri;
const body = JSON.stringify(content);
const response = yield fetch(uri, { method: "POST", body });
const status = response.status;
const json = yield response.json();
return parse(endpoint, status, json);
});
class DekuSigner {
signOperation(operation) {
return __awaiter(this, void 0, void 0, function* () {
const jsonOperation = Operation.toDTO(operation);
const signature = yield this.sign(JSON.stringify(jsonOperation.as_json()));
const key = yield this.publicKey();
return {
key,
signature,
operation,
};
});
}
/**
* Returns the block at the given level
* @param level the level of the block to return
* @returns the block at the given level
*/
getBlockByLevel(level) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield (0, network_1.get)(this.endpoints["GET_BLOCK_BY_LEVEL"](level));
return block;
});
}
/**
* Converts a memory signer to a deku signer
* @param signer a memory signer instanciante by "InMemorySigner"
* @returns a deku signer
* Returns the block at the given hash
* @param hash the hash of the block to return
* @returns the block from the given hash
*/
const fromMemorySigner = (signer) => {
class MemorySigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () {
const payloadHex = Buffer.from(payload).toString("hex");
const signature = yield signer.sign(payloadHex);
return signature.prefixSig;
});
this.publicKey = () => signer.publicKey();
this.publicKeyHash = () => signer.publicKeyHash();
}
}
return new MemorySigner();
};
getBlockByHash(hash) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield (0, network_1.get)(this.endpoints["GET_BLOCK_BY_HASH"](hash));
return block;
});
}
/**
* Converts a beacon signer to a deku signer
* @param signer a beacon signer instanciante by "DAppClient"
* @returns a deku signer
* Returns the genesis block
* @returns the genesis block
*/
const fromBeaconSigner = (signer) => {
class BeaconSigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () {
const payloadHex = Buffer.from(payload).toString("hex");
const sig = yield signer.requestSignPayload({ payload: payloadHex });
if (!sig) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "cannot sign payload" });
}
return sig.signature;
});
this.publicKey = () => __awaiter(this, void 0, void 0, function* () {
const account = yield signer.getActiveAccount();
if (!account) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "Your account is not active" });
}
return account.publicKey;
});
this.publicKeyHash = () => __awaiter(this, void 0, void 0, function* () {
const account = yield signer.getActiveAccount();
if (!account) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "Your account is not active" });
}
return account.address;
});
}
}
return new BeaconSigner();
};
const fromCustomSigner = (signer) => {
class CustomSigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () { return signer.sign(payload); });
this.publicKey = () => __awaiter(this, void 0, void 0, function* () { return signer.publicKey(); });
this.publicKeyHash = () => __awaiter(this, void 0, void 0, function* () { return signer.publicKeyHash(); });
}
}
return new CustomSigner();
};
class DekuToolkit {
constructor(setting) {
this.endpoints = makeEndpoints(setting.dekuRpc);
this._dekuSigner = setting.dekuSigner;
this.onBlockCallback = () => { return; }; // The callback is not provided by the user in the constructor
// FIXME: not working properly
//this.initializeStream(setting.dekuRpc)
// .catch(err => console.error(`error: ${err}`));
this.pendingOperations = {};
}
initializeStream(dekuRpc) {
return __awaiter(this, void 0, void 0, function* () {
const streamUri = urlJoin(dekuRpc, "/api/v1/chain/blocks/monitor");
const response = yield fetch(streamUri);
const body = response.body;
if (!body)
return null;
const reader = body.getReader();
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = yield reader.read();
if (done)
break;
const decoder = new TextDecoder("utf-8");
const json = JSONValue.of(JSON.parse(decoder.decode(value)));
const block_hash = json.as_string();
// Add parsing for a block hash
if (block_hash === null)
return null;
const block = yield this.getBlockByHash(block_hash);
this.handleBlock(block);
return null;
}
return;
});
}
/**
* Sets the deku signer
* @param wallet the wallet you want to use
* @returns deku toolkit
*/
setDekuSigner(signer) {
this._dekuSigner = signer;
return this;
}
/**
* Utils function that check if the deku signer is setup
* @returns void if the signer is set, otherwise the promise is rejected
*/
assertTzWallet() {
if (!this._dekuSigner) {
throw new Error("Tezos wallet required, see setTzWallet");
}
return this._dekuSigner;
}
/**
* Sets ther tezos rpc node
* @param rpc the url of the tezos rpc,
* @returns
*/
setTezosRpc(rpc) {
const tezos = new taquito.TezosToolkit(rpc);
// get the consensus and discovery address
const uri = this.endpoints["GET_CHAIN_INFO"];
const consensusContract = () => get(uri).then(({ consensus }) => tezos.contract.at(consensus));
// const discoveryContract = () => get(uri).then(({ discovery }) => tezos.contract.at(discovery));
this._consensus = new Consensus(consensusContract);
// this._discovery = new Discovery(discoveryContract);
return this;
}
/**
* Sets the callback to call when a block is received
* @param callback the callback to be called when a new block arrived to the client
* Returns the deku updated toolkit
*/
onBlock(callback) {
this.onBlockCallback = callback;
return this;
}
/**
* Access the consensus contract to interact with it
* @return the consensus contract
*/
get consensus() {
return this._consensus;
}
/**
* Access the discovery contract to interact with it
* @return the consensus contract
*/
get discovery() {
throw "Not implemented";
// return this._discovery;
}
/**
* Returns the address of the consensus and discovery used by the deku chain
* @returns the consensus and discovery addresses
*/
info() {
return __awaiter(this, void 0, void 0, function* () {
const info = yield get(this.endpoints["GET_CHAIN_INFO"]);
return info;
});
}
/**
* Returns the current level of the chain
* @returns the level of the chain as a promise
*/
level() {
return __awaiter(this, void 0, void 0, function* () {
const level = yield get(this.endpoints["GET_CURRENT_LEVEL"]);
return level;
});
}
/**
* Returns the block at the given level
* @param level the level of the block to return
* @returns the block at the given level
*/
getBlockByLevel(level) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_BLOCK_BY_LEVEL"](level));
return block;
});
}
/**
* Returns the block at the given hash
* @param hash the hash of the block to return
* @returns the block from the given hash
*/
getBlockByHash(hash) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_BLOCK_BY_HASH"](hash));
return block;
});
}
/**
* Returns the genesis block
* @returns the genesis block
*/
getGenesis() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_GENESIS"]);
return block;
});
}
/**
* Returns the current block of deku
* @returns the current block
*/
getCurrentBlock() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_CURRENT_BLOCK"]);
return block;
});
}
getBalance(address, { ticketer, data }) {
return __awaiter(this, void 0, void 0, function* () {
const ticket_id = TicketID.createTicketID(ticketer, data.startsWith("0x") ? data : "0x" + data);
const balance = yield get(this.endpoints["GET_BALANCE"](address, ticket_id));
return balance;
});
}
getProof(operation_hash) {
return __awaiter(this, void 0, void 0, function* () {
const proof = yield get(this.endpoints["GET_PROOF"](operation_hash));
return proof;
});
}
/**
* Convert an optional operation options to operation info: source, level, nonce
* If the level is not provided, the returned level is the current level of the chain
* If the nonce is not provided, the returned nonce is a random one
* The source is always the source of the signer
* @param options
* @returns the source, a level and a nonce
*/
parseOperationOptions(options) {
return __awaiter(this, void 0, void 0, function* () {
const dekuSigner = this.assertTzWallet();
const source = yield dekuSigner.publicKeyHash();
const level = options === undefined || options.level === undefined ? yield this.level() : options.level;
const nonce = options === undefined || options.nonce === undefined ? Nonce.rand() : options.nonce;
return {
source, level, nonce
};
});
}
submitOperation(operation) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the deku signer
const dekuSigner = this.assertTzWallet();
// Add the operation to the pending operation list
const operationHash = hashOperation(operation);
this.addPendingOperation(operationHash);
// Sign the transaction
const signedOperation = yield dekuSigner.signOperation(operation);
// Send the operation
const body = Operation.signedToDTO(signedOperation);
const hash = yield post(this.endpoints["OPERATIONS"], body);
console.info("operation submitted");
console.info(`same hash: ${operationHash === hash}`);
return hash;
});
}
/**
* Transfer some ticket to someone
* @param receiver the address of the ticket receiver
* @param amount the amount of ticket you want to send
* @param options to define a custom level/nonce
* @param ticketer KT address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the transfer
*/
transferTo(receiver, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const transaction = Operation.createTransaction(level, nonce, source, receiver, amount, ticketer, data);
return this.submitOperation(transaction);
});
}
/**
* Withdraw
* @param owner the address of the ticket owner on Tezos (e.g. a KT1)
* @param amount the amount of ticket you want to withdraw
* @param options to define a custom level/nonce
* @param ticketer KT1 address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the withdraw
*/
withdrawTo(owner, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const withdraw = Operation.createWithdraw(level, nonce, source, owner, amount, ticketer, data);
return this.submitOperation(withdraw);
});
}
/**
* Submits an operation to the vm
* @param payload the string (TODO: is it better to have a json instead of a string ?)
* @param options {level, nonce} optional options
* @returns the hash the submitted operation
*/
submitVmOperation(payload, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
const vmOperation = Operation.createVmOperation(level, nonce, source, payload);
return this.submitOperation(vmOperation);
});
}
/**
* Resolve pending operations when the client receive a new block.
* @param block the received block from the API
*/
handleBlock(block) {
// Calling the callback given by the user
this.onBlockCallback(block);
// Get the hash of every operations in the block
const hashes = block.block.payload.flatMap(string => {
const operationContent = JSONValue.of(JSON.parse(string)).at("operation");
const operation = Operation.ofDTO(operationContent);
if (operation === null)
return [];
return [hashOperation(operation)];
});
hashes.forEach(hash => {
// Check if there is a pending operation
if (this.pendingOperations[hash] === undefined)
return null;
// if so it means that the pending operation is applied
this.pendingOperations[hash].applied = true;
const resolve = this.pendingOperations[hash].resolve;
// Check if the resolve function exists (it exists if the user is calling the "wait" function)
if (resolve === undefined)
return null;
// if so call it with the block level
resolve(block.block.level);
// Drop the watched operations
delete this.pendingOperations[hash];
getGenesis() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield (0, network_1.get)(this.endpoints["GET_GENESIS"]);
return block;
});
}
/**
* Returns the current block of deku
* @returns the current block
*/
getCurrentBlock() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield (0, network_1.get)(this.endpoints["GET_CURRENT_BLOCK"]);
return block;
});
}
getBalance(address, { ticketer, data }) {
return __awaiter(this, void 0, void 0, function* () {
const ticket_id = ticket_id_1.default.createTicketID(ticketer, data.startsWith("0x") ? data : "0x" + data);
const balance = yield (0, network_1.get)(this.endpoints["GET_BALANCE"](address, ticket_id));
return balance;
});
}
getProof(operation_hash) {
return __awaiter(this, void 0, void 0, function* () {
const proof = yield (0, network_1.get)(this.endpoints["GET_PROOF"](operation_hash));
return proof;
});
}
/**
* Convert an optional operation options to operation info: source, level, nonce
* If the level is not provided, the returned level is the current level of the chain
* If the nonce is not provided, the returned nonce is a random one
* The source is always the source of the signer
* @param options
* @returns the source, a level and a nonce
*/
parseOperationOptions(options) {
return __awaiter(this, void 0, void 0, function* () {
const dekuSigner = this.assertTzWallet();
const source = yield dekuSigner.publicKeyHash();
const level = options === undefined || options.level === undefined ? yield this.level() : options.level;
const nonce = options === undefined || options.nonce === undefined ? nonce_1.default.rand() : options.nonce;
return {
source, level, nonce
};
});
}
submitOperation(operation) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the deku signer
const dekuSigner = this.assertTzWallet();
// Add the operation to the pending operation list
const operationHash = (0, hash_1.hashOperation)(operation);
this.addPendingOperation(operationHash);
// Sign the transaction
const signedOperation = yield dekuSigner.signOperation(operation);
// Send the operation
const body = operation_1.default.signedToDTO(signedOperation);
const hash = yield (0, network_1.post)(this.endpoints["OPERATIONS"], body);
console.info("operation submitted");
console.info(`same hash: ${operationHash === hash}`);
return hash;
});
}
/**
* Transfer some ticket to someone
* @param receiver the address of the ticket receiver
* @param amount the amount of ticket you want to send
* @param options to define a custom level/nonce
* @param ticketer KT address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the transfer
*/
transferTo(receiver, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const transaction = operation_1.default.createTransaction(level, nonce, source, receiver, amount, ticketer, data);
return this.submitOperation(transaction);
});
}
/**
* Withdraw
* @param owner the address of the ticket owner on Tezos (e.g. a KT1)
* @param amount the amount of ticket you want to withdraw
* @param options to define a custom level/nonce
* @param ticketer KT1 address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the withdraw
*/
withdrawTo(owner, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const withdraw = operation_1.default.createWithdraw(level, nonce, source, owner, amount, ticketer, data);
return this.submitOperation(withdraw);
});
}
/**
* Submits an operation to the vm
* @param payload the string (TODO: is it better to have a json instead of a string ?)
* @param options {level, nonce} optional options
* @returns the hash the submitted operation
*/
submitVmOperation(payload, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
const vmOperation = operation_1.default.createVmOperation(level, nonce, source, payload);
return this.submitOperation(vmOperation);
});
}
/**
* Resolve pending operations when the client receive a new block.
* @param block the received block from the API
*/
handleBlock(block) {
// Calling the callback given by the user
this.onBlockCallback(block);
// Get the hash of every operations in the block
const hashes = block.block.payload.flatMap(string => {
const operationContent = json_1.default.of(JSON.parse(string)).at("operation");
const operation = operation_1.default.ofDTO(operationContent);
if (operation === null)
return [];
return [(0, hash_1.hashOperation)(operation)];
});
hashes.forEach(hash => {
// Check if there is a pending operation
if (this.pendingOperations[hash] === undefined)
return null;
});
// For the rest of the pending operations, we need to increment their age
// And reject too old operations
Object.keys(this.pendingOperations).forEach(key => {
// Increment the age
const age = this.pendingOperations[key].age + 1;
this.pendingOperations[key].age = age;
const maxAge = this.pendingOperations[key].maxAge;
const reject = this.pendingOperations[key].reject;
if (maxAge === undefined || reject === undefined)
return null;
if (age >= maxAge) {
reject();
delete this.pendingOperations[key]; // TODO: it may crash everything, if so purify this function
}
// if so it means that the pending operation is applied
this.pendingOperations[hash].applied = true;
const resolve = this.pendingOperations[hash].resolve;
// Check if the resolve function exists (it exists if the user is calling the "wait" function)
if (resolve === undefined)
return null;
// if so call it with the block level
resolve(block.block.level);
// Drop the watched operations
delete this.pendingOperations[hash];
return null;
});
// For the rest of the pending operations, we need to increment their age
// And reject too old operations
Object.keys(this.pendingOperations).forEach(key => {
// Increment the age
const age = this.pendingOperations[key].age + 1;
this.pendingOperations[key].age = age;
const maxAge = this.pendingOperations[key].maxAge;
const reject = this.pendingOperations[key].reject;
if (maxAge === undefined || reject === undefined)
return null;
if (age >= maxAge) {
reject();
delete this.pendingOperations[key]; // TODO: it may crash everything, if so purify this function
}
return null;
});
}
/**
* Add an operation to the pending operation map
* @param operationHash
*/
addPendingOperation(operationHash) {
this.pendingOperations[operationHash] = {
age: 0,
applied: false,
resolve: undefined,
reject: undefined,
maxAge: undefined,
};
}
/**
* Wait for the given operations during a given duration
* @param operation the hash of the operation to wait
* @param options {maxAge} the max duration to wait (in blocks)
*/
wait(operation, options) {
return __awaiter(this, void 0, void 0, function* () {
// Parsing the options
const maxAge = options && options.maxAge || 2; // We should always wait a minimum of 2 blocks. TODO: or 3 ?
const promise = new Promise((resolve, abort) => {
const watchedOperation = this.pendingOperations[operation];
const reject = () => abort({ type: "OPERATION_NOT_APPLIED", msg: "The operation has not been seen in blocks" });
this.pendingOperations[operation] = watchedOperation === undefined
? { age: 0, applied: false, resolve, reject, maxAge }
: Object.assign(Object.assign({}, watchedOperation), { resolve, reject, maxAge });
});
}
/**
* Add an operation to the pending operation map
* @param operationHash
*/
addPendingOperation(operationHash) {
this.pendingOperations[operationHash] = {
age: 0,
applied: false,
resolve: undefined,
reject: undefined,
maxAge: undefined,
};
}
/**
* Wait for the given operations during a given duration
* @param operation the hash of the operation to wait
* @param options {maxAge} the max duration to wait (in blocks)
*/
wait(operation, options) {
return __awaiter(this, void 0, void 0, function* () {
// Parsing the options
const maxAge = options && options.maxAge || 2; // We should always wait a minimum of 2 blocks. TODO: or 3 ?
const promise = new Promise((resolve, abort) => {
const watchedOperation = this.pendingOperations[operation];
const reject = () => abort({ type: "OPERATION_NOT_APPLIED", msg: "The operation has not been seen in blocks" });
this.pendingOperations[operation] = watchedOperation === undefined
? { age: 0, applied: false, resolve, reject, maxAge }
: Object.assign(Object.assign({}, watchedOperation), { resolve, reject, maxAge });
});
return promise;
});
}
return promise;
});
}
exports.DekuToolkit = DekuToolkit;
exports.fromBeaconSigner = fromBeaconSigner;
exports.fromCustomSigner = fromCustomSigner;
exports.fromMemorySigner = fromMemorySigner;
Object.defineProperty(exports, '__esModule', { value: true });
}));
//# sourceMappingURL=index.js.map
}
exports.DekuToolkit = DekuToolkit;
var signers_1 = require("./utils/signers");
Object.defineProperty(exports, "fromBeaconSigner", { enumerable: true, get: function () { return signers_1.fromBeaconSigner; } });
Object.defineProperty(exports, "fromCustomSigner", { enumerable: true, get: function () { return signers_1.fromCustomSigner; } });
Object.defineProperty(exports, "fromMemorySigner", { enumerable: true, get: function () { return signers_1.fromMemorySigner; } });
//# sourceMappingURL=index.js.map
{
"name": "@marigold-dev/deku-toolkit",
"version": "0.1.8",
"version": "0.1.9",
"description": "toolkit to interact with deku",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

import { TezosToolkit } from '@taquito/taquito';
import * as blake from 'blakejs';
import * as bs58check from 'bs58check';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(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());
});
}
class Consensus {
constructor(contract) {
this._contract = contract;
}
/**
* Retrieve the level of the chain from the consensus contract
* @returns the level of the chain
*/
level() {
return __awaiter(this, void 0, void 0, function* () {
const contract = yield this._contract();
const storage = yield contract.storage();
return storage.root_hash.current_block_level.c[0];
});
}
/**
* Returns the list of tezos address of all validators known by the consensus
* @returns a list of tezos address
*/
validators() {
return __awaiter(this, void 0, void 0, function* () {
const contract = yield this._contract();
const storage = yield contract.storage();
return storage.root_hash.current_validators;
});
}
/**
* Returns the address of the consensus contract
* @returns tezos address as string
*/
address() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._contract()).address;
});
}
}
/**
* Creates a new once
* @returns random number between 0 and 2**32
*/
const rand = () => {
const maxInt32 = 2147483647;
const nonce = Math.floor(Math.random() * maxInt32);
return nonce;
};
const toDTO$3 = (nonce) => {
return nonce.toString();
};
const ofDTO$5 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
}
catch (_a) {
return null;
}
};
var Nonce = {
rand,
toDTO: toDTO$3,
ofDTO: ofDTO$5
};
const toDTO$2 = (amount) => {
return amount.toString();
};
const ofDTO$4 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
}
catch (_a) {
return null;
}
};
var Amount = {
toDTO: toDTO$2,
ofDTO: ofDTO$4
};
const toDTO$1 = (level) => {
return level.toString();
};
const ofDTO$3 = (json) => {
const string = json.as_string();
if (string === null)
return null;
try {
return Number.parseInt(string);
}
catch (_a) {
return null;
}
};
var Level = {
toDTO: toDTO$1,
ofDTO: ofDTO$3
};
// Please, tell me there is a better JSON library that this one
class JSONValue {
constructor() {
this._json = null;
}
static of(json) {
const value = new JSONValue();
value._json = json;
return value;
}
null() {
return JSONValue.of(null);
}
at(field) {
if (this._json === null)
return this.null();
if (typeof this._json !== "object")
return this.null();
if (Array.isArray(this._json))
return this.null();
if (!(field in this._json))
return this.null();
const value = this._json[field];
return JSONValue.of(value);
}
as_string() {
if (this._json === null)
return null;
if (typeof this._json !== "string")
return null;
return this._json;
}
as_int() {
if (this._json === null)
return null;
if (typeof this._json !== "number")
return null;
return this._json;
}
as_array() {
if (this._json === null)
return null;
if (!Array.isArray(this._json))
return null;
return this._json.map(json => JSONValue.of(json));
}
as_string_array() {
if (this._json === null)
return null;
if (!Array.isArray(this._json))
return null;
const array = this._json.flatMap(elt => {
const element = JSONValue.of(elt).as_string();
if (element === null)
return [];
return [element];
});
return array.length === this._json.length ? array : null; // If the size of doesn't match it means there wasn't only strings in the array
}
as_json() {
return this._json;
}
}
const createTransaction = (level, nonce, source, receiver, amount, ticketer, data) => {
const a = {
level,
nonce,
source,
type: "Transaction",
content: {
receiver,
ticket_id: ["Ticket_id", {
ticketer: ticketer,
data
}],
amount
}
};
return a;
};
const createVmOperation = (level, nonce, source, payload) => {
return {
level,
nonce,
source,
type: "Vm",
content: {
payload
}
};
};
const createWithdraw = (level, nonce, source, owner, amount, ticketer, data) => {
const a = {
level,
nonce,
source,
type: "Withdraw",
content: {
owner,
ticket_id: ["Ticket_id", {
ticketer: ticketer,
data
}],
amount
}
};
return a;
};
const toDTO = (operation) => {
const { level, nonce, source, type, content } = operation;
switch (type) {
case "Transaction": {
const { receiver, amount, ticket_id } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Ticket_transfer", { receiver, ticket_id, amount: Amount.toDTO(amount) }]
};
return JSONValue.of(dto);
}
case "Withdraw": {
const { owner, amount, ticket_id } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Tezos_withdraw", { owner: ["Implicit", owner], ticket_id, amount: Amount.toDTO(amount) }]
};
return JSONValue.of(dto);
}
case "Vm": {
const { payload } = content;
const dto = {
level: Level.toDTO(level),
nonce: Nonce.toDTO(nonce),
source: source,
content: ["Vm_transaction", { operation: payload, tickets: [] }]
};
return JSONValue.of(dto);
}
}
};
const signedToDTO = (signedOperation) => {
const { key, signature, operation } = signedOperation;
const op = toDTO(operation).as_json();
return {
key,
signature,
operation: op
};
};
// FIXME to update with ticket ids and withdraws
const ofDTO$2 = (json) => {
const level_json = json.at("level");
const nonce_json = json.at("nonce");
const source = json.at("source").as_string();
const content_array = json.at("content").as_array();
if (content_array === null || source === null)
return null;
const [type_str, payload] = content_array;
const type = type_str.as_string();
if (type === null)
return null;
const level = Level.ofDTO(level_json);
if (level === null)
return null;
const nonce = Nonce.ofDTO(nonce_json);
if (nonce === null)
return null;
switch (type) {
case "Transaction": {
const amount_json = payload.at("amount");
const receiver_str = payload.at("receiver").as_string();
if (receiver_str === null)
return null;
const amount = Amount.ofDTO(amount_json);
if (amount === null)
return null;
return createTransaction(level, nonce, source, receiver_str, amount, "error", "error");
}
case "Vm_transaction": {
const operation = payload.at("operation").as_string();
if (operation === null)
return null;
return createVmOperation(level, nonce, source, operation);
}
default:
return null;
}
};
var Operation = {
createTransaction,
createVmOperation,
createWithdraw,
toDTO,
ofDTO: ofDTO$2,
signedToDTO
};
const createTicketID = (ticketer, data) => {
return {
ticketer,
data
};
};
var TicketID = {
createTicketID
};
const ofDTO$1 = (dto) => {
const key_str = dto.at("key").as_string();
const signature_str = dto.at("signature").as_string();
const block = dto.at("block");
const author_str = block.at("author").as_string();
const level = Level.ofDTO(block.at("level"));
const previous_str = block.at("previous").as_string();
const payload_json = block.at("payload").as_string_array();
const tezos_operations = block.at("tezos_operations").as_string_array();
if (key_str === null)
return null;
if (signature_str === null)
return null;
if (author_str === null)
return null;
if (level === null)
return null;
if (previous_str === null)
return null;
if (payload_json === null)
return null;
if (tezos_operations === null)
return null;
return {
key: key_str,
signature: signature_str,
block: {
author: author_str,
level,
previous: previous_str,
payload: payload_json,
tezos_operations
}
};
};
var Block = {
ofDTO: ofDTO$1
};
const PREFIX = {
"Do": new Uint8Array([86, 124]),
"Db": new Uint8Array([85, 22]),
};
/**
* Hash the string representation of the payload, returns the b58 reprensentation starting with the given prefix
* @param prefix the prefix of your hash
* @returns
*/
const toB58Hash = (prefix) => (payload) => {
const payloadStr = JSON.stringify(payload.as_json());
const blakeHash = blake.blake2b(payloadStr, undefined, 32);
const tmp = new Uint8Array(prefix.length + blakeHash.length);
tmp.set(prefix);
tmp.set(blakeHash, prefix.length);
const b58 = bs58check.encode(Buffer.from(tmp));
return b58;
};
const fromB58Hash = (x) => {
const y = bs58check.decode(x);
const tmp = new Uint8Array(y.buffer).slice(0, 32 + 2);
return "0x" + Buffer.from(tmp.slice(2)).toString("hex");
};
const createOperationHash = toB58Hash(PREFIX.Do);
const hashOperation = (operation) => {
const json = Operation.toDTO(operation);
return createOperationHash(json);
};
const ofDTO = (json) => {
console.log(json.as_json());
const withdrawal_handles_hash = json.at("withdrawal_handles_hash").as_string();
const handle = json.at("handle");
const proof = json.at("proof").as_array();
if (proof === null)
return null;
const proof2 = proof.flatMap((x) => {
const y = x.as_array();
if (y === null) {
throw "nope";
}
return [y];
}).flat();
console.log(proof2);
const proof3 = proof2.flatMap((x) => {
const y = x.as_string();
if (y === null) {
console.log(y);
throw "Nope";
}
return [fromB58Hash(y)];
});
const id = handle.at("id").as_int();
const owner = handle.at("owner").as_array();
const ticket_id = handle.at("ticket_id").as_array();
if (ticket_id === null)
return null;
const ticketer = ticket_id[1].at("ticketer").as_string();
const data = ticket_id[1].at("data").as_string();
const hash = handle.at("hash").as_string();
const amount = handle.at("amount").as_string();
if (withdrawal_handles_hash === null)
return null;
console.log("a");
if (proof === null)
return null;
console.log("b");
if (id === null)
return null;
console.log("c");
if (owner === null)
return null;
console.log("d");
if (ticketer === null)
return null;
console.log("e");
if (data === null)
return null;
console.log("f");
if (hash === null)
return null;
console.log("g");
if (amount === null)
return null;
console.log("h");
const address = owner[1].as_string();
if (address === null)
return null;
console.log("i");
return {
withdrawal_handles_hash: fromB58Hash(withdrawal_handles_hash),
handle: {
id,
owner: address,
ticket_id: {
ticketer,
data
},
hash,
amount
},
proof: proof3
};
};
var Proof = {
ofDTO
};
// https://github.com/jfromaniello/url-join
// MIT License
// Copyright (c) 2015 José F. Romaniello
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
function normalize(strArray) {
const resultArray = [];
if (strArray.length === 0) {
return '';
}
if (typeof strArray[0] !== 'string') {
throw new TypeError('Url must be a string. Received ' + strArray[0]);
}
// If the first part is a plain protocol, we combine it with the next part.
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
strArray[0] = strArray.shift() + strArray[0];
}
// There must be two or three slashes in the file protocol, two slashes in anything else.
if (strArray[0].match(/^file:\/\/\//)) {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
}
else {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
}
for (let i = 0; i < strArray.length; i++) {
let component = strArray[i];
if (typeof component !== 'string') {
throw new TypeError('Url must be a string. Received ' + component);
}
if (component === '') {
continue;
}
if (i > 0) {
// Removing the starting slashes for each component but the first.
component = component.replace(/^[\/]+/, '');
}
if (i < strArray.length - 1) {
// Removing the ending slashes for each component but the last.
component = component.replace(/[\/]+$/, '');
}
else {
// For the last component we will combine multiple slashes to a single one.
component = component.replace(/[\/]+$/, '/');
}
resultArray.push(component);
}
let str = resultArray.join('/');
// Each input component is now separated by a single slash except the possible first plain protocol part.
// remove trailing slash before parameters or hash
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
// replace ? in parameters with &
const parts = str.split('?');
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
return str;
}
function urlJoin(...args) {
const parts = Array.from(Array.isArray(args[0]) ? args[0] : args);
return normalize(parts);
}
const VERSION = "/api/v1";
const makeEndpoints = (root) => ({
"GET_CHAIN_INFO": {
uri: urlJoin(root, `${VERSION}/chain/info`),
expectedStatus: 200,
parse: (json) => {
const consensus = json.at("consensus").as_string();
// const discovery = json.at("discovery").as_string();
if (consensus === null)
return null;
// if (discovery === null) return null;
return { consensus };
}
},
"GET_CURRENT_LEVEL": {
uri: urlJoin(root, `${VERSION}/chain/level`),
expectedStatus: 200,
parse: (json) => {
const level_json = json.at("level");
return Level.ofDTO(level_json);
}
},
"GET_BLOCK_BY_LEVEL": (level) => ({
uri: urlJoin(root, `${VERSION}/chain/blocks/${Level.toDTO(level)}`),
expectedStatus: 200,
parse: Block.ofDTO
}),
"GET_BLOCK_BY_HASH": (blockHash) => ({
uri: urlJoin(root, `${VERSION}/chain/blocks/${blockHash}`),
expectedStatus: 200,
parse: Block.ofDTO
}),
"GET_GENESIS": {
uri: urlJoin(root, `${VERSION}/chain/blocks/genesis`),
expectedStatus: 200,
parse: Block.ofDTO
},
"GET_CURRENT_BLOCK": {
uri: urlJoin(root, `${VERSION}/chain/blocks/genesis`),
expectedStatus: 200,
parse: Block.ofDTO
},
"GET_BALANCE": (address, ticket_id) => ({
uri: urlJoin(root, `${VERSION}/balance/${address}/${ticket_id.ticketer}/${ticket_id.data}`),
expectedStatus: 200,
parse: (json) => {
return json.at("balance").as_int();
}
}),
"GET_PROOF": (operation_hash) => ({
uri: urlJoin(root, `${VERSION}/proof/${operation_hash}`),
expectedStatus: 200,
parse: Proof.ofDTO
}),
"OPERATIONS": {
uri: urlJoin(root, `${VERSION}/operations`),
expectedStatus: 200,
parse: (json) => {
const hash = json.at("hash").as_string();
return hash;
}
},
});
const parse = (endpoint, status, json) => __awaiter(void 0, void 0, void 0, function* () {
if (status !== endpoint.expectedStatus) {
return Promise.reject(json);
}
const jsonValue = JSONValue.of(json);
const parsedResponse = endpoint.parse(jsonValue);
if (parsedResponse === null) {
return Promise.reject({ "type": "ERROR", "msg": "please contact the team" });
}
return parsedResponse;
});
const get = (endpoint) => __awaiter(void 0, void 0, void 0, function* () {
const uri = endpoint.uri;
const response = yield fetch(uri);
const status = response.status;
const json = yield response.json();
return parse(endpoint, status, json);
});
const post = (endpoint, content) => __awaiter(void 0, void 0, void 0, function* () {
const uri = endpoint.uri;
const body = JSON.stringify(content);
const response = yield fetch(uri, { method: "POST", body });
const status = response.status;
const json = yield response.json();
return parse(endpoint, status, json);
});
class DekuSigner {
signOperation(operation) {
return __awaiter(this, void 0, void 0, function* () {
const jsonOperation = Operation.toDTO(operation);
const signature = yield this.sign(JSON.stringify(jsonOperation.as_json()));
const key = yield this.publicKey();
return {
key,
signature,
operation,
};
});
}
}
/**
* Converts a memory signer to a deku signer
* @param signer a memory signer instanciante by "InMemorySigner"
* @returns a deku signer
*/
const fromMemorySigner = (signer) => {
class MemorySigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () {
const payloadHex = Buffer.from(payload).toString("hex");
const signature = yield signer.sign(payloadHex);
return signature.prefixSig;
});
this.publicKey = () => signer.publicKey();
this.publicKeyHash = () => signer.publicKeyHash();
}
}
return new MemorySigner();
};
/**
* Converts a beacon signer to a deku signer
* @param signer a beacon signer instanciante by "DAppClient"
* @returns a deku signer
*/
const fromBeaconSigner = (signer) => {
class BeaconSigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () {
const payloadHex = Buffer.from(payload).toString("hex");
const sig = yield signer.requestSignPayload({ payload: payloadHex });
if (!sig) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "cannot sign payload" });
}
return sig.signature;
});
this.publicKey = () => __awaiter(this, void 0, void 0, function* () {
const account = yield signer.getActiveAccount();
if (!account) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "Your account is not active" });
}
return account.publicKey;
});
this.publicKeyHash = () => __awaiter(this, void 0, void 0, function* () {
const account = yield signer.getActiveAccount();
if (!account) {
return Promise.reject({ type: "SIGNER_ERROR", msg: "Your account is not active" });
}
return account.address;
});
}
}
return new BeaconSigner();
};
const fromCustomSigner = (signer) => {
class CustomSigner extends DekuSigner {
constructor() {
super(...arguments);
this.sign = (payload) => __awaiter(this, void 0, void 0, function* () { return signer.sign(payload); });
this.publicKey = () => __awaiter(this, void 0, void 0, function* () { return signer.publicKey(); });
this.publicKeyHash = () => __awaiter(this, void 0, void 0, function* () { return signer.publicKeyHash(); });
}
}
return new CustomSigner();
};
class DekuToolkit {
constructor(setting) {
this.endpoints = makeEndpoints(setting.dekuRpc);
this._dekuSigner = setting.dekuSigner;
this.onBlockCallback = () => { return; }; // The callback is not provided by the user in the constructor
// FIXME: not working properly
//this.initializeStream(setting.dekuRpc)
// .catch(err => console.error(`error: ${err}`));
this.pendingOperations = {};
}
initializeStream(dekuRpc) {
return __awaiter(this, void 0, void 0, function* () {
const streamUri = urlJoin(dekuRpc, "/api/v1/chain/blocks/monitor");
const response = yield fetch(streamUri);
const body = response.body;
if (!body)
return null;
const reader = body.getReader();
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = yield reader.read();
if (done)
break;
const decoder = new TextDecoder("utf-8");
const json = JSONValue.of(JSON.parse(decoder.decode(value)));
const block_hash = json.as_string();
// Add parsing for a block hash
if (block_hash === null)
return null;
const block = yield this.getBlockByHash(block_hash);
this.handleBlock(block);
return null;
}
return;
});
}
/**
* Sets the deku signer
* @param wallet the wallet you want to use
* @returns deku toolkit
*/
setDekuSigner(signer) {
this._dekuSigner = signer;
return this;
}
/**
* Utils function that check if the deku signer is setup
* @returns void if the signer is set, otherwise the promise is rejected
*/
assertTzWallet() {
if (!this._dekuSigner) {
throw new Error("Tezos wallet required, see setTzWallet");
}
return this._dekuSigner;
}
/**
* Sets ther tezos rpc node
* @param rpc the url of the tezos rpc,
* @returns
*/
setTezosRpc(rpc) {
const tezos = new TezosToolkit(rpc);
// get the consensus and discovery address
const uri = this.endpoints["GET_CHAIN_INFO"];
const consensusContract = () => get(uri).then(({ consensus }) => tezos.contract.at(consensus));
// const discoveryContract = () => get(uri).then(({ discovery }) => tezos.contract.at(discovery));
this._consensus = new Consensus(consensusContract);
// this._discovery = new Discovery(discoveryContract);
return this;
}
/**
* Sets the callback to call when a block is received
* @param callback the callback to be called when a new block arrived to the client
* Returns the deku updated toolkit
*/
onBlock(callback) {
this.onBlockCallback = callback;
return this;
}
/**
* Access the consensus contract to interact with it
* @return the consensus contract
*/
get consensus() {
return this._consensus;
}
/**
* Access the discovery contract to interact with it
* @return the consensus contract
*/
get discovery() {
throw "Not implemented";
// return this._discovery;
}
/**
* Returns the address of the consensus and discovery used by the deku chain
* @returns the consensus and discovery addresses
*/
info() {
return __awaiter(this, void 0, void 0, function* () {
const info = yield get(this.endpoints["GET_CHAIN_INFO"]);
return info;
});
}
/**
* Returns the current level of the chain
* @returns the level of the chain as a promise
*/
level() {
return __awaiter(this, void 0, void 0, function* () {
const level = yield get(this.endpoints["GET_CURRENT_LEVEL"]);
return level;
});
}
/**
* Returns the block at the given level
* @param level the level of the block to return
* @returns the block at the given level
*/
getBlockByLevel(level) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_BLOCK_BY_LEVEL"](level));
return block;
});
}
/**
* Returns the block at the given hash
* @param hash the hash of the block to return
* @returns the block from the given hash
*/
getBlockByHash(hash) {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_BLOCK_BY_HASH"](hash));
return block;
});
}
/**
* Returns the genesis block
* @returns the genesis block
*/
getGenesis() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_GENESIS"]);
return block;
});
}
/**
* Returns the current block of deku
* @returns the current block
*/
getCurrentBlock() {
return __awaiter(this, void 0, void 0, function* () {
const block = yield get(this.endpoints["GET_CURRENT_BLOCK"]);
return block;
});
}
getBalance(address, { ticketer, data }) {
return __awaiter(this, void 0, void 0, function* () {
const ticket_id = TicketID.createTicketID(ticketer, data.startsWith("0x") ? data : "0x" + data);
const balance = yield get(this.endpoints["GET_BALANCE"](address, ticket_id));
return balance;
});
}
getProof(operation_hash) {
return __awaiter(this, void 0, void 0, function* () {
const proof = yield get(this.endpoints["GET_PROOF"](operation_hash));
return proof;
});
}
/**
* Convert an optional operation options to operation info: source, level, nonce
* If the level is not provided, the returned level is the current level of the chain
* If the nonce is not provided, the returned nonce is a random one
* The source is always the source of the signer
* @param options
* @returns the source, a level and a nonce
*/
parseOperationOptions(options) {
return __awaiter(this, void 0, void 0, function* () {
const dekuSigner = this.assertTzWallet();
const source = yield dekuSigner.publicKeyHash();
const level = options === undefined || options.level === undefined ? yield this.level() : options.level;
const nonce = options === undefined || options.nonce === undefined ? Nonce.rand() : options.nonce;
return {
source, level, nonce
};
});
}
submitOperation(operation) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the deku signer
const dekuSigner = this.assertTzWallet();
// Add the operation to the pending operation list
const operationHash = hashOperation(operation);
this.addPendingOperation(operationHash);
// Sign the transaction
const signedOperation = yield dekuSigner.signOperation(operation);
// Send the operation
const body = Operation.signedToDTO(signedOperation);
const hash = yield post(this.endpoints["OPERATIONS"], body);
console.info("operation submitted");
console.info(`same hash: ${operationHash === hash}`);
return hash;
});
}
/**
* Transfer some ticket to someone
* @param receiver the address of the ticket receiver
* @param amount the amount of ticket you want to send
* @param options to define a custom level/nonce
* @param ticketer KT address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the transfer
*/
transferTo(receiver, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const transaction = Operation.createTransaction(level, nonce, source, receiver, amount, ticketer, data);
return this.submitOperation(transaction);
});
}
/**
* Withdraw
* @param owner the address of the ticket owner on Tezos (e.g. a KT1)
* @param amount the amount of ticket you want to withdraw
* @param options to define a custom level/nonce
* @param ticketer KT1 address, first half of the ticket id
* @param data other half of the ticket id
* @returns an operation hash of the withdraw
*/
withdrawTo(owner, amount, ticketer, data, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
// Create the transaction
const withdraw = Operation.createWithdraw(level, nonce, source, owner, amount, ticketer, data);
return this.submitOperation(withdraw);
});
}
/**
* Submits an operation to the vm
* @param payload the string (TODO: is it better to have a json instead of a string ?)
* @param options {level, nonce} optional options
* @returns the hash the submitted operation
*/
submitVmOperation(payload, options) {
return __awaiter(this, void 0, void 0, function* () {
const { source, level, nonce } = yield this.parseOperationOptions(options);
const vmOperation = Operation.createVmOperation(level, nonce, source, payload);
return this.submitOperation(vmOperation);
});
}
/**
* Resolve pending operations when the client receive a new block.
* @param block the received block from the API
*/
handleBlock(block) {
// Calling the callback given by the user
this.onBlockCallback(block);
// Get the hash of every operations in the block
const hashes = block.block.payload.flatMap(string => {
const operationContent = JSONValue.of(JSON.parse(string)).at("operation");
const operation = Operation.ofDTO(operationContent);
if (operation === null)
return [];
return [hashOperation(operation)];
});
hashes.forEach(hash => {
// Check if there is a pending operation
if (this.pendingOperations[hash] === undefined)
return null;
// if so it means that the pending operation is applied
this.pendingOperations[hash].applied = true;
const resolve = this.pendingOperations[hash].resolve;
// Check if the resolve function exists (it exists if the user is calling the "wait" function)
if (resolve === undefined)
return null;
// if so call it with the block level
resolve(block.block.level);
// Drop the watched operations
delete this.pendingOperations[hash];
return null;
});
// For the rest of the pending operations, we need to increment their age
// And reject too old operations
Object.keys(this.pendingOperations).forEach(key => {
// Increment the age
const age = this.pendingOperations[key].age + 1;
this.pendingOperations[key].age = age;
const maxAge = this.pendingOperations[key].maxAge;
const reject = this.pendingOperations[key].reject;
if (maxAge === undefined || reject === undefined)
return null;
if (age >= maxAge) {
reject();
delete this.pendingOperations[key]; // TODO: it may crash everything, if so purify this function
}
return null;
});
}
/**
* Add an operation to the pending operation map
* @param operationHash
*/
addPendingOperation(operationHash) {
this.pendingOperations[operationHash] = {
age: 0,
applied: false,
resolve: undefined,
reject: undefined,
maxAge: undefined,
};
}
/**
* Wait for the given operations during a given duration
* @param operation the hash of the operation to wait
* @param options {maxAge} the max duration to wait (in blocks)
*/
wait(operation, options) {
return __awaiter(this, void 0, void 0, function* () {
// Parsing the options
const maxAge = options && options.maxAge || 2; // We should always wait a minimum of 2 blocks. TODO: or 3 ?
const promise = new Promise((resolve, abort) => {
const watchedOperation = this.pendingOperations[operation];
const reject = () => abort({ type: "OPERATION_NOT_APPLIED", msg: "The operation has not been seen in blocks" });
this.pendingOperations[operation] = watchedOperation === undefined
? { age: 0, applied: false, resolve, reject, maxAge }
: Object.assign(Object.assign({}, watchedOperation), { resolve, reject, maxAge });
});
return promise;
});
}
}
export { DekuToolkit, fromBeaconSigner, fromCustomSigner, fromMemorySigner };
//# sourceMappingURL=index.es6.js.map

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display