0.1 release, add .on(...) and .once(...) to RJSVM, add tests
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
build
|
||||||
|
node_modules
|
||||||
|
.vscode
|
||||||
|
lib
|
||||||
|
docs
|
||||||
|
gui/*.js
|
||||||
|
src/gui/build
|
||||||
|
src/gui/dist
|
||||||
|
src/gui/node_modules
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
src
|
||||||
|
.git
|
||||||
|
.vscode
|
||||||
|
node_modules
|
||||||
|
test
|
||||||
|
.drone.yml
|
||||||
|
.gitignore
|
||||||
|
tsconfig.json
|
||||||
|
lib/src/xrpIO/ripple-bindings.*
|
||||||
Vendored
-4
@@ -1,4 +0,0 @@
|
|||||||
import { RJSVM, RJSVM_Config, RJSVM_Implementations, Function_Map, Endpoints_Of, State_Of, Generic_Ctor_ReturnType } from "./types";
|
|
||||||
export declare abstract class RJSVM_Builder {
|
|
||||||
static from<Base_Ctor extends (new (...args: any) => RJSVM<State_T, Endpoints_T>) | (abstract new (...args: any) => RJSVM<State_T, Endpoints_T>), Impl extends RJSVM_Implementations<any, Endpoints_T>, Endpoints_T extends Function_Map = Endpoints_Of<Generic_Ctor_ReturnType<Base_Ctor>>, State_T = State_Of<Generic_Ctor_ReturnType<Base_Ctor>>>(Base: Base_Ctor, defs: Impl): (new (config: RJSVM_Config) => RJSVM<State_T, Endpoints_T>);
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.RJSVM_Builder = void 0;
|
|
||||||
const types_1 = require("./types");
|
|
||||||
const xrpl_1 = require("xrpl");
|
|
||||||
const xrpio_1 = require("xrpio");
|
|
||||||
const dataparser_1 = require("../../util/dataparser");
|
|
||||||
const protocol_constants_1 = require("../../util/protocol.constants");
|
|
||||||
class RJSVM_Builder {
|
|
||||||
static from(Base, defs) {
|
|
||||||
return class RJSVM_Runnable extends Base {
|
|
||||||
config;
|
|
||||||
sync_block_height = -1;
|
|
||||||
rippleApi;
|
|
||||||
xrpIO;
|
|
||||||
definitions;
|
|
||||||
constructor(config) {
|
|
||||||
super();
|
|
||||||
this.config = config;
|
|
||||||
if (!protocol_constants_1.XRP_ADDRESS.test(this.owner)) {
|
|
||||||
throw new Error(`Inavlid owner address ${this.owner}`);
|
|
||||||
}
|
|
||||||
this.definitions = Object.freeze(defs);
|
|
||||||
Object.entries(this.definitions).forEach(([k, v]) => {
|
|
||||||
this[k] = (env, ...args) => v.implementation.apply(this, [env, ...args]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
connect = async () => {
|
|
||||||
this.rippleApi = new xrpl_1.Client(this.config.rippleNode);
|
|
||||||
await this.rippleApi.connect();
|
|
||||||
this.xrpIO = new xrpio_1.xrpIO(this.config.rippleNode);
|
|
||||||
await this.xrpIO.connect();
|
|
||||||
await this.sync();
|
|
||||||
this.rippleApi.on('ledgerClosed', (ledger) => {
|
|
||||||
/*
|
|
||||||
console.log("---- Ledger ----")
|
|
||||||
console.log("index",ledger.ledger_index)
|
|
||||||
console.log("hash", ledger.ledger_hash)
|
|
||||||
console.log("---- /Ledger ----")
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
await this.rippleApi.request({
|
|
||||||
command: 'subscribe',
|
|
||||||
streams: ['ledger']
|
|
||||||
});
|
|
||||||
};
|
|
||||||
handlePayload = async (tx, payload) => {
|
|
||||||
if (!(payload.endpoint in this.definitions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const endpointDef = this.definitions[payload.endpoint];
|
|
||||||
if (endpointDef.visibility === 'owner' && tx.Account !== this.owner) {
|
|
||||||
console.log(`owner restricted endpoint "${payload.endpoint}" called from ${tx.hash}. But ${tx.Account} != ${this.owner}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (endpointDef.fee && Number(tx.Amount) < endpointDef.fee) {
|
|
||||||
console.log(`Insufficient fee ${tx.hash}. Required ${endpointDef.fee}, was ${tx.Amount}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await this.xrpIO.treeRead([payload.data], tx.Account);
|
|
||||||
const jsonData = JSON.parse(data);
|
|
||||||
endpointDef.parameterSchema.parse(jsonData);
|
|
||||||
this[payload.endpoint].apply(this, [tx, jsonData]);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
parseMemos = async (tx, memos) => {
|
|
||||||
memos
|
|
||||||
.map((memo) => {
|
|
||||||
if (!memo.Memo || !memo.Memo.MemoData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = dataparser_1.DataParser.hex_to_ascii(memo.Memo.MemoData);
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter((data) => data != undefined)
|
|
||||||
.forEach(payload => {
|
|
||||||
try {
|
|
||||||
const parsedPayload = types_1.payloadSchema.parse(payload);
|
|
||||||
this.handlePayload(tx, parsedPayload);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
sync = async (marker) => {
|
|
||||||
//If `forward` is set to true, returns values indexed with the oldest ledger first.
|
|
||||||
//Otherwise, the results are indexed with the newest ledger first.
|
|
||||||
//(Each page of results may not be internally ordered, but the pages are overall ordered.)
|
|
||||||
const resp = await this.rippleApi.request({
|
|
||||||
command: "account_tx",
|
|
||||||
account: this.config.listeningAddress,
|
|
||||||
forward: true,
|
|
||||||
ledger_index_min: this.sync_block_height,
|
|
||||||
marker: marker,
|
|
||||||
});
|
|
||||||
//results may not be ordered, so sort them
|
|
||||||
const raw_txs = resp.result.transactions
|
|
||||||
.sort((a, b) => a.tx.ledger_index - b.tx.ledger_index)
|
|
||||||
.map((entry) => entry.tx);
|
|
||||||
//apply any state changes
|
|
||||||
await Promise.all(raw_txs.map((tx) => this.parseMemos(tx, tx.Memos)));
|
|
||||||
//if marker is present the result is paginated.
|
|
||||||
//re-run the same request with the marker included
|
|
||||||
if (resp.result.marker) {
|
|
||||||
await this.sync(resp.result.marker);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//presence of no marker means we caught up to current block height
|
|
||||||
this.sync_block_height = resp.result.ledger_index_max + 1;
|
|
||||||
//schedule the next sync
|
|
||||||
setTimeout(this.sync, 10000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.RJSVM_Builder = RJSVM_Builder;
|
|
||||||
Vendored
-67
@@ -1,67 +0,0 @@
|
|||||||
import { z } from "zod";
|
|
||||||
export declare abstract class RJSVM<State_T = any, Definitions_T extends Function_Map = Function_Map> {
|
|
||||||
owner: string;
|
|
||||||
state: State_T;
|
|
||||||
sync_block_height: number;
|
|
||||||
config: RJSVM_Config;
|
|
||||||
definitions: RJSVM_Implementations<any, Definitions_T>;
|
|
||||||
connect: () => Promise<void>;
|
|
||||||
}
|
|
||||||
export type Generic_Ctor_ReturnType<Ctor> = Ctor extends new (...args: any) => infer T ? T : Ctor extends abstract new (...args: any) => infer A ? A : never;
|
|
||||||
export type State_Of<T extends RJSVM<any>> = T extends RJSVM<infer State_T> ? State_T : any;
|
|
||||||
export type Endpoints_Of<T extends RJSVM<any, any>> = T extends RJSVM<any, infer Endpoints_T> ? Endpoints_T : any;
|
|
||||||
export type PaymentTx_T = {
|
|
||||||
Account: string;
|
|
||||||
Amount: string;
|
|
||||||
Destination: string;
|
|
||||||
Fee: string;
|
|
||||||
Flags: number;
|
|
||||||
LastLedgerSequence: number;
|
|
||||||
Memos: any[];
|
|
||||||
Sequence: number;
|
|
||||||
SigningPubKey: string;
|
|
||||||
TransactionType: 'Payment';
|
|
||||||
TxnSignature: string;
|
|
||||||
date: number;
|
|
||||||
hash: string;
|
|
||||||
inLedger: number;
|
|
||||||
ledger_index: number;
|
|
||||||
};
|
|
||||||
export type ParameterizedFunction = (...args: any) => void;
|
|
||||||
export type Function_Map = {
|
|
||||||
[K in string]: ParameterizedFunction;
|
|
||||||
};
|
|
||||||
export type RJSVM_Endpoint<RJSVM_T extends RJSVM<any, Definitions_T>, Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>, Impl extends RJSVM_EndpointHandler<RJSVM_T, Definitions_T, ParameterizedFunction> = RJSVM_EndpointHandler<RJSVM_T, Definitions_T, ParameterizedFunction>> = {
|
|
||||||
implementation: Impl;
|
|
||||||
visibility: 'owner' | 'public';
|
|
||||||
fee?: number;
|
|
||||||
parameterSchema: z.Schema;
|
|
||||||
};
|
|
||||||
export type RJSVM_Implementations<RJSVM_T extends RJSVM<any, Definitions>, Definitions extends Function_Map = Endpoints_Of<RJSVM_T>> = {
|
|
||||||
[Key in keyof Definitions]: RJSVM_Endpoint<RJSVM_T, Definitions, RJSVM_EndpointHandler<RJSVM_T, Definitions, Definitions[Key]>>;
|
|
||||||
};
|
|
||||||
export type RJSVM_EndpointHandler<RJSVM_T extends RJSVM<any, Definitions_T>, Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>, Fn extends ParameterizedFunction = ParameterizedFunction> = (this: RJSVM_T & RJSVM_Interface<RJSVM_T, State_Of<RJSVM_T>, Definitions_T>, env: PaymentTx_T, ...args: Parameters<Fn>) => void;
|
|
||||||
export type RJSVM_Interface<RJSVM_T extends RJSVM<State_T, Definitions_T>, State_T = State_Of<RJSVM_T>, Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>> = {
|
|
||||||
state: State_T;
|
|
||||||
} & {
|
|
||||||
[K in keyof Definitions_T]?: RJSVM_EndpointHandler<RJSVM_T, Definitions_T, Definitions_T[K]>;
|
|
||||||
};
|
|
||||||
export type RJSVM_InitState<State_T> = {
|
|
||||||
owner: string;
|
|
||||||
state: State_T;
|
|
||||||
};
|
|
||||||
export type RJSVM_Config = {
|
|
||||||
rippleNode: string;
|
|
||||||
listeningAddress: string;
|
|
||||||
};
|
|
||||||
export declare const payloadSchema: z.ZodObject<{
|
|
||||||
endpoint: z.ZodString;
|
|
||||||
data: z.ZodString;
|
|
||||||
}, "strip", z.ZodTypeAny, {
|
|
||||||
endpoint?: string;
|
|
||||||
data?: string;
|
|
||||||
}, {
|
|
||||||
endpoint?: string;
|
|
||||||
data?: string;
|
|
||||||
}>;
|
|
||||||
export type Payload = z.infer<typeof payloadSchema>;
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.payloadSchema = exports.RJSVM = void 0;
|
|
||||||
const zod_1 = require("zod");
|
|
||||||
class RJSVM {
|
|
||||||
owner;
|
|
||||||
state;
|
|
||||||
sync_block_height;
|
|
||||||
config;
|
|
||||||
definitions;
|
|
||||||
connect;
|
|
||||||
}
|
|
||||||
exports.RJSVM = RJSVM;
|
|
||||||
exports.payloadSchema = zod_1.z.object({
|
|
||||||
endpoint: zod_1.z.string(),
|
|
||||||
data: zod_1.z.string()
|
|
||||||
});
|
|
||||||
Vendored
-15
@@ -1,15 +0,0 @@
|
|||||||
type Wallet = {
|
|
||||||
address: string;
|
|
||||||
secret: string;
|
|
||||||
};
|
|
||||||
type DatawriterConfig = {
|
|
||||||
receiveAddress: string;
|
|
||||||
sendWallet: Wallet;
|
|
||||||
xrpNode: string;
|
|
||||||
};
|
|
||||||
export declare class Datawriter {
|
|
||||||
private config;
|
|
||||||
constructor(config: DatawriterConfig);
|
|
||||||
callEndpoint(endpointName: string, contractAddress: string, parameter: any, fee?: number): Promise<void>;
|
|
||||||
}
|
|
||||||
export {};
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.Datawriter = void 0;
|
|
||||||
const xrpio_1 = require("xrpio");
|
|
||||||
class Datawriter {
|
|
||||||
config;
|
|
||||||
constructor(config) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
async callEndpoint(endpointName, contractAddress, parameter, fee) {
|
|
||||||
const xrpio = new xrpio_1.xrpIO(this.config.xrpNode);
|
|
||||||
await xrpio.connect();
|
|
||||||
try {
|
|
||||||
const dataHash = await xrpio.treeWrite(JSON.stringify(parameter), this.config.receiveAddress, this.config.sendWallet.secret);
|
|
||||||
await xrpio.writeRaw({
|
|
||||||
data: JSON.stringify({
|
|
||||||
endpoint: endpointName,
|
|
||||||
data: dataHash
|
|
||||||
})
|
|
||||||
}, contractAddress, this.config.sendWallet.secret, undefined, fee ? String(fee) : undefined);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
await xrpio.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.Datawriter = Datawriter;
|
|
||||||
(async () => {
|
|
||||||
const owner_dw = new Datawriter({
|
|
||||||
receiveAddress: "rDuXvMYNCEJCYDMFQykcafXhgi2NvMWqR",
|
|
||||||
sendWallet: {
|
|
||||||
address: "rUsPfG1hn6w6is28p5FUDWdMwvCo1iHrYq",
|
|
||||||
secret: "sEdTMicaTVmfsVMLhxrufyAzEQSnsaP"
|
|
||||||
},
|
|
||||||
xrpNode: "wss://s.altnet.rippletest.net:51233"
|
|
||||||
});
|
|
||||||
//await owner_dw.callEndpoint('submit', 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq', { title: "1", body: "2", from: "3" }, 100)
|
|
||||||
const user_dw = new Datawriter({
|
|
||||||
receiveAddress: "rwqCiEr3SLF43rAduhCChkR2K1XDhiqx5g",
|
|
||||||
sendWallet: {
|
|
||||||
address: "rHWN4X3hbodryX8H1EoPvmMV7AFHngEiBe",
|
|
||||||
secret: "sEdTdLPWvz69UAUmt1zYijTyWheER9u"
|
|
||||||
},
|
|
||||||
xrpNode: "wss://s.altnet.rippletest.net:51233"
|
|
||||||
});
|
|
||||||
//await owner_dw.callEndpoint('submit', 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq', { title: "1", body: "2", from: "3" }, 100)
|
|
||||||
//await user_dw.callEndpoint('restricted', 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq', { title: "user", body: "user", from: "user" })
|
|
||||||
//await owner_dw.callEndpoint('restricted', 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq', { title: "owner", body: "owner", from: "owner" })
|
|
||||||
await user_dw.callEndpoint('setTns', 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq', { hash: '01708abcF00636CE10E191FD782DBDC8F4076F28404BD88EBC31DE42DD084C0944B', name: 'test' });
|
|
||||||
})();
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
export * from "./RJSVM/framework/rjsvm";
|
|
||||||
export * from "./RJSVM/framework/types";
|
|
||||||
export * from "./util/dataparser";
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
||||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
__exportStar(require("./RJSVM/framework/rjsvm"), exports);
|
|
||||||
__exportStar(require("./RJSVM/framework/types"), exports);
|
|
||||||
__exportStar(require("./util/dataparser"), exports);
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
export {};
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const zod_1 = require("zod");
|
|
||||||
const types_1 = require("./RJSVM/framework/types");
|
|
||||||
const main_1 = require("./main");
|
|
||||||
const schemas_1 = require("./util/schemas");
|
|
||||||
const shoutSchema = zod_1.z.object({
|
|
||||||
title: zod_1.z.string(),
|
|
||||||
body: zod_1.z.string(),
|
|
||||||
from: zod_1.z.string(),
|
|
||||||
id: zod_1.z.optional(zod_1.z.string())
|
|
||||||
});
|
|
||||||
const tnsEntrySchema = zod_1.z.object({
|
|
||||||
hash: schemas_1.xrp_transaction_hash_schema,
|
|
||||||
name: zod_1.z.string(),
|
|
||||||
});
|
|
||||||
class RJSVM_Base extends types_1.RJSVM {
|
|
||||||
owner = "rUsPfG1hn6w6is28p5FUDWdMwvCo1iHrYq";
|
|
||||||
state = {
|
|
||||||
shouts: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const RJSVM_Contract = {
|
|
||||||
submit: {
|
|
||||||
implementation: function (env, shout) {
|
|
||||||
this.state.shouts.unshift(shout);
|
|
||||||
console.log(shout);
|
|
||||||
},
|
|
||||||
visibility: 'public',
|
|
||||||
fee: 10,
|
|
||||||
parameterSchema: shoutSchema
|
|
||||||
},
|
|
||||||
restricted: {
|
|
||||||
implementation: function (env, shout) {
|
|
||||||
this.state.shouts.unshift(shout);
|
|
||||||
console.log(shout);
|
|
||||||
},
|
|
||||||
visibility: 'owner',
|
|
||||||
parameterSchema: shoutSchema
|
|
||||||
},
|
|
||||||
setTns: {
|
|
||||||
implementation: function (env, tnsEntry) {
|
|
||||||
console.log(tnsEntry);
|
|
||||||
},
|
|
||||||
visibility: 'public',
|
|
||||||
parameterSchema: tnsEntrySchema,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const Rjsvm = main_1.RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract);
|
|
||||||
const conf = {
|
|
||||||
listeningAddress: "rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq",
|
|
||||||
rippleNode: "wss://s.altnet.rippletest.net:51233"
|
|
||||||
};
|
|
||||||
const rjsvm = new Rjsvm(conf);
|
|
||||||
rjsvm.connect();
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
export declare class DataParser {
|
|
||||||
static hex_to_ascii(input: any): string;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.DataParser = void 0;
|
|
||||||
class DataParser {
|
|
||||||
static hex_to_ascii(input) {
|
|
||||||
var hex = input.toString();
|
|
||||||
var str = '';
|
|
||||||
for (var n = 0; n < hex.length; n += 2) {
|
|
||||||
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.DataParser = DataParser;
|
|
||||||
Vendored
-15
@@ -1,15 +0,0 @@
|
|||||||
export declare const MSG_DELIM: string;
|
|
||||||
export declare const MSG_DATA_MAX: number;
|
|
||||||
export declare const PUBKEY_LEN: number;
|
|
||||||
export declare const NON_ZERO_TX_HASH: RegExp;
|
|
||||||
export declare const PTR_FORMAT: RegExp;
|
|
||||||
export declare const DATA_FORMAT: RegExp;
|
|
||||||
export declare const SIGNATURE_FORMAT: RegExp;
|
|
||||||
export declare const SIGNER_FORMAT: RegExp;
|
|
||||||
export declare const MSG_FORMAT: RegExp;
|
|
||||||
export declare const AMOUNT_DECIMALS = 18;
|
|
||||||
export declare const MAX_SUPPLY = 20000000;
|
|
||||||
export declare const AMOUNT_FORMAT: RegExp;
|
|
||||||
export declare const MIN_XRP_FEE = "0.00001";
|
|
||||||
export declare const MIN_XRP_TX_VALUE = "0.000001";
|
|
||||||
export declare const XRP_ADDRESS: RegExp;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.XRP_ADDRESS = exports.MIN_XRP_TX_VALUE = exports.MIN_XRP_FEE = exports.AMOUNT_FORMAT = exports.MAX_SUPPLY = exports.AMOUNT_DECIMALS = exports.MSG_FORMAT = exports.SIGNER_FORMAT = exports.SIGNATURE_FORMAT = exports.DATA_FORMAT = exports.PTR_FORMAT = exports.NON_ZERO_TX_HASH = exports.PUBKEY_LEN = exports.MSG_DATA_MAX = exports.MSG_DELIM = void 0;
|
|
||||||
exports.MSG_DELIM = ' ';
|
|
||||||
exports.MSG_DATA_MAX = 925;
|
|
||||||
exports.PUBKEY_LEN = 66;
|
|
||||||
exports.NON_ZERO_TX_HASH = new RegExp(`[0-9A-F]{64}`);
|
|
||||||
exports.PTR_FORMAT = new RegExp(`^((${exports.NON_ZERO_TX_HASH.source})|0)`);
|
|
||||||
exports.DATA_FORMAT = new RegExp(`(.{1,${exports.MSG_DATA_MAX}})`);
|
|
||||||
exports.SIGNATURE_FORMAT = new RegExp(`(\\S{140}|\\S{142})$`);
|
|
||||||
exports.SIGNER_FORMAT = new RegExp(`(\\S{${exports.PUBKEY_LEN}})`);
|
|
||||||
exports.MSG_FORMAT = new RegExp(`${exports.PTR_FORMAT.source}${exports.MSG_DELIM}${exports.DATA_FORMAT.source}`, 'm');
|
|
||||||
exports.AMOUNT_DECIMALS = 18;
|
|
||||||
exports.MAX_SUPPLY = 20_000_000;
|
|
||||||
exports.AMOUNT_FORMAT = new RegExp(`\d+(\.\d{1,${exports.AMOUNT_DECIMALS}})?`);
|
|
||||||
exports.MIN_XRP_FEE = "0.00001";
|
|
||||||
exports.MIN_XRP_TX_VALUE = "0.000001";
|
|
||||||
exports.XRP_ADDRESS = new RegExp(`^([r])([1-9A-HJ-NP-Za-km-z]{24,34})`);
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
import { z } from "zod";
|
|
||||||
export declare const xrp_address_schema: z.ZodString;
|
|
||||||
export declare const xrp_transaction_hash_schema: z.ZodString;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.xrp_transaction_hash_schema = exports.xrp_address_schema = void 0;
|
|
||||||
const zod_1 = require("zod");
|
|
||||||
const protocol_constants_1 = require("./protocol.constants");
|
|
||||||
const xrpio_1 = require("xrpio");
|
|
||||||
exports.xrp_address_schema = zod_1.z.string().regex(protocol_constants_1.XRP_ADDRESS, "Not a valid XRP address");
|
|
||||||
exports.xrp_transaction_hash_schema = zod_1.z.string().regex(xrpio_1.NON_ZERO_TX_HASH, "Not a valid XRP transaction hash");
|
|
||||||
+1742
-20
File diff suppressed because it is too large
Load Diff
+28
@@ -1,3 +1,31 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.2.1](https://github.com/ljharb/define-properties/compare/v1.2.0...v1.2.1) - 2023-09-12
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [Refactor] use `define-data-property` [`e7782a7`](https://github.com/ljharb/define-properties/commit/e7782a7480a62f8b6e141b49371e6de4df176c97)
|
||||||
|
- [actions] use reusable rebase action [`cd249c3`](https://github.com/ljharb/define-properties/commit/cd249c3920607bc8eeb7c0cd5b672b810983cac5)
|
||||||
|
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`8205f97`](https://github.com/ljharb/define-properties/commit/8205f9734a4da8ee5b3b29798788567a09b330e8)
|
||||||
|
|
||||||
|
## [v1.2.0](https://github.com/ljharb/define-properties/compare/v1.1.4...v1.2.0) - 2023-02-10
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [New] if the predicate is boolean `true`, it compares the existing value with `===` as the predicate [`d8dd6fc`](https://github.com/ljharb/define-properties/commit/d8dd6fca40d7c5878a4b643b91e66ae5a513a194)
|
||||||
|
- [meta] add `auto-changelog` [`7ebe2b0`](https://github.com/ljharb/define-properties/commit/7ebe2b0a0f90e62b842942cd45e86864fe75d9f6)
|
||||||
|
- [meta] use `npmignore` to autogenerate an npmignore file [`647478a`](https://github.com/ljharb/define-properties/commit/647478a8401fbf053fb633c0a3a7c982da6bad74)
|
||||||
|
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`e620d70`](https://github.com/ljharb/define-properties/commit/e620d707d2e1118a38796f22a862200eb0a53fff)
|
||||||
|
- [Dev Deps] update `aud`, `tape` [`f1e5072`](https://github.com/ljharb/define-properties/commit/f1e507225c2551a99ed4fe40d3fe71b0f44acf88)
|
||||||
|
- [actions] update checkout action [`628b3af`](https://github.com/ljharb/define-properties/commit/628b3af5c74b8f0963296d811a8f6fa657baf964)
|
||||||
|
|
||||||
|
<!-- auto-changelog-above -->
|
||||||
|
|
||||||
1.1.4 / 2022-04-14
|
1.1.4 / 2022-04-14
|
||||||
=================
|
=================
|
||||||
* [Refactor] use `has-property-descriptors`
|
* [Refactor] use `has-property-descriptors`
|
||||||
|
|||||||
+12
-12
@@ -5,29 +5,29 @@ var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbo
|
|||||||
|
|
||||||
var toStr = Object.prototype.toString;
|
var toStr = Object.prototype.toString;
|
||||||
var concat = Array.prototype.concat;
|
var concat = Array.prototype.concat;
|
||||||
var origDefineProperty = Object.defineProperty;
|
var defineDataProperty = require('define-data-property');
|
||||||
|
|
||||||
var isFunction = function (fn) {
|
var isFunction = function (fn) {
|
||||||
return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
|
return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
|
||||||
};
|
};
|
||||||
|
|
||||||
var hasPropertyDescriptors = require('has-property-descriptors')();
|
var supportsDescriptors = require('has-property-descriptors')();
|
||||||
|
|
||||||
var supportsDescriptors = origDefineProperty && hasPropertyDescriptors;
|
|
||||||
|
|
||||||
var defineProperty = function (object, name, value, predicate) {
|
var defineProperty = function (object, name, value, predicate) {
|
||||||
if (name in object && (!isFunction(predicate) || !predicate())) {
|
if (name in object) {
|
||||||
|
if (predicate === true) {
|
||||||
|
if (object[name] === value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (!isFunction(predicate) || !predicate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (supportsDescriptors) {
|
if (supportsDescriptors) {
|
||||||
origDefineProperty(object, name, {
|
defineDataProperty(object, name, value, true);
|
||||||
configurable: true,
|
|
||||||
enumerable: false,
|
|
||||||
value: value,
|
|
||||||
writable: true
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
object[name] = value; // eslint-disable-line no-param-reassign
|
defineDataProperty(object, name, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+27
-5
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "define-properties",
|
"name": "define-properties",
|
||||||
"version": "1.1.4",
|
"version": "1.2.1",
|
||||||
"author": "Jordan Harband <ljharb@gmail.com>",
|
"author": "Jordan Harband <ljharb@gmail.com>",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@@ -9,13 +9,16 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prepack": "npmignore --auto --commentLines=autogenerated",
|
||||||
"prepublish": "not-in-publish || npm run prepublishOnly",
|
"prepublish": "not-in-publish || npm run prepublishOnly",
|
||||||
"prepublishOnly": "safe-publish-latest",
|
"prepublishOnly": "safe-publish-latest",
|
||||||
"pretest": "npm run lint",
|
"pretest": "npm run lint",
|
||||||
"test": "npm run tests-only",
|
"test": "npm run tests-only",
|
||||||
"posttest": "aud --production",
|
"posttest": "aud --production",
|
||||||
"tests-only": "nyc tape 'test/**/*.js'",
|
"tests-only": "nyc tape 'test/**/*.js'",
|
||||||
"lint": "eslint --ext=js,mjs ."
|
"lint": "eslint --ext=js,mjs .",
|
||||||
|
"version": "auto-changelog && git add CHANGELOG.md",
|
||||||
|
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -31,16 +34,20 @@
|
|||||||
"ES5"
|
"ES5"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.0.1",
|
||||||
"has-property-descriptors": "^1.0.0",
|
"has-property-descriptors": "^1.0.0",
|
||||||
"object-keys": "^1.1.1"
|
"object-keys": "^1.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ljharb/eslint-config": "^21.0.0",
|
"@ljharb/eslint-config": "^21.1.0",
|
||||||
"aud": "^2.0.0",
|
"aud": "^2.0.3",
|
||||||
|
"auto-changelog": "^2.4.0",
|
||||||
"eslint": "=8.8.0",
|
"eslint": "=8.8.0",
|
||||||
|
"in-publish": "^2.0.1",
|
||||||
|
"npmignore": "^0.3.0",
|
||||||
"nyc": "^10.3.2",
|
"nyc": "^10.3.2",
|
||||||
"safe-publish-latest": "^2.0.0",
|
"safe-publish-latest": "^2.0.0",
|
||||||
"tape": "^5.5.3"
|
"tape": "^5.6.6"
|
||||||
},
|
},
|
||||||
"testling": {
|
"testling": {
|
||||||
"files": "test/index.js",
|
"files": "test/index.js",
|
||||||
@@ -62,5 +69,20 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"auto-changelog": {
|
||||||
|
"output": "CHANGELOG.md",
|
||||||
|
"template": "keepachangelog",
|
||||||
|
"unreleased": false,
|
||||||
|
"commitLimit": false,
|
||||||
|
"backfillLimit": false,
|
||||||
|
"hideCredit": true,
|
||||||
|
"startingVersion": "1.1.5"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"ignore": [
|
||||||
|
".github/workflows",
|
||||||
|
"test/"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -17,6 +17,7 @@
|
|||||||
"eqeqeq": [2, "allow-null"],
|
"eqeqeq": [2, "allow-null"],
|
||||||
"func-name-matching": 0,
|
"func-name-matching": 0,
|
||||||
"id-length": 0,
|
"id-length": 0,
|
||||||
|
"max-lines": 0,
|
||||||
"max-lines-per-function": [2, 90],
|
"max-lines-per-function": [2, 90],
|
||||||
"max-params": [2, 4],
|
"max-params": [2, 4],
|
||||||
"max-statements": 0,
|
"max-statements": 0,
|
||||||
|
|||||||
+19
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.2.1](https://github.com/ljharb/get-intrinsic/compare/v1.2.0...v1.2.1) - 2023-05-13
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [Fix] avoid a crash in envs without `__proto__` [`7bad8d0`](https://github.com/ljharb/get-intrinsic/commit/7bad8d061bf8721733b58b73a2565af2b6756b64)
|
||||||
|
- [Dev Deps] update `es-abstract` [`c60e6b7`](https://github.com/ljharb/get-intrinsic/commit/c60e6b7b4cf9660c7f27ed970970fd55fac48dc5)
|
||||||
|
|
||||||
|
## [v1.2.0](https://github.com/ljharb/get-intrinsic/compare/v1.1.3...v1.2.0) - 2023-01-19
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [actions] update checkout action [`ca6b12f`](https://github.com/ljharb/get-intrinsic/commit/ca6b12f31eaacea4ea3b055e744cd61623385ffb)
|
||||||
|
- [Dev Deps] update `@ljharb/eslint-config`, `es-abstract`, `object-inspect`, `tape` [`41a3727`](https://github.com/ljharb/get-intrinsic/commit/41a3727d0026fa04273ae216a5f8e12eefd72da8)
|
||||||
|
- [Fix] ensure `Error.prototype` is undeniable [`c511e97`](https://github.com/ljharb/get-intrinsic/commit/c511e97ae99c764c4524b540dee7a70757af8da3)
|
||||||
|
- [Dev Deps] update `aud`, `es-abstract`, `tape` [`1bef8a8`](https://github.com/ljharb/get-intrinsic/commit/1bef8a8fd439ebb80863199b6189199e0851ac67)
|
||||||
|
- [Dev Deps] update `aud`, `es-abstract` [`0d41f16`](https://github.com/ljharb/get-intrinsic/commit/0d41f16bcd500bc28b7bfc98043ebf61ea081c26)
|
||||||
|
- [New] add `BigInt64Array` and `BigUint64Array` [`a6cca25`](https://github.com/ljharb/get-intrinsic/commit/a6cca25f29635889b7e9bd669baf9e04be90e48c)
|
||||||
|
- [Tests] use `gopd` [`ecf7722`](https://github.com/ljharb/get-intrinsic/commit/ecf7722240d15cfd16edda06acf63359c10fb9bd)
|
||||||
|
|
||||||
## [v1.1.3](https://github.com/ljharb/get-intrinsic/compare/v1.1.2...v1.1.3) - 2022-09-12
|
## [v1.1.3](https://github.com/ljharb/get-intrinsic/compare/v1.1.2...v1.1.3) - 2022-09-12
|
||||||
|
|
||||||
### Commits
|
### Commits
|
||||||
|
|||||||
+25
-8
@@ -43,18 +43,23 @@ var ThrowTypeError = $gOPD
|
|||||||
: throwTypeError;
|
: throwTypeError;
|
||||||
|
|
||||||
var hasSymbols = require('has-symbols')();
|
var hasSymbols = require('has-symbols')();
|
||||||
|
var hasProto = require('has-proto')();
|
||||||
|
|
||||||
var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto
|
var getProto = Object.getPrototypeOf || (
|
||||||
|
hasProto
|
||||||
|
? function (x) { return x.__proto__; } // eslint-disable-line no-proto
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
var needsEval = {};
|
var needsEval = {};
|
||||||
|
|
||||||
var TypedArray = typeof Uint8Array === 'undefined' ? undefined : getProto(Uint8Array);
|
var TypedArray = typeof Uint8Array === 'undefined' || !getProto ? undefined : getProto(Uint8Array);
|
||||||
|
|
||||||
var INTRINSICS = {
|
var INTRINSICS = {
|
||||||
'%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError,
|
'%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError,
|
||||||
'%Array%': Array,
|
'%Array%': Array,
|
||||||
'%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer,
|
'%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer,
|
||||||
'%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined,
|
'%ArrayIteratorPrototype%': hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined,
|
||||||
'%AsyncFromSyncIteratorPrototype%': undefined,
|
'%AsyncFromSyncIteratorPrototype%': undefined,
|
||||||
'%AsyncFunction%': needsEval,
|
'%AsyncFunction%': needsEval,
|
||||||
'%AsyncGenerator%': needsEval,
|
'%AsyncGenerator%': needsEval,
|
||||||
@@ -62,6 +67,8 @@ var INTRINSICS = {
|
|||||||
'%AsyncIteratorPrototype%': needsEval,
|
'%AsyncIteratorPrototype%': needsEval,
|
||||||
'%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics,
|
'%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics,
|
||||||
'%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt,
|
'%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt,
|
||||||
|
'%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined : BigInt64Array,
|
||||||
|
'%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined : BigUint64Array,
|
||||||
'%Boolean%': Boolean,
|
'%Boolean%': Boolean,
|
||||||
'%DataView%': typeof DataView === 'undefined' ? undefined : DataView,
|
'%DataView%': typeof DataView === 'undefined' ? undefined : DataView,
|
||||||
'%Date%': Date,
|
'%Date%': Date,
|
||||||
@@ -82,10 +89,10 @@ var INTRINSICS = {
|
|||||||
'%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array,
|
'%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array,
|
||||||
'%isFinite%': isFinite,
|
'%isFinite%': isFinite,
|
||||||
'%isNaN%': isNaN,
|
'%isNaN%': isNaN,
|
||||||
'%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined,
|
'%IteratorPrototype%': hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined,
|
||||||
'%JSON%': typeof JSON === 'object' ? JSON : undefined,
|
'%JSON%': typeof JSON === 'object' ? JSON : undefined,
|
||||||
'%Map%': typeof Map === 'undefined' ? undefined : Map,
|
'%Map%': typeof Map === 'undefined' ? undefined : Map,
|
||||||
'%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined : getProto(new Map()[Symbol.iterator]()),
|
'%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Map()[Symbol.iterator]()),
|
||||||
'%Math%': Math,
|
'%Math%': Math,
|
||||||
'%Number%': Number,
|
'%Number%': Number,
|
||||||
'%Object%': Object,
|
'%Object%': Object,
|
||||||
@@ -98,10 +105,10 @@ var INTRINSICS = {
|
|||||||
'%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect,
|
'%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect,
|
||||||
'%RegExp%': RegExp,
|
'%RegExp%': RegExp,
|
||||||
'%Set%': typeof Set === 'undefined' ? undefined : Set,
|
'%Set%': typeof Set === 'undefined' ? undefined : Set,
|
||||||
'%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined : getProto(new Set()[Symbol.iterator]()),
|
'%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Set()[Symbol.iterator]()),
|
||||||
'%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer,
|
'%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer,
|
||||||
'%String%': String,
|
'%String%': String,
|
||||||
'%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined,
|
'%StringIteratorPrototype%': hasSymbols && getProto ? getProto(''[Symbol.iterator]()) : undefined,
|
||||||
'%Symbol%': hasSymbols ? Symbol : undefined,
|
'%Symbol%': hasSymbols ? Symbol : undefined,
|
||||||
'%SyntaxError%': $SyntaxError,
|
'%SyntaxError%': $SyntaxError,
|
||||||
'%ThrowTypeError%': ThrowTypeError,
|
'%ThrowTypeError%': ThrowTypeError,
|
||||||
@@ -117,6 +124,16 @@ var INTRINSICS = {
|
|||||||
'%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet
|
'%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (getProto) {
|
||||||
|
try {
|
||||||
|
null.error; // eslint-disable-line no-unused-expressions
|
||||||
|
} catch (e) {
|
||||||
|
// https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229
|
||||||
|
var errorProto = getProto(getProto(e));
|
||||||
|
INTRINSICS['%Error.prototype%'] = errorProto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var doEval = function doEval(name) {
|
var doEval = function doEval(name) {
|
||||||
var value;
|
var value;
|
||||||
if (name === '%AsyncFunction%') {
|
if (name === '%AsyncFunction%') {
|
||||||
@@ -132,7 +149,7 @@ var doEval = function doEval(name) {
|
|||||||
}
|
}
|
||||||
} else if (name === '%AsyncIteratorPrototype%') {
|
} else if (name === '%AsyncIteratorPrototype%') {
|
||||||
var gen = doEval('%AsyncGenerator%');
|
var gen = doEval('%AsyncGenerator%');
|
||||||
if (gen) {
|
if (gen && getProto) {
|
||||||
value = getProto(gen.prototype);
|
value = getProto(gen.prototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "get-intrinsic",
|
"name": "get-intrinsic",
|
||||||
"version": "1.1.3",
|
"version": "1.2.1",
|
||||||
"description": "Get and robustly cache all JS language-level intrinsics at first require time",
|
"description": "Get and robustly cache all JS language-level intrinsics at first require time",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -48,24 +48,25 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/ljharb/get-intrinsic#readme",
|
"homepage": "https://github.com/ljharb/get-intrinsic#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ljharb/eslint-config": "^21.0.0",
|
"@ljharb/eslint-config": "^21.0.1",
|
||||||
"aud": "^2.0.0",
|
"aud": "^2.0.2",
|
||||||
"auto-changelog": "^2.4.0",
|
"auto-changelog": "^2.4.0",
|
||||||
"call-bind": "^1.0.2",
|
"call-bind": "^1.0.2",
|
||||||
"es-abstract": "^1.20.2",
|
"es-abstract": "^1.21.2",
|
||||||
"es-value-fixtures": "^1.4.2",
|
"es-value-fixtures": "^1.4.2",
|
||||||
"eslint": "=8.8.0",
|
"eslint": "=8.8.0",
|
||||||
"evalmd": "^0.0.19",
|
"evalmd": "^0.0.19",
|
||||||
"for-each": "^0.3.3",
|
"for-each": "^0.3.3",
|
||||||
|
"gopd": "^1.0.1",
|
||||||
"make-async-function": "^1.0.0",
|
"make-async-function": "^1.0.0",
|
||||||
"make-async-generator-function": "^1.0.0",
|
"make-async-generator-function": "^1.0.0",
|
||||||
"make-generator-function": "^2.0.0",
|
"make-generator-function": "^2.0.0",
|
||||||
"mock-property": "^1.0.0",
|
"mock-property": "^1.0.0",
|
||||||
"npmignore": "^0.3.0",
|
"npmignore": "^0.3.0",
|
||||||
"nyc": "^10.3.2",
|
"nyc": "^10.3.2",
|
||||||
"object-inspect": "^1.12.2",
|
"object-inspect": "^1.12.3",
|
||||||
"safe-publish-latest": "^2.0.0",
|
"safe-publish-latest": "^2.0.0",
|
||||||
"tape": "^5.6.0"
|
"tape": "^5.6.3"
|
||||||
},
|
},
|
||||||
"auto-changelog": {
|
"auto-changelog": {
|
||||||
"output": "CHANGELOG.md",
|
"output": "CHANGELOG.md",
|
||||||
@@ -78,6 +79,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
|
"has-proto": "^1.0.1",
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
},
|
},
|
||||||
"testling": {
|
"testling": {
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ var mockProperty = require('mock-property');
|
|||||||
|
|
||||||
var callBound = require('call-bind/callBound');
|
var callBound = require('call-bind/callBound');
|
||||||
var v = require('es-value-fixtures');
|
var v = require('es-value-fixtures');
|
||||||
var $gOPD = require('es-abstract/helpers/getOwnPropertyDescriptor');
|
var $gOPD = require('gopd');
|
||||||
var DefinePropertyOrThrow = require('es-abstract/2021/DefinePropertyOrThrow');
|
var DefinePropertyOrThrow = require('es-abstract/2021/DefinePropertyOrThrow');
|
||||||
|
|
||||||
var $isProto = callBound('%Object.prototype.isPrototypeOf%');
|
var $isProto = callBound('%Object.prototype.isPrototypeOf%');
|
||||||
|
|||||||
+14
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.1.12](https://github.com/inspect-js/is-typed-array/compare/v1.1.11...v1.1.12) - 2023-07-17
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [Refactor] use `which-typed-array` for all internals [`7619405`](https://github.com/inspect-js/is-typed-array/commit/761940532de595f6721fed101b02814dcfa7fe4e)
|
||||||
|
|
||||||
|
## [v1.1.11](https://github.com/inspect-js/is-typed-array/compare/v1.1.10...v1.1.11) - 2023-07-17
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [Fix] `node < v0.6` lacks proper Object toString behavior [`c94b90d`](https://github.com/inspect-js/is-typed-array/commit/c94b90dc6bc457783d6f8cc208415a49da0933b7)
|
||||||
|
- [Robustness] use `call-bind` [`573b00b`](https://github.com/inspect-js/is-typed-array/commit/573b00b8deec42ac1ac262415e442ea0b7e1c96b)
|
||||||
|
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `object-inspect`, `tape` [`c88c2d4`](https://github.com/inspect-js/is-typed-array/commit/c88c2d479976110478fa4038fe8921251c06a163)
|
||||||
|
|
||||||
## [v1.1.10](https://github.com/inspect-js/is-typed-array/compare/v1.1.9...v1.1.10) - 2022-11-02
|
## [v1.1.10](https://github.com/inspect-js/is-typed-array/compare/v1.1.9...v1.1.10) - 2022-11-02
|
||||||
|
|
||||||
### Commits
|
### Commits
|
||||||
|
|||||||
+2
-55
@@ -1,60 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var forEach = require('for-each');
|
var whichTypedArray = require('which-typed-array');
|
||||||
var availableTypedArrays = require('available-typed-arrays');
|
|
||||||
var callBound = require('call-bind/callBound');
|
|
||||||
|
|
||||||
var $toString = callBound('Object.prototype.toString');
|
|
||||||
var hasToStringTag = require('has-tostringtag/shams')();
|
|
||||||
var gOPD = require('gopd');
|
|
||||||
|
|
||||||
var g = typeof globalThis === 'undefined' ? global : globalThis;
|
|
||||||
var typedArrays = availableTypedArrays();
|
|
||||||
|
|
||||||
var $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) {
|
|
||||||
for (var i = 0; i < array.length; i += 1) {
|
|
||||||
if (array[i] === value) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
var $slice = callBound('String.prototype.slice');
|
|
||||||
var toStrTags = {};
|
|
||||||
var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');
|
|
||||||
if (hasToStringTag && gOPD && getPrototypeOf) {
|
|
||||||
forEach(typedArrays, function (typedArray) {
|
|
||||||
var arr = new g[typedArray]();
|
|
||||||
if (Symbol.toStringTag in arr) {
|
|
||||||
var proto = getPrototypeOf(arr);
|
|
||||||
var descriptor = gOPD(proto, Symbol.toStringTag);
|
|
||||||
if (!descriptor) {
|
|
||||||
var superProto = getPrototypeOf(proto);
|
|
||||||
descriptor = gOPD(superProto, Symbol.toStringTag);
|
|
||||||
}
|
|
||||||
toStrTags[typedArray] = descriptor.get;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var tryTypedArrays = function tryAllTypedArrays(value) {
|
|
||||||
var anyTrue = false;
|
|
||||||
forEach(toStrTags, function (getter, typedArray) {
|
|
||||||
if (!anyTrue) {
|
|
||||||
try {
|
|
||||||
anyTrue = getter.call(value) === typedArray;
|
|
||||||
} catch (e) { /**/ }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return anyTrue;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function isTypedArray(value) {
|
module.exports = function isTypedArray(value) {
|
||||||
if (!value || typeof value !== 'object') { return false; }
|
return !!whichTypedArray(value);
|
||||||
if (!hasToStringTag || !(Symbol.toStringTag in value)) {
|
|
||||||
var tag = $slice($toString(value), 8, -1);
|
|
||||||
return $indexOf(typedArrays, tag) > -1;
|
|
||||||
}
|
|
||||||
if (!gOPD) { return false; }
|
|
||||||
return tryTypedArrays(value);
|
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-10
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "is-typed-array",
|
"name": "is-typed-array",
|
||||||
"version": "1.1.10",
|
"version": "1.1.12",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Jordan Harband",
|
"name": "Jordan Harband",
|
||||||
"email": "ljharb@gmail.com",
|
"email": "ljharb@gmail.com",
|
||||||
@@ -58,27 +58,25 @@
|
|||||||
"@@toStringTag"
|
"@@toStringTag"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"available-typed-arrays": "^1.0.5",
|
"which-typed-array": "^1.1.11"
|
||||||
"call-bind": "^1.0.2",
|
|
||||||
"for-each": "^0.3.3",
|
|
||||||
"gopd": "^1.0.1",
|
|
||||||
"has-tostringtag": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ljharb/eslint-config": "^21.0.0",
|
"@ljharb/eslint-config": "^21.1.0",
|
||||||
"aud": "^2.0.1",
|
"aud": "^2.0.3",
|
||||||
"auto-changelog": "^2.4.0",
|
"auto-changelog": "^2.4.0",
|
||||||
"eslint": "=8.8.0",
|
"eslint": "=8.8.0",
|
||||||
"evalmd": "^0.0.19",
|
"evalmd": "^0.0.19",
|
||||||
|
"for-each": "^0.3.3",
|
||||||
|
"has-tostringtag": "^1.0.0",
|
||||||
"in-publish": "^2.0.1",
|
"in-publish": "^2.0.1",
|
||||||
"is-callable": "^1.2.7",
|
"is-callable": "^1.2.7",
|
||||||
"make-arrow-function": "^1.2.0",
|
"make-arrow-function": "^1.2.0",
|
||||||
"make-generator-function": "^2.0.0",
|
"make-generator-function": "^2.0.0",
|
||||||
"npmignore": "^0.3.0",
|
"npmignore": "^0.3.0",
|
||||||
"nyc": "^10.3.2",
|
"nyc": "^10.3.2",
|
||||||
"object-inspect": "^1.12.2",
|
"object-inspect": "^1.12.3",
|
||||||
"safe-publish-latest": "^2.0.0",
|
"safe-publish-latest": "^2.0.0",
|
||||||
"tape": "^5.6.1"
|
"tape": "^5.6.5"
|
||||||
},
|
},
|
||||||
"testling": {
|
"testling": {
|
||||||
"files": "test/index.js",
|
"files": "test/index.js",
|
||||||
|
|||||||
+15
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.1.11](https://github.com/inspect-js/which-typed-array/compare/v1.1.10...v1.1.11) - 2023-07-17
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [Fix] `node < v0.6` lacks proper Object toString behavior [`b8fd654`](https://github.com/inspect-js/which-typed-array/commit/b8fd65479c0bd18385378cfae79750ebf7cb6ee7)
|
||||||
|
- [Dev Deps] update `tape` [`e1734c9`](https://github.com/inspect-js/which-typed-array/commit/e1734c99d79880ab11efa55220498a7a1e887834)
|
||||||
|
|
||||||
|
## [v1.1.10](https://github.com/inspect-js/which-typed-array/compare/v1.1.9...v1.1.10) - 2023-07-10
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
- [actions] update rebase action to use reusable workflow [`2c10582`](https://github.com/inspect-js/which-typed-array/commit/2c105820d77274c079cb6d040cb348396e516ef5)
|
||||||
|
- [Robustness] use `call-bind` [`b2335fd`](https://github.com/inspect-js/which-typed-array/commit/b2335fdfca80840995eea5e6fcfffc6d712279a1)
|
||||||
|
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`ad5e41b`](https://github.com/inspect-js/which-typed-array/commit/ad5e41ba18e7d23af1f9b211215c43a64bf75d70)
|
||||||
|
|
||||||
## [v1.1.9](https://github.com/inspect-js/which-typed-array/compare/v1.1.8...v1.1.9) - 2022-11-02
|
## [v1.1.9](https://github.com/inspect-js/which-typed-array/compare/v1.1.8...v1.1.9) - 2022-11-02
|
||||||
|
|
||||||
### Commits
|
### Commits
|
||||||
|
|||||||
+49
-15
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
var forEach = require('for-each');
|
var forEach = require('for-each');
|
||||||
var availableTypedArrays = require('available-typed-arrays');
|
var availableTypedArrays = require('available-typed-arrays');
|
||||||
|
var callBind = require('call-bind');
|
||||||
var callBound = require('call-bind/callBound');
|
var callBound = require('call-bind/callBound');
|
||||||
var gOPD = require('gopd');
|
var gOPD = require('gopd');
|
||||||
|
|
||||||
@@ -12,11 +13,19 @@ var g = typeof globalThis === 'undefined' ? global : globalThis;
|
|||||||
var typedArrays = availableTypedArrays();
|
var typedArrays = availableTypedArrays();
|
||||||
|
|
||||||
var $slice = callBound('String.prototype.slice');
|
var $slice = callBound('String.prototype.slice');
|
||||||
var toStrTags = {};
|
|
||||||
var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');
|
var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');
|
||||||
|
|
||||||
|
var $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) {
|
||||||
|
for (var i = 0; i < array.length; i += 1) {
|
||||||
|
if (array[i] === value) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
var cache = { __proto__: null };
|
||||||
if (hasToStringTag && gOPD && getPrototypeOf) {
|
if (hasToStringTag && gOPD && getPrototypeOf) {
|
||||||
forEach(typedArrays, function (typedArray) {
|
forEach(typedArrays, function (typedArray) {
|
||||||
if (typeof g[typedArray] === 'function') {
|
|
||||||
var arr = new g[typedArray]();
|
var arr = new g[typedArray]();
|
||||||
if (Symbol.toStringTag in arr) {
|
if (Symbol.toStringTag in arr) {
|
||||||
var proto = getPrototypeOf(arr);
|
var proto = getPrototypeOf(arr);
|
||||||
@@ -25,31 +34,56 @@ if (hasToStringTag && gOPD && getPrototypeOf) {
|
|||||||
var superProto = getPrototypeOf(proto);
|
var superProto = getPrototypeOf(proto);
|
||||||
descriptor = gOPD(superProto, Symbol.toStringTag);
|
descriptor = gOPD(superProto, Symbol.toStringTag);
|
||||||
}
|
}
|
||||||
toStrTags[typedArray] = descriptor.get;
|
cache['$' + typedArray] = callBind(descriptor.get);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
forEach(typedArrays, function (typedArray) {
|
||||||
|
var arr = new g[typedArray]();
|
||||||
|
cache['$' + typedArray] = callBind(arr.slice);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var tryTypedArrays = function tryAllTypedArrays(value) {
|
var tryTypedArrays = function tryAllTypedArrays(value) {
|
||||||
var foundName = false;
|
var found = false;
|
||||||
forEach(toStrTags, function (getter, typedArray) {
|
forEach(cache, function (getter, typedArray) {
|
||||||
if (!foundName) {
|
if (!found) {
|
||||||
try {
|
try {
|
||||||
var name = getter.call(value);
|
if ('$' + getter(value) === typedArray) {
|
||||||
if (name === typedArray) {
|
found = $slice(typedArray, 1);
|
||||||
foundName = name;
|
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) { /**/ }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return foundName;
|
return found;
|
||||||
};
|
};
|
||||||
|
|
||||||
var isTypedArray = require('is-typed-array');
|
var trySlices = function tryAllSlices(value) {
|
||||||
|
var found = false;
|
||||||
|
forEach(cache, function (getter, name) {
|
||||||
|
if (!found) {
|
||||||
|
try {
|
||||||
|
getter(value);
|
||||||
|
found = $slice(name, 1);
|
||||||
|
} catch (e) { /**/ }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = function whichTypedArray(value) {
|
module.exports = function whichTypedArray(value) {
|
||||||
if (!isTypedArray(value)) { return false; }
|
if (!value || typeof value !== 'object') { return false; }
|
||||||
if (!hasToStringTag || !(Symbol.toStringTag in value)) { return $slice($toString(value), 8, -1); }
|
if (!hasToStringTag) {
|
||||||
|
var tag = $slice($toString(value), 8, -1);
|
||||||
|
if ($indexOf(typedArrays, tag) > -1) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
if (tag !== 'Object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// node < 0.6 hits here on real Typed Arrays
|
||||||
|
return trySlices(value);
|
||||||
|
}
|
||||||
|
if (!gOPD) { return null; } // unknown engine
|
||||||
return tryTypedArrays(value);
|
return tryTypedArrays(value);
|
||||||
};
|
};
|
||||||
|
|||||||
+5
-6
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "which-typed-array",
|
"name": "which-typed-array",
|
||||||
"version": "1.1.9",
|
"version": "1.1.11",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Jordan Harband",
|
"name": "Jordan Harband",
|
||||||
"email": "ljharb@gmail.com",
|
"email": "ljharb@gmail.com",
|
||||||
@@ -62,12 +62,11 @@
|
|||||||
"call-bind": "^1.0.2",
|
"call-bind": "^1.0.2",
|
||||||
"for-each": "^0.3.3",
|
"for-each": "^0.3.3",
|
||||||
"gopd": "^1.0.1",
|
"gopd": "^1.0.1",
|
||||||
"has-tostringtag": "^1.0.0",
|
"has-tostringtag": "^1.0.0"
|
||||||
"is-typed-array": "^1.1.10"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ljharb/eslint-config": "^21.0.0",
|
"@ljharb/eslint-config": "^21.1.0",
|
||||||
"aud": "^2.0.1",
|
"aud": "^2.0.3",
|
||||||
"auto-changelog": "^2.4.0",
|
"auto-changelog": "^2.4.0",
|
||||||
"eslint": "=8.8.0",
|
"eslint": "=8.8.0",
|
||||||
"in-publish": "^2.0.1",
|
"in-publish": "^2.0.1",
|
||||||
@@ -77,7 +76,7 @@
|
|||||||
"npmignore": "^0.3.0",
|
"npmignore": "^0.3.0",
|
||||||
"nyc": "^10.3.2",
|
"nyc": "^10.3.2",
|
||||||
"safe-publish-latest": "^2.0.0",
|
"safe-publish-latest": "^2.0.0",
|
||||||
"tape": "^5.6.1"
|
"tape": "^5.6.5"
|
||||||
},
|
},
|
||||||
"testling": {
|
"testling": {
|
||||||
"files": "test/index.js",
|
"files": "test/index.js",
|
||||||
|
|||||||
+1
-1
@@ -90,7 +90,7 @@ test('Typed Arrays', function (t) {
|
|||||||
var TypedArray = global[typedArray];
|
var TypedArray = global[typedArray];
|
||||||
if (isCallable(TypedArray)) {
|
if (isCallable(TypedArray)) {
|
||||||
var arr = new TypedArray(10);
|
var arr = new TypedArray(10);
|
||||||
t.equal(typedArray, whichTypedArray(arr), 'new ' + typedArray + '(10) is typed array of type ' + typedArray);
|
t.equal(whichTypedArray(arr), typedArray, 'new ' + typedArray + '(10) is typed array of type ' + typedArray);
|
||||||
} else {
|
} else {
|
||||||
t.comment('# SKIP ' + typedArray + ' is not supported');
|
t.comment('# SKIP ' + typedArray + ' is not supported');
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+3078
-40
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
"start": "npm run build && npm run launch",
|
"start": "npm run build && npm run launch",
|
||||||
"build": "npm run clean && npm run tsc",
|
"build": "npm run clean && npm run tsc",
|
||||||
"launch": "node lib/launcher.js",
|
"launch": "node lib/launcher.js",
|
||||||
|
"test": "npm run clean && npm run build && mocha --bail=true lib/test/Test.js",
|
||||||
"tsc": "tsc"
|
"tsc": "tsc"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -18,7 +19,14 @@
|
|||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/chai": "^4.3.6",
|
||||||
|
"@types/expect": "^1.20.4",
|
||||||
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "^18.11.9",
|
"@types/node": "^18.11.9",
|
||||||
|
"chai": "^4.3.4",
|
||||||
|
"chai-as-promised": "^7.1.1",
|
||||||
|
"mocha": "^6.2.0",
|
||||||
|
"ts-mocha": "^6.0.0",
|
||||||
"typescript": "^4.9.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { xrpIO } from "xrpio";
|
||||||
|
|
||||||
|
type Wallet = {
|
||||||
|
address: string,
|
||||||
|
secret: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatawriterConfig = {
|
||||||
|
receiveAddress: string
|
||||||
|
sendWallet: Wallet
|
||||||
|
xrpNode: string
|
||||||
|
contractAddress: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Datawriter {
|
||||||
|
|
||||||
|
constructor(private config: DatawriterConfig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async callEndpoint(endpointName: string, parameter: any, fee?: number) {
|
||||||
|
const xrpio: xrpIO = new xrpIO(this.config.xrpNode)
|
||||||
|
await xrpio.connect()
|
||||||
|
try{
|
||||||
|
const dataHash = await xrpio.treeWrite(
|
||||||
|
JSON.stringify(parameter),
|
||||||
|
this.config.receiveAddress,
|
||||||
|
this.config.sendWallet.secret
|
||||||
|
)
|
||||||
|
const hash = await xrpio.writeRaw(
|
||||||
|
{
|
||||||
|
data: JSON.stringify({
|
||||||
|
endpoint: endpointName,
|
||||||
|
data: dataHash
|
||||||
|
})
|
||||||
|
},
|
||||||
|
this.config.contractAddress,
|
||||||
|
this.config.sendWallet.secret,
|
||||||
|
undefined,
|
||||||
|
fee ? String(fee) : undefined
|
||||||
|
)
|
||||||
|
}catch(e){
|
||||||
|
console.log(e)
|
||||||
|
}finally{
|
||||||
|
await xrpio.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { PaymentTx_T, ParameterizedFunction, Payload, RJSVM, RJSVM_Config, RJSVM_Endpoint, RJSVM_Implementations, payloadSchema, Function_Map, Endpoints_Of, State_Of, Generic_Ctor_ReturnType } from "./types"
|
import { PaymentTx_T, ParameterizedFunction, Payload, RJSVM, RJSVM_Config, RJSVM_Implementations, Function_Map, Endpoints_Of, State_Of, Generic_Ctor_ReturnType, RJSVM_Endpoint } from "./types"
|
||||||
import { Client as Xrpl } from 'xrpl';
|
import { Client as Xrpl } from 'xrpl';
|
||||||
import { xrpIO } from 'xrpio';
|
import { xrpIO } from 'xrpio';
|
||||||
import { DataParser } from "../../util/dataparser";
|
import { DataParser } from "../../util/dataparser";
|
||||||
import { XRP_ADDRESS } from "../../util/protocol.constants";
|
import { XRP_ADDRESS } from "../../util/protocol.constants";
|
||||||
|
import { payloadSchema } from "./schemas";
|
||||||
|
import { InsufficientFeeError, RestrictedAccessError } from "../../util/errors";
|
||||||
|
|
||||||
|
|
||||||
export abstract class RJSVM_Builder {
|
export abstract class RJSVM_Builder {
|
||||||
@@ -18,6 +20,10 @@ export abstract class RJSVM_Builder {
|
|||||||
|
|
||||||
private rippleApi: Xrpl
|
private rippleApi: Xrpl
|
||||||
private xrpIO: xrpIO
|
private xrpIO: xrpIO
|
||||||
|
private syncTimeout: NodeJS.Timeout
|
||||||
|
private subscribers = {}
|
||||||
|
private onceSubscribers = {}
|
||||||
|
|
||||||
public readonly definitions: Impl
|
public readonly definitions: Impl
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -27,7 +33,9 @@ export abstract class RJSVM_Builder {
|
|||||||
|
|
||||||
|
|
||||||
if(!XRP_ADDRESS.test(this.owner)){
|
if(!XRP_ADDRESS.test(this.owner)){
|
||||||
throw new Error(`Inavlid owner address ${this.owner}`)
|
const err = new Error(`Inavlid owner address ${this.owner}`)
|
||||||
|
this.emit('error', err)
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -45,18 +53,72 @@ export abstract class RJSVM_Builder {
|
|||||||
await this.xrpIO.connect()
|
await this.xrpIO.connect()
|
||||||
await this.sync()
|
await this.sync()
|
||||||
|
|
||||||
this.rippleApi.on('ledgerClosed', (ledger: any) => {
|
|
||||||
/*
|
/*
|
||||||
|
prototype for a new-block listener. would call on every closed ledger (i.e. new block)
|
||||||
|
could be used to implement limited lifetime states without requiring new events to trigger
|
||||||
|
|
||||||
|
this.rippleApi.on('ledgerClosed', (ledger: any) => {
|
||||||
console.log("---- Ledger ----")
|
console.log("---- Ledger ----")
|
||||||
console.log("index",ledger.ledger_index)
|
console.log("index",ledger.ledger_index)
|
||||||
console.log("hash", ledger.ledger_hash)
|
console.log("hash", ledger.ledger_hash)
|
||||||
console.log("---- /Ledger ----")
|
console.log("---- /Ledger ----")
|
||||||
*/
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.rippleApi.request({
|
await this.rippleApi.request({
|
||||||
command: 'subscribe',
|
command: 'subscribe',
|
||||||
streams: ['ledger']
|
streams: ['ledger']
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnect = async () => {
|
||||||
|
if(this.syncTimeout){
|
||||||
|
clearTimeout(this.syncTimeout)
|
||||||
|
this.syncTimeout = undefined
|
||||||
|
}
|
||||||
|
if(this.xrpIO){
|
||||||
|
await this.xrpIO.disconnect()
|
||||||
|
this.xrpIO = undefined
|
||||||
|
}
|
||||||
|
if(this.rippleApi){
|
||||||
|
await this.rippleApi.disconnect()
|
||||||
|
this.rippleApi = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscribers = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public on = (event: string, handler: ParameterizedFunction) => {
|
||||||
|
const availableEvents = ['error', ...Object.keys(this.definitions)]
|
||||||
|
if(!availableEvents.includes(event))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!this.subscribers[event])
|
||||||
|
this.subscribers[event] = []
|
||||||
|
|
||||||
|
this.subscribers[event].push(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public once = (event: string, handler: ParameterizedFunction) => {
|
||||||
|
const availableEvents = ['error', ...Object.keys(this.definitions)]
|
||||||
|
if(!availableEvents.includes(event))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!this.onceSubscribers[event])
|
||||||
|
this.onceSubscribers[event] = []
|
||||||
|
|
||||||
|
this.onceSubscribers[event].push(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
private emit = (event: string, payload: any) => {
|
||||||
|
if(this.subscribers[event])
|
||||||
|
this.subscribers[event].forEach(handler => handler(payload))
|
||||||
|
|
||||||
|
if(this.onceSubscribers[event]){
|
||||||
|
this.onceSubscribers[event].forEach(handler => handler(payload))
|
||||||
|
this.onceSubscribers[event] = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handlePayload = async (tx: PaymentTx_T, payload: Payload) => {
|
private handlePayload = async (tx: PaymentTx_T, payload: Payload) => {
|
||||||
@@ -66,14 +128,15 @@ export abstract class RJSVM_Builder {
|
|||||||
|
|
||||||
const endpointDef: RJSVM_Endpoint<RJSVM, any> = this.definitions[payload.endpoint]
|
const endpointDef: RJSVM_Endpoint<RJSVM, any> = this.definitions[payload.endpoint]
|
||||||
|
|
||||||
|
|
||||||
if(endpointDef.visibility === 'owner' && tx.Account !== this.owner){
|
if(endpointDef.visibility === 'owner' && tx.Account !== this.owner){
|
||||||
console.log(`owner restricted endpoint "${payload.endpoint}" called from ${tx.hash}. But ${tx.Account} != ${this.owner}`)
|
const err = new RestrictedAccessError(payload.endpoint, tx.hash, tx.Account, this.owner)
|
||||||
|
this.emit('error', err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(endpointDef.fee && Number(tx.Amount) < endpointDef.fee){
|
if(endpointDef.fee && Number(tx.Amount) < endpointDef.fee){
|
||||||
console.log(`Insufficient fee ${tx.hash}. Required ${endpointDef.fee}, was ${tx.Amount}`)
|
const err = new InsufficientFeeError(tx.hash, Number(endpointDef.fee), Number(tx.Amount))
|
||||||
|
this.emit('error', err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,8 +145,9 @@ export abstract class RJSVM_Builder {
|
|||||||
const jsonData = JSON.parse(data)
|
const jsonData = JSON.parse(data)
|
||||||
endpointDef.parameterSchema.parse(jsonData)
|
endpointDef.parameterSchema.parse(jsonData)
|
||||||
this[payload.endpoint].apply(this, [tx, jsonData])
|
this[payload.endpoint].apply(this, [tx, jsonData])
|
||||||
|
this.emit(payload.endpoint, jsonData)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
this.emit('error', err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +161,8 @@ export abstract class RJSVM_Builder {
|
|||||||
try {
|
try {
|
||||||
const data = DataParser.hex_to_ascii(memo.Memo.MemoData)
|
const data = DataParser.hex_to_ascii(memo.Memo.MemoData)
|
||||||
return JSON.parse(data)
|
return JSON.parse(data)
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
this.emit('error', err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -106,7 +171,9 @@ export abstract class RJSVM_Builder {
|
|||||||
try {
|
try {
|
||||||
const parsedPayload = payloadSchema.parse(payload)
|
const parsedPayload = payloadSchema.parse(payload)
|
||||||
this.handlePayload(tx, parsedPayload)
|
this.handlePayload(tx, parsedPayload)
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
this.emit('error', err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -140,7 +207,7 @@ export abstract class RJSVM_Builder {
|
|||||||
//presence of no marker means we caught up to current block height
|
//presence of no marker means we caught up to current block height
|
||||||
this.sync_block_height = resp.result.ledger_index_max + 1
|
this.sync_block_height = resp.result.ledger_index_max + 1
|
||||||
//schedule the next sync
|
//schedule the next sync
|
||||||
setTimeout(this.sync, 10000)
|
this.syncTimeout = setTimeout(this.sync, 10000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { XRP_ADDRESS } from "./protocol.constants";
|
import { NON_ZERO_TX_HASH, XRP_ADDRESS } from "../../util/protocol.constants";
|
||||||
import { NON_ZERO_TX_HASH } from "xrpio";
|
|
||||||
|
export const payloadSchema = z.object({
|
||||||
|
endpoint: z.string(),
|
||||||
|
data: z.string()
|
||||||
|
})
|
||||||
|
|
||||||
export const xrp_address_schema = z.string().regex(XRP_ADDRESS, "Not a valid XRP address")
|
export const xrp_address_schema = z.string().regex(XRP_ADDRESS, "Not a valid XRP address")
|
||||||
export const xrp_transaction_hash_schema = z.string().regex(NON_ZERO_TX_HASH, "Not a valid XRP transaction hash")
|
export const xrp_transaction_hash_schema = z.string().regex(NON_ZERO_TX_HASH, "Not a valid XRP transaction hash")
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { payloadSchema } from "./schemas";
|
||||||
|
|
||||||
export abstract class RJSVM<State_T = any, Definitions_T extends Function_Map = Function_Map>{
|
export abstract class RJSVM<State_T = any, Definitions_T extends Function_Map = Function_Map>{
|
||||||
owner: string
|
owner: string
|
||||||
state: State_T
|
state: State_T
|
||||||
sync_block_height: number
|
sync_block_height: number
|
||||||
config: RJSVM_Config
|
config: RJSVM_Config
|
||||||
definitions: RJSVM_Implementations<any, Definitions_T>
|
definitions: RJSVM_Implementations<RJSVM<any, Definitions_T>, Definitions_T>
|
||||||
connect: () => Promise<void>
|
connect: () => Promise<void>
|
||||||
|
disconnect: () => Promise<void>
|
||||||
|
on: (event: string, handler: ParameterizedFunction) => void
|
||||||
|
once: (event: string, handler: ParameterizedFunction) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Generic_Ctor_ReturnType<Ctor>
|
export type Generic_Ctor_ReturnType<Ctor>
|
||||||
@@ -14,8 +18,8 @@ export type Generic_Ctor_ReturnType<Ctor>
|
|||||||
: Ctor extends abstract new (...args:any) => infer A ? A
|
: Ctor extends abstract new (...args:any) => infer A ? A
|
||||||
: never
|
: never
|
||||||
|
|
||||||
export type State_Of<T extends RJSVM<any>> = T extends RJSVM<infer State_T> ? State_T : any
|
export type State_Of<T extends RJSVM> = T extends RJSVM<infer State_T> ? State_T : any
|
||||||
export type Endpoints_Of<T extends RJSVM<any, any>> = T extends RJSVM<any, infer Endpoints_T> ? Endpoints_T : any
|
export type Endpoints_Of<T extends RJSVM> = T extends RJSVM<any, infer Endpoints_T> ? Endpoints_T : any
|
||||||
|
|
||||||
|
|
||||||
export type PaymentTx_T = {
|
export type PaymentTx_T = {
|
||||||
@@ -72,24 +76,15 @@ export type RJSVM_Interface<
|
|||||||
State_T = State_Of<RJSVM_T>,
|
State_T = State_Of<RJSVM_T>,
|
||||||
Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>,
|
Definitions_T extends Function_Map = Endpoints_Of<RJSVM_T>,
|
||||||
> = {
|
> = {
|
||||||
|
owner: string
|
||||||
state: State_T
|
state: State_T
|
||||||
} & {
|
} & {
|
||||||
[K in keyof Definitions_T]?: RJSVM_EndpointHandler<RJSVM_T, Definitions_T, Definitions_T[K]>
|
[K in keyof Definitions_T]?: RJSVM_EndpointHandler<RJSVM_T, Definitions_T, Definitions_T[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RJSVM_InitState<State_T> = {
|
|
||||||
owner: string,
|
|
||||||
state: State_T
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RJSVM_Config = {
|
export type RJSVM_Config = {
|
||||||
rippleNode: string,
|
rippleNode: string,
|
||||||
listeningAddress: string
|
listeningAddress: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const payloadSchema = z.object({
|
|
||||||
endpoint: z.string(),
|
|
||||||
data: z.string()
|
|
||||||
})
|
|
||||||
|
|
||||||
export type Payload = z.infer<typeof payloadSchema>
|
export type Payload = z.infer<typeof payloadSchema>
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import { xrpIO } from "xrpio";
|
|
||||||
|
|
||||||
type Wallet = {
|
|
||||||
address: string,
|
|
||||||
secret: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type DatawriterConfig = {
|
|
||||||
receiveAddress: string
|
|
||||||
sendWallet: Wallet
|
|
||||||
xrpNode: string
|
|
||||||
contractAddress: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Datawriter {
|
|
||||||
|
|
||||||
constructor(private config: DatawriterConfig) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async callEndpoint(endpointName: string, parameter: any, fee?: number) {
|
|
||||||
const xrpio: xrpIO = new xrpIO(this.config.xrpNode)
|
|
||||||
await xrpio.connect()
|
|
||||||
try{
|
|
||||||
const dataHash = await xrpio.treeWrite(
|
|
||||||
JSON.stringify(parameter),
|
|
||||||
this.config.receiveAddress,
|
|
||||||
this.config.sendWallet.secret
|
|
||||||
)
|
|
||||||
await xrpio.writeRaw(
|
|
||||||
{
|
|
||||||
data: JSON.stringify({
|
|
||||||
endpoint: endpointName,
|
|
||||||
data: dataHash
|
|
||||||
})
|
|
||||||
},
|
|
||||||
this.config.contractAddress,
|
|
||||||
this.config.sendWallet.secret,
|
|
||||||
undefined,
|
|
||||||
fee ? String(fee) : undefined
|
|
||||||
)
|
|
||||||
}catch(e){
|
|
||||||
console.log(e)
|
|
||||||
}finally{
|
|
||||||
await xrpio.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const owner_dw = new Datawriter({
|
|
||||||
receiveAddress: "rDuXvMYNCEJCYDMFQykcafXhgi2NvMWqR",
|
|
||||||
sendWallet: {
|
|
||||||
address: "rUsPfG1hn6w6is28p5FUDWdMwvCo1iHrYq",
|
|
||||||
secret: "sEdTMicaTVmfsVMLhxrufyAzEQSnsaP"
|
|
||||||
},
|
|
||||||
xrpNode: "wss://s.altnet.rippletest.net:51233",
|
|
||||||
contractAddress: 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq'
|
|
||||||
})
|
|
||||||
|
|
||||||
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
|
||||||
|
|
||||||
const user_dw = new Datawriter({
|
|
||||||
receiveAddress: "rwqCiEr3SLF43rAduhCChkR2K1XDhiqx5g",
|
|
||||||
sendWallet: {
|
|
||||||
address: "rHWN4X3hbodryX8H1EoPvmMV7AFHngEiBe",
|
|
||||||
secret: "sEdTdLPWvz69UAUmt1zYijTyWheER9u"
|
|
||||||
},
|
|
||||||
xrpNode: "wss://s.altnet.rippletest.net:51233",
|
|
||||||
contractAddress: 'rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq'
|
|
||||||
})
|
|
||||||
|
|
||||||
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
|
||||||
//await user_dw.callEndpoint('restricted', { title: "user", body: "user", from: "user" })
|
|
||||||
//await owner_dw.callEndpoint('restricted', { title: "owner", body: "owner", from: "owner" })
|
|
||||||
|
|
||||||
await user_dw.callEndpoint('setTns', { hash: '01708abcF00636CE10E191FD782DBDC8F4076F28404BD88EBC31DE42DD084C0944B', name: 'test'})
|
|
||||||
|
|
||||||
})()
|
|
||||||
@@ -1,7 +1,49 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { RJSVM_Implementations, RJSVM_Interface, RJSVM, RJSVM_Config, RJSVM_InitState } from "./RJSVM/framework/types"
|
import { RJSVM_Implementations, RJSVM_Interface, RJSVM, RJSVM_Config } from "../src/RJSVM/framework/types"
|
||||||
import { RJSVM_Builder } from "./main";
|
import { RJSVM_Builder } from "../src/main";
|
||||||
import { xrp_transaction_hash_schema } from "./util/schemas";
|
import { Wallet } from "xrpio";
|
||||||
|
import { Datawriter } from "./RJSVM/datawriter/datawriter";
|
||||||
|
import { makeTestnetWallet } from "../test/tools";
|
||||||
|
import { xrp_transaction_hash_schema } from "./RJSVM/framework/schemas";
|
||||||
|
|
||||||
|
const xrpNode = "wss://s.altnet.rippletest.net:51233"
|
||||||
|
|
||||||
|
let ownerWallet: Wallet //the RJSVM owner
|
||||||
|
let userWallet: Wallet //a RJSVM user
|
||||||
|
let listeningWallet: Wallet //wallet the RJSVM listens to
|
||||||
|
let drainWallet: Wallet //random wallet to send stuff to, could be anything
|
||||||
|
let rjsvm: RJSVM
|
||||||
|
|
||||||
|
let user_datawriter: Datawriter
|
||||||
|
let owner_datawriter: Datawriter
|
||||||
|
|
||||||
|
|
||||||
|
const setup = async () => {
|
||||||
|
|
||||||
|
[ownerWallet, listeningWallet, userWallet, drainWallet] = await Promise.all([makeTestnetWallet(),makeTestnetWallet(),makeTestnetWallet(),makeTestnetWallet()])
|
||||||
|
|
||||||
|
owner_datawriter = new Datawriter({
|
||||||
|
receiveAddress: drainWallet.address,
|
||||||
|
sendWallet: ownerWallet,
|
||||||
|
xrpNode: xrpNode,
|
||||||
|
contractAddress: listeningWallet.address
|
||||||
|
})
|
||||||
|
|
||||||
|
user_datawriter = new Datawriter({
|
||||||
|
receiveAddress: drainWallet.address,
|
||||||
|
sendWallet: userWallet,
|
||||||
|
xrpNode: xrpNode,
|
||||||
|
contractAddress: listeningWallet.address
|
||||||
|
})
|
||||||
|
|
||||||
|
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
||||||
|
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
||||||
|
//await user_dw.callEndpoint('restricted', { title: "user", body: "user", from: "user" })
|
||||||
|
//await owner_dw.callEndpoint('restricted', { title: "owner", body: "owner", from: "owner" })
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define parameter types
|
||||||
|
// #########################
|
||||||
|
|
||||||
const shoutSchema = z.object({
|
const shoutSchema = z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
@@ -21,22 +63,34 @@ type State = {
|
|||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define endpoints
|
||||||
|
// #########################
|
||||||
|
|
||||||
type RJSVM_Endpoints = {
|
type RJSVM_Endpoints = {
|
||||||
submit: (data: Shout) => void
|
submit: (data: Shout) => void
|
||||||
restricted: (data: Shout) => void
|
restricted: (data: Shout) => void
|
||||||
setTns: (entry: TnsEntry) => void
|
setTns: (entry: TnsEntry) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define init state
|
||||||
|
// #########################
|
||||||
|
|
||||||
abstract class RJSVM_Base
|
abstract class RJSVM_Base
|
||||||
extends RJSVM<State, RJSVM_Endpoints>
|
extends RJSVM<State, RJSVM_Endpoints>
|
||||||
implements RJSVM_Interface<RJSVM_Base> {
|
implements RJSVM_Interface<RJSVM_Base> {
|
||||||
owner = "rUsPfG1hn6w6is28p5FUDWdMwvCo1iHrYq"
|
owner = ownerWallet.address
|
||||||
|
|
||||||
state: State = {
|
state: State = {
|
||||||
shouts: []
|
shouts: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Implement logic
|
||||||
|
// #########################
|
||||||
|
|
||||||
const RJSVM_Contract: RJSVM_Implementations<RJSVM_Base> = {
|
const RJSVM_Contract: RJSVM_Implementations<RJSVM_Base> = {
|
||||||
submit: {
|
submit: {
|
||||||
implementation: function (env, shout) {
|
implementation: function (env, shout) {
|
||||||
@@ -65,14 +119,22 @@ const RJSVM_Contract: RJSVM_Implementations<RJSVM_Base> = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Build and connect
|
||||||
|
// #########################
|
||||||
|
|
||||||
const Rjsvm = RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract);
|
const Rjsvm = RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract);
|
||||||
|
|
||||||
const conf: RJSVM_Config = {
|
const conf: RJSVM_Config = {
|
||||||
listeningAddress: "rLaXUiYvW1EMns69PsAfwSLb2VgNtPpZwq",
|
listeningAddress: listeningWallet.address,
|
||||||
rippleNode: "wss://s.altnet.rippletest.net:51233"
|
rippleNode: "wss://s.altnet.rippletest.net:51233"
|
||||||
}
|
}
|
||||||
|
|
||||||
const rjsvm = new Rjsvm(conf)
|
rjsvm = new Rjsvm(conf)
|
||||||
|
await rjsvm.connect()
|
||||||
|
}
|
||||||
|
|
||||||
rjsvm.connect()
|
(async () => {
|
||||||
|
await setup()
|
||||||
|
await owner_datawriter.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
||||||
|
})()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export class RestrictedAccessError extends Error{
|
||||||
|
constructor(endpoint:string, hash:string, callee:string, expecedCallee:string){
|
||||||
|
super(`Restricted endpoint "${endpoint}" called in ${hash}. But callee ${callee} is not owner ${expecedCallee}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InsufficientFeeError extends Error{
|
||||||
|
constructor(hash: string, requiredFee:number, suppliedFee:number){
|
||||||
|
super(`Insufficient fee in ${hash}. Required fee is ${requiredFee}, but was ${suppliedFee}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
+247
@@ -0,0 +1,247 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { RJSVM_Implementations, RJSVM_Interface, RJSVM, RJSVM_Config } from "../src/RJSVM/framework/types"
|
||||||
|
import { DataParser, RJSVM_Builder } from "../src/main";
|
||||||
|
import { xrp_transaction_hash_schema } from "../src/RJSVM/framework/schemas";
|
||||||
|
|
||||||
|
//Test requirements
|
||||||
|
import { assert, expect } from 'chai';
|
||||||
|
import { describe, it } from "mocha";
|
||||||
|
import { makeTestnetWallet } from "./tools";
|
||||||
|
import { Wallet } from "xrpio";
|
||||||
|
import { Datawriter } from "../src/RJSVM/datawriter/datawriter";
|
||||||
|
import { InsufficientFeeError, RestrictedAccessError } from "../src/util/errors";
|
||||||
|
var should = require('chai').should();
|
||||||
|
var chai = require('chai');
|
||||||
|
var chaiAsPromised = require('chai-as-promised');
|
||||||
|
chai.use(chaiAsPromised);
|
||||||
|
|
||||||
|
|
||||||
|
const xrpNode = "wss://s.altnet.rippletest.net:51233"
|
||||||
|
|
||||||
|
let ownerWallet: Wallet //the RJSVM owner
|
||||||
|
let userWallet: Wallet //a RJSVM user
|
||||||
|
let listeningWallet: Wallet //wallet the RJSVM listens to
|
||||||
|
let drainWallet: Wallet //random wallet to send stuff to, could be any user-controlled secondary wallet
|
||||||
|
let rjsvm: RJSVM
|
||||||
|
|
||||||
|
let user_datawriter: Datawriter
|
||||||
|
let owner_datawriter: Datawriter
|
||||||
|
|
||||||
|
|
||||||
|
const setup = async () => {
|
||||||
|
|
||||||
|
[ownerWallet, listeningWallet, userWallet, drainWallet] = await Promise.all([makeTestnetWallet(), makeTestnetWallet(), makeTestnetWallet(), makeTestnetWallet()])
|
||||||
|
|
||||||
|
owner_datawriter = new Datawriter({
|
||||||
|
receiveAddress: drainWallet.address,
|
||||||
|
sendWallet: ownerWallet,
|
||||||
|
xrpNode: xrpNode,
|
||||||
|
contractAddress: listeningWallet.address
|
||||||
|
})
|
||||||
|
|
||||||
|
user_datawriter = new Datawriter({
|
||||||
|
receiveAddress: drainWallet.address,
|
||||||
|
sendWallet: userWallet,
|
||||||
|
xrpNode: xrpNode,
|
||||||
|
contractAddress: listeningWallet.address
|
||||||
|
})
|
||||||
|
|
||||||
|
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
||||||
|
//await owner_dw.callEndpoint('submit', { title: "1", body: "2", from: "3" }, 100)
|
||||||
|
//await user_dw.callEndpoint('restricted', { title: "user", body: "user", from: "user" })
|
||||||
|
//await owner_dw.callEndpoint('restricted', { title: "owner", body: "owner", from: "owner" })
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define parameter types
|
||||||
|
// #########################
|
||||||
|
|
||||||
|
const shoutSchema = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
body: z.string(),
|
||||||
|
from: z.string(),
|
||||||
|
id: z.optional(z.string())
|
||||||
|
})
|
||||||
|
type Shout = z.infer<typeof shoutSchema>
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
shouts: Shout[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define endpoints
|
||||||
|
// #########################
|
||||||
|
|
||||||
|
type RJSVM_Endpoints = {
|
||||||
|
submit: (data: Shout) => void
|
||||||
|
restricted: (data: Shout) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Define init state
|
||||||
|
// #########################
|
||||||
|
|
||||||
|
abstract class RJSVM_Base
|
||||||
|
extends RJSVM<State, RJSVM_Endpoints>
|
||||||
|
implements RJSVM_Interface<RJSVM_Base> {
|
||||||
|
owner = ownerWallet.address
|
||||||
|
|
||||||
|
state: State = {
|
||||||
|
shouts: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Implement logic
|
||||||
|
// #########################
|
||||||
|
|
||||||
|
const RJSVM_Contract: RJSVM_Implementations<RJSVM_Base> = {
|
||||||
|
submit: {
|
||||||
|
implementation: function (env, shout) {
|
||||||
|
this.state.shouts.unshift(shout)
|
||||||
|
},
|
||||||
|
visibility: 'public',
|
||||||
|
fee: 10,
|
||||||
|
parameterSchema: shoutSchema
|
||||||
|
},
|
||||||
|
|
||||||
|
restricted: {
|
||||||
|
implementation: function (env, shout) {
|
||||||
|
this.state.shouts.unshift(shout)
|
||||||
|
},
|
||||||
|
visibility: 'owner',
|
||||||
|
parameterSchema: shoutSchema
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################
|
||||||
|
// Build and connect
|
||||||
|
// #########################
|
||||||
|
|
||||||
|
const Rjsvm = RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract);
|
||||||
|
|
||||||
|
const conf: RJSVM_Config = {
|
||||||
|
listeningAddress: listeningWallet.address,
|
||||||
|
rippleNode: xrpNode
|
||||||
|
}
|
||||||
|
|
||||||
|
rjsvm = new Rjsvm(conf)
|
||||||
|
await rjsvm.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('RJSVM basic functions', () => {
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
this.timeout(10000)
|
||||||
|
await setup()
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await rjsvm.disconnect()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Env contains the payload carrying transaction', function (done) {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
makeTestnetWallet().then(async testWallet => {
|
||||||
|
//create a mock RJSVM
|
||||||
|
abstract class RJSVM_Base
|
||||||
|
extends RJSVM<undefined, { testEndpoint: () => void }>
|
||||||
|
implements RJSVM_Interface<RJSVM_Base> {
|
||||||
|
owner = ownerWallet.address
|
||||||
|
state = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
//Implementation of the 'test' endpoint
|
||||||
|
const RJSVM_Contract: RJSVM_Implementations<RJSVM_Base> = {
|
||||||
|
testEndpoint: {
|
||||||
|
implementation: function (env) {
|
||||||
|
|
||||||
|
expect(env.Account).to.be.equal(userWallet.address)
|
||||||
|
expect(env.Amount).to.be.equal('1')
|
||||||
|
expect(env.Destination).to.be.equal(testWallet.address)
|
||||||
|
expect(Number(env.Fee)).to.be.greaterThanOrEqual(10)
|
||||||
|
expect(env.LastLedgerSequence).to.be.a('number')
|
||||||
|
|
||||||
|
expect(env.Memos).to.be.an('Array')
|
||||||
|
const memo = JSON.parse(DataParser.hex_to_ascii(env.Memos[0].Memo.MemoData))
|
||||||
|
expect(memo.endpoint).to.be.equal('testEndpoint')
|
||||||
|
|
||||||
|
expect(env.Sequence).to.be.a('number')
|
||||||
|
expect(env.SigningPubKey).to.be.a('string')
|
||||||
|
expect(env.TransactionType).to.be.equal('Payment')
|
||||||
|
expect(env.TxnSignature).to.be.a('string')
|
||||||
|
expect(env.date).to.be.a('number')
|
||||||
|
expect(env.hash).to.be.a('string')
|
||||||
|
expect(env.inLedger).to.be.a('number')
|
||||||
|
expect(env.ledger_index).to.be.a('number')
|
||||||
|
|
||||||
|
runnable.disconnect()
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
visibility: 'public',
|
||||||
|
parameterSchema: z.any()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Rjsvm = RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract)
|
||||||
|
const runnable = new Rjsvm({listeningAddress: testWallet.address,rippleNode: xrpNode})
|
||||||
|
await runnable.connect()
|
||||||
|
|
||||||
|
const dw = new Datawriter({
|
||||||
|
contractAddress: testWallet.address,
|
||||||
|
sendWallet: userWallet,
|
||||||
|
receiveAddress: drainWallet.address,
|
||||||
|
xrpNode: xrpNode
|
||||||
|
})
|
||||||
|
dw.callEndpoint('testEndpoint', "")
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Called endpoint triggers in RJSVM', function (done) {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
const data = { title: "1", body: "2", from: "3" };
|
||||||
|
rjsvm.once('submit', (payload) => {
|
||||||
|
expect(payload).to.be.an('object')
|
||||||
|
expect(payload).to.deep.equal(data)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
owner_datawriter.callEndpoint('submit', data, 10)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Calling an endpoint with insufficient fee fails', function (done) {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
const data = { title: "f", body: "f", from: "f" };
|
||||||
|
rjsvm.once('error', (err) => {
|
||||||
|
expect(err).to.be.instanceOf(InsufficientFeeError)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
owner_datawriter.callEndpoint('submit', data, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Restricted endpoint can be called by owner', function (done) {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
const data = { title: "11", body: "22", from: "33" };
|
||||||
|
rjsvm.once('restricted', (payload) => {
|
||||||
|
expect(payload).to.be.an('object')
|
||||||
|
expect(payload).to.deep.equal(data)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
owner_datawriter.callEndpoint('restricted', data)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('Restricted endpoint cannot be called by non-owner', function (done) {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
const data = { title: "e", body: "e", from: "e" };
|
||||||
|
rjsvm.once('error', (err) => {
|
||||||
|
expect(err).to.be.instanceOf(RestrictedAccessError)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
user_datawriter.callEndpoint('restricted', data)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
type Wallet = {secret: string, address:string }
|
||||||
|
|
||||||
|
export const makeTestnetWallet = () : Promise<Wallet> => fetch('https://faucet.altnet.rippletest.net/accounts', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
}).then((raw:any) => {
|
||||||
|
return raw.json().then(content => {
|
||||||
|
return({
|
||||||
|
secret: content.account.secret,
|
||||||
|
address: content.account.address
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user