begin rework for js tests and hook examples

This commit is contained in:
Richard Holland
2022-06-06 14:05:17 +00:00
parent d452f9ca5a
commit 5f74392bcb
68 changed files with 4197 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
/**
* This hook just accepts any transaction coming through it
*/
#include "../hookapi.h"
int64_t cbak(uint32_t reserved) {
return 0;
}
int64_t hook(uint32_t reserved ) {
TRACESTR("Accept.c: Called.");
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,34 @@
const wasm = 'accept.wasm'
if (process.argv.length < 3)
{
console.log("Usage: node accept <account family seed>")
process.exit(1);
}
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const secret = process.argv[2];
const account = t.xrpljs.Wallet.fromSeed(secret)
t.feeSubmit(process.argv[2],
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm(wasm),
HookApiVersion: 0,
HookNamespace: "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE",
HookOn: "0000000000000000",
Flags: t.hsfOVERRIDE
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(e=>console.log(e));
}).catch(e=>console.log(e));

View File

@@ -0,0 +1,4 @@
all:
wasmcc accept.c -o accept.wasm -O0 -Wl,--allow-undefined -I../
hook-cleaner accept.wasm

View File

@@ -0,0 +1,19 @@
if (process.argv.length < 5)
{
console.log("Usage: node pay <source family seed> <amount xrp> <destination account>")
process.exit(1)
}
const secret = process.argv[2];
const amount = BigInt(process.argv[3]) * 1000000n
const dest = process.argv[4];
const server = 'ws://localhost:6005'
require('../../utils-tests.js').TestRig(server).then(t=>
{
t.pay(secret, amount, dest).then(x=>
{
console.log(x);
process.exit(0);
});
});

View File

@@ -0,0 +1,95 @@
#include <stdint.h>
#include "hookapi.h"
int64_t cbak(uint32_t reserved)
{
TRACESTR("Carbon: callback called.");
return 0;
}
int64_t hook(uint32_t reserved)
{
TRACESTR("Carbon: started");
// before we start calling hook-api functions we should tell the hook how many tx we intend to create
etxn_reserve(1); // we are going to emit 1 transaction
// hooks communicate accounts via the 20 byte account ID, this can be generated from an raddr like so
// a more efficient way to do this is precompute the account-id from the raddr (if the raddr never changes)
uint8_t carbon_accid[20];
int64_t ret = util_accid(
SBUF(carbon_accid), /* <-- generate into this buffer */
SBUF("rfCarbonVNTuXckX6x2qTMFmFSnm6dEWGX") ); /* <-- from this r-addr */
TRACEVAR(ret);
// this api fetches the AccountID of the account the hook currently executing is installed on
// since hooks can be triggered by both incoming and ougoing transactions this is important to know
unsigned char hook_accid[20];
hook_account((uint32_t)hook_accid, 20);
// NB:
// almost all of the hook apis require a buffer pointer and buffer length to be supplied ... to make this a
// little easier to code a macro: `SBUF(your_buffer)` expands to `your_buffer, sizeof(your_buffer)`
// next fetch the sfAccount field from the originating transaction
uint8_t account_field[20];
int32_t account_field_len = otxn_field(SBUF(account_field), sfAccount);
TRACEVAR(account_field_len);
if (account_field_len < 20) // negative values indicate errors from every api
rollback(SBUF("Carbon: sfAccount field missing!!!"), 1); // this code could never be hit in prod
// but it's here for completeness
// compare the "From Account" (sfAccount) on the transaction with the account the hook is running on
int equal = 0; BUFFER_EQUAL(equal, hook_accid, account_field, 20);
if (!equal)
{
// if the accounts are not equal (memcmp != 0) the otxn was sent to the hook account by someone else
// accept() it and end the hook execution here
accept(SBUF("Carbon: Incoming transaction"), 2);
}
// execution to here means the user has sent a valid transaction FROM the account the hook is installed on
// fetch the sent Amount
// Amounts can be 384 bits or 64 bits. If the Amount is an XRP value it will be 64 bits.
unsigned char amount_buffer[48];
int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount);
int64_t drops_to_send = 1000; // this will be the default
if (amount_len != 8)
{
// you can trace the behaviour of your hook using the trace(buf, size, as_hex) api
// which will output to xrpld's trace log
TRACESTR("Carbon: Non-xrp transaction detected, sending default 1000 drops to rfCarbon");
} else
{
TRACESTR("Carbon: XRP transaction detected, computing 1% to send to rfCarbon");
int64_t otxn_drops = AMOUNT_TO_DROPS(amount_buffer);
TRACEVAR(otxn_drops);
if (otxn_drops > 100000) // if its less we send the default amount. or if there was an error we send default
drops_to_send = (int64_t)((double)otxn_drops * 0.01f); // otherwise we send 1%
}
TRACEVAR(drops_to_send);
// create a buffer to write the emitted transaction into
unsigned char tx[PREPARE_PAYMENT_SIMPLE_SIZE];
// we will use an XRP payment macro, this will populate the buffer with a serialized binary transaction
// Parameter list: ( buf_out, drops_amount, to_address, dest_tag, src_tag )
PREPARE_PAYMENT_SIMPLE(tx, drops_to_send++, carbon_accid, 0, 0);
// emit the transaction
uint8_t emithash[32];
int64_t emit_result = emit(SBUF(emithash), SBUF(tx));
TRACEVAR(emit_result);
// accept and allow the original transaction through
accept(SBUF("Carbon: Emitted transaction"), 0);
return 0;
}

View File

@@ -0,0 +1,38 @@
const wasm = 'carbon.wasm'
if (process.argv.length < 3)
{
console.log("Usage: node carbon <account family seed>")
process.exit(1);
}
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
t.fundFromGenesis(["rfCarbonVNTuXckX6x2qTMFmFSnm6dEWGX"]).then(()=>
{
const secret = process.argv[2];
const account = t.xrpljs.Wallet.fromSeed(secret)
t.feeSubmit(process.argv[2],
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm(wasm),
HookApiVersion: 0,
HookNamespace: "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE",
HookOn: "0000000000000000",
Flags: t.hsfOVERRIDE
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(e=>console.log(e));

View File

@@ -0,0 +1,5 @@
all:
wasmcc carbon.c -o carbon.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner carbon.wasm

View File

@@ -0,0 +1,19 @@
if (process.argv.length < 5)
{
console.log("Usage: node pay <source family seed> <amount xrp> <destination account>")
process.exit(1)
}
const secret = process.argv[2];
const amount = BigInt(process.argv[3]) * 1000000n
const dest = process.argv[4];
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
t.pay(secret, amount, dest).then(x=>
{
console.log(x);
process.exit(0);
});
});

View File

@@ -0,0 +1,72 @@
//Authors: NeilH, RichardAH
// (joke) test hook that doubles incoming XRP payments and sends it back
// April 1st 2021: Added (unfair) coin flip
#include <stdint.h>
#include "../hookapi.h"
int64_t hook(uint32_t reserved)
{
uint8_t hook_accid[20];
if (hook_account(SBUF(hook_accid)) < 0)
rollback(SBUF("Doubler: Could not fetch hook account id."), 1);
// next fetch the sfAccount field from the originating transaction
uint8_t account_field[20];
int32_t account_field_len = otxn_field(SBUF(account_field), sfAccount);
// compare the "From Account" (sfAccount) on the transaction with the account the hook is running on
int equal = 0; BUFFER_EQUAL(equal, hook_accid, account_field, 20);
if (equal)
{
accept(SBUF("Doubler: Outgoing transaction. Passing."), 2);
return 0;
}
uint8_t digest[96];
if (ledger_last_hash(digest, 32) != 32)
rollback(SBUF("Doubler: Failed to fetch last closed ledger."), 3);
uint8_t key[32]; // left as 0...0
state(digest + 32, 32, SBUF(key)); // if this load fails then we don't care, the hash is just 0
etxn_nonce(digest + 64, 32); // todo: if we enforce sfFirstLedgerSequence = +1 then this will be impossible to cheat
uint8_t hash[32];
if (util_sha512h(SBUF(hash), SBUF(digest)) != 32)
rollback(SBUF("Doubler: Could not compute digest for coin flip."), 4);
if (state_set(SBUF(hash), SBUF(key)) != 32)
rollback(SBUF("Doubler: Could not set state."), 5);
// first digit of lcl hash is our biased coin flip, you lose 60% of the time :P
if (hash[0] % 10 < 6)
accept(SBUF("Doubler: Tails, you lose. Om nom nom xrp."), 4);
// before we start calling hook-api functions we should tell the hook how many tx we intend to create
etxn_reserve(1); // we are going to emit 1 transaction
// fetch the sent Amount
// Amounts can be 384 bits or 64 bits. If the Amount is an XRP value it will be 64 bits.
unsigned char amount_buffer[48];
int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount);
int64_t drops_to_send = AMOUNT_TO_DROPS(amount_buffer) * 2; // doubler pays back 2x received
if (amount_len != 8)
rollback(SBUF("Doubler: Rejecting incoming non-XRP transaction"), 5);
uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE];
// we will use an XRP payment macro, this will populate the buffer with a serialized binary transaction
// Parameter list: ( buf_out, drops_amount, drops_fee, to_address, dest_tag, src_tag )
PREPARE_PAYMENT_SIMPLE(tx, drops_to_send, account_field, 0, 0);
// emit the transaction
uint8_t emithash[32];
emit(SBUF(emithash), SBUF(tx));
// accept and allow the original transaction through
accept(SBUF("Doubler: Heads, you won! Funds emitted!"), 0);
return 0;
}

View File

@@ -0,0 +1,35 @@
const wasm = 'doubler.wasm'
if (process.argv.length < 3)
{
console.log("Usage: node doubler <account family seed>")
process.exit(1);
}
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const secret = process.argv[2];
const account = t.xrpljs.Wallet.fromSeed(secret)
t.feeSubmit(process.argv[2],
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm(wasm),
HookApiVersion: 0,
HookNamespace: "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE",
HookOn: "0000000000000000",
Flags: t.hsfOVERRIDE
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(e=>console.log(e));

View File

@@ -0,0 +1,4 @@
all:
wasmcc doubler.c -o doubler.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner doubler.wasm

View File

@@ -0,0 +1,19 @@
if (process.argv.length < 5)
{
console.log("Usage: node pay <source family seed> <amount xrp> <destination account>")
process.exit(1)
}
const secret = process.argv[2];
const amount = BigInt(process.argv[3]) * 1000000n
const dest = process.argv[4];
require('../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
t.pay(secret, amount, dest).then(x=>
{
console.log(x);
process.exit(0);
});
});

46
hook/examples/error.h Normal file
View File

@@ -0,0 +1,46 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_error.sh
#ifndef HOOK_ERROR_CODES
#define SUCCESS 0
#define OUT_OF_BOUNDS -1
#define INTERNAL_ERROR -2
#define TOO_BIG -3
#define TOO_SMALL -4
#define DOESNT_EXIST -5
#define NO_FREE_SLOTS -6
#define INVALID_ARGUMENT -7
#define ALREADY_SET -8
#define PREREQUISITE_NOT_MET -9
#define FEE_TOO_LARGE -10
#define EMISSION_FAILURE -11
#define TOO_MANY_NONCES -12
#define TOO_MANY_EMITTED_TXN -13
#define NOT_IMPLEMENTED -14
#define INVALID_ACCOUNT -15
#define GUARD_VIOLATION -16
#define INVALID_FIELD -17
#define PARSE_ERROR -18
#define RC_ROLLBACK -19
#define RC_ACCEPT -20
#define NO_SUCH_KEYLET -21
#define NOT_AN_ARRAY -22
#define NOT_AN_OBJECT -23
#define INVALID_FLOAT -10024
#define DIVISION_BY_ZERO -25
#define MANTISSA_OVERSIZED -26
#define MANTISSA_UNDERSIZED -27
#define EXPONENT_OVERSIZED -28
#define EXPONENT_UNDERSIZED -29
#define OVERFLOW -30
#define NOT_IOU_AMOUNT -31
#define NOT_AN_AMOUNT -32
#define CANT_RETURN_NEGATIVE -33
#define NOT_AUTHORIZED -34
#define PREVIOUS_FAILURE_PREVENTS_RETRY -35
#define TOO_MANY_PARAMS -36
#define INVALID_TXN -37
#define RESERVE_INSUFFICIENT -38
#define COMPLEX_NOT_SUPPORTED -39
#define DOES_NOT_MATCH -40
#define HOOK_ERROR_CODES
#endif //HOOK_ERROR_CODES

539
hook/examples/extern.h Normal file
View File

@@ -0,0 +1,539 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_extern.sh
#include <stdint.h>
#ifndef HOOK_EXTERN
extern int32_t
_g(
uint32_t guard_id,
uint32_t maxiter
);
extern int64_t
accept(
uint32_t read_ptr,
uint32_t read_len,
int64_t error_code
);
extern int64_t
emit(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
etxn_burden (
void
);
extern int64_t
etxn_details(
uint32_t write_ptr,
uint32_t write_len
);
extern int64_t
etxn_fee_base(
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
etxn_generation (
void
);
extern int64_t
etxn_nonce(
uint32_t write_ptr,
uint32_t write_len
);
extern int64_t
etxn_reserve(
uint32_t count
);
extern int64_t
fee_base (
void
);
extern int64_t
float_compare(
int64_t float1,
int64_t float2,
uint32_t mode
);
extern int64_t
float_divide(
int64_t float1,
int64_t float2
);
extern int64_t
float_exponent(
int64_t float1
);
extern int64_t
float_exponent_set(
int64_t float1,
int32_t exponent
);
extern int64_t
float_int(
int64_t float1,
uint32_t decimal_places,
uint32_t abs
);
extern int64_t
float_invert(
int64_t float1
);
extern int64_t
float_log(
int64_t float1
);
extern int64_t
float_mantissa(
int64_t float1
);
extern int64_t
float_mantissa_set(
int64_t float1,
int64_t mantissa
);
extern int64_t
float_mulratio(
int64_t float1,
uint32_t round_up,
uint32_t numerator,
uint32_t denominator
);
extern int64_t
float_multiply(
int64_t float1,
int64_t float2
);
extern int64_t
float_negate(
int64_t float1
);
extern int64_t
float_one (
void
);
extern int64_t
float_root(
int64_t float1,
uint32_t n
);
extern int64_t
float_set(
int32_t exponent,
int64_t mantissa
);
extern int64_t
float_sign(
int64_t float1
);
extern int64_t
float_sign_set(
int64_t float1,
uint32_t negative
);
extern int64_t
float_sto(
uint32_t write_ptr,
uint32_t write_len,
uint32_t cread_ptr,
uint32_t cread_len,
uint32_t iread_ptr,
uint32_t iread_len,
int64_t float1,
uint32_t field_code
);
extern int64_t
float_sto_set(
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
float_sum(
int64_t float1,
int64_t float2
);
extern int64_t
hook_account(
uint32_t write_ptr,
uint32_t write_len
);
extern int64_t
hook_again (
void
);
extern int64_t
hook_hash(
uint32_t write_ptr,
uint32_t write_len,
int32_t hook_no
);
extern int64_t
hook_param(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
hook_param_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t hread_ptr,
uint32_t hread_len
);
extern int64_t
hook_pos (
void
);
extern int64_t
hook_skip(
uint32_t read_ptr,
uint32_t read_len,
uint32_t flags
);
extern int64_t
ledger_keylet(
uint32_t write_ptr,
uint32_t write_len,
uint32_t lread_ptr,
uint32_t lread_len,
uint32_t hread_ptr,
uint32_t hread_len
);
extern int64_t
ledger_last_hash(
uint32_t write_ptr,
uint32_t write_len
);
extern int64_t
ledger_last_time (
void
);
extern int64_t
ledger_nonce(
uint32_t write_ptr,
uint32_t write_len
);
extern int64_t
ledger_seq (
void
);
extern int64_t
meta_slot(
uint32_t slot_no
);
extern int64_t
otxn_burden (
void
);
extern int64_t
otxn_field(
uint32_t write_ptr,
uint32_t write_len,
uint32_t field_id
);
extern int64_t
otxn_field_txt(
uint32_t write_ptr,
uint32_t write_len,
uint32_t field_id
);
extern int64_t
otxn_generation (
void
);
extern int64_t
otxn_id(
uint32_t write_ptr,
uint32_t write_len,
uint32_t flags
);
extern int64_t
otxn_slot(
uint32_t slot_no
);
extern int64_t
otxn_type (
void
);
extern int64_t
rollback(
uint32_t read_ptr,
uint32_t read_len,
int64_t error_code
);
extern int64_t
slot(
uint32_t write_ptr,
uint32_t write_len,
uint32_t slot
);
extern int64_t
slot_clear(
uint32_t slot
);
extern int64_t
slot_count(
uint32_t slot
);
extern int64_t
slot_float(
uint32_t slot_no
);
extern int64_t
slot_id(
uint32_t write_ptr,
uint32_t write_len,
uint32_t slot
);
extern int64_t
slot_set(
uint32_t read_ptr,
uint32_t read_len,
int32_t slot
);
extern int64_t
slot_size(
uint32_t slot
);
extern int64_t
slot_subarray(
uint32_t parent_slot,
uint32_t array_id,
uint32_t new_slot
);
extern int64_t
slot_subfield(
uint32_t parent_slot,
uint32_t field_id,
uint32_t new_slot
);
extern int64_t
slot_type(
uint32_t slot_no,
uint32_t flags
);
extern int64_t
state(
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len
);
extern int64_t
state_foreign(
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len
);
extern int64_t
state_foreign_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len
);
extern int64_t
state_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len
);
extern int64_t
sto_emplace(
uint32_t write_ptr,
uint32_t write_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t fread_ptr,
uint32_t fread_len,
uint32_t field_id
);
extern int64_t
sto_erase(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len,
uint32_t field_id
);
extern int64_t
sto_subarray(
uint32_t read_ptr,
uint32_t read_len,
uint32_t array_id
);
extern int64_t
sto_subfield(
uint32_t read_ptr,
uint32_t read_len,
uint32_t field_id
);
extern int64_t
sto_validate(
uint32_t tread_ptr,
uint32_t tread_len
);
extern int64_t
trace(
uint32_t mread_ptr,
uint32_t mread_len,
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t as_hex
);
extern int64_t
trace_float(
uint32_t read_ptr,
uint32_t read_len,
int64_t float1
);
extern int64_t
trace_num(
uint32_t read_ptr,
uint32_t read_len,
int64_t number
);
extern int64_t
trace_slot(
uint32_t read_ptr,
uint32_t read_len,
uint32_t slot
);
extern int64_t
util_accid(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
util_keylet(
uint32_t write_ptr,
uint32_t write_len,
uint32_t keylet_type,
uint32_t a,
uint32_t b,
uint32_t c,
uint32_t d,
uint32_t e,
uint32_t f
);
extern int64_t
util_raddr(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
util_sha512h(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
extern int64_t
util_verify(
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t kread_ptr,
uint32_t kread_len
);
#define HOOK_EXTERN
#endif //HOOK_EXTERN

5
hook/examples/genheaders.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
headergen/generate_error.sh > error.h
headergen/generate_extern.sh > extern.h
headergen/generate_sfcodes.sh > sfcodes.h

View File

@@ -0,0 +1,2 @@
Bash scripts herein will generate up to date headers from the Hooks source.
You must pipe them into the desired output file.

View File

@@ -0,0 +1,8 @@
#!/bin/bash
RIPPLED_ROOT="`git rev-parse --show-toplevel`/src/ripple"
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
echo '// Generated using generate_error.sh'
echo '#ifndef HOOK_ERROR_CODES'
cat $RIPPLED_ROOT/app/hook/Enum.h | tr -d '\n' | grep -Eo 'hook_return_code : int64_t *{[^}]+}' | grep -Eo '[A-Z_]+ *= *[0-9-]+' | sed -E 's/ *= */ /g' | sed -E 's/^/#define /g'
echo '#define HOOK_ERROR_CODES'
echo '#endif //HOOK_ERROR_CODES'

View File

@@ -0,0 +1,9 @@
#!/bin/bash
RIPPLED_ROOT="`git rev-parse --show-toplevel`/src/ripple"
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
echo '// Generated using generate_extern.sh'
echo '#include <stdint.h>'
echo '#ifndef HOOK_EXTERN'
cat $RIPPLED_ROOT/app/hook/applyHook.h | tr -d '\n' | grep -Eo 'DECLARE_HOOK[^\(]+\([^\)]+\)' | grep DECLARE_HOOK | cut -d'(' -f2 | sed -E 's/_t,/_t/g' | sed -E 's/ */ /g' | sort | grep -Ev '^$' | sed -E s'/\)/ \)/g' | tr '\t' ' ' | sed -E 's/^([^ ]+ [^ ]+)/\1,/g' | sed -E 's/,,*/,/g' | sed -E 's/\)/\)\n/g' | sort | grep -vE '^$' | sed -E 's/^([^,]+),/\1 (/g' | sed -E 's/\( *\)/(void)/g' | sed -E 's/, *\(/(/g' | sed -E 's/ */ /g' | sed -E 's/ *\( /(/g' | sed -E 's/ \)/)/g' | sed -E 's/\)([^;]?)/);\1/g' | sed -E 's/^int/extern int/g' | sed -E 's/^(extern [^ ]+ )/\1\n/g' | grep -Ev '^,+$' | sed -E 's/\(/\(\n /g' | sed -E 's/, */,\n /g' | sed -E 's/^extern/\nextern/g' | sed -E 's/\);/\n);/g'
echo '#define HOOK_EXTERN'
echo '#endif //HOOK_EXTERN'

View File

@@ -0,0 +1,30 @@
#/bin/bash
RIPPLED_ROOT="`git rev-parse --show-toplevel`/src/ripple"
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
echo '// Generated using generate_sfcodes.sh'
cat $RIPPLED_ROOT/protocol/impl/SField.cpp | grep -E '^CONSTRUCT_' |
sed 's/UINT16/1/g' |
sed 's/UINT32/2/g' |
sed 's/UINT64/3/g' |
sed 's/HASH128/4/g' |
sed 's/HASH256/5/g' |
sed 's/UINT128/4/g' |
sed 's/UINT256/5/g' |
sed 's/AMOUNT/6/g' |
sed 's/VL/7/g' |
sed 's/ACCOUNT/8/g' |
sed 's/OBJECT/14/g' |
sed 's/ARRAY/15/g' |
sed 's/UINT8/16/g' |
sed 's/HASH160/17/g' |
sed 's/UINT160/17/g' |
sed 's/PATHSET/18/g' |
sed 's/VECTOR256/19/g' |
sed 's/UINT96/20/g' |
sed 's/UINT192/21/g' |
sed 's/UINT384/22/g' |
sed 's/UINT512/23/g' |
grep -Eo '"([^"]+)", *([0-9]+), *([0-9]+)' |
sed 's/"//g' | sed 's/ *//g' | sed 's/,/ /g' |
awk '{print ("#define sf"$1" (("$2"U << 16U) + "$3"U)")}'

48
hook/examples/hookapi.h Normal file
View File

@@ -0,0 +1,48 @@
/**
* Hook API include file
*
* Note to the reader:
* This include defines two types of things: external functions and macros
* Functions are used sparingly because a non-inlining compiler may produce
* undesirable output.
*
* Find documentation here: https://xrpl-hooks.readme.io/reference/
*/
#ifndef HOOKAPI_INCLUDED
#define HOOKAPI_INCLUDED 1
#define KEYLET_HOOK 1
#define KEYLET_HOOK_STATE 2
#define KEYLET_ACCOUNT 3
#define KEYLET_AMENDMENTS 4
#define KEYLET_CHILD 5
#define KEYLET_SKIP 6
#define KEYLET_FEES 7
#define KEYLET_NEGATIVE_UNL 8
#define KEYLET_LINE 9
#define KEYLET_OFFER 10
#define KEYLET_QUALITY 11
#define KEYLET_EMITTED_DIR 12
#define KEYLET_TICKET 13
#define KEYLET_SIGNERS 14
#define KEYLET_CHECK 15
#define KEYLET_DEPOSIT_PREAUTH 16
#define KEYLET_UNCHECKED 17
#define KEYLET_OWNER_DIR 18
#define KEYLET_PAGE 19
#define KEYLET_ESCROW 20
#define KEYLET_PAYCHAN 21
#define KEYLET_EMITTED 22
#define COMPARE_EQUAL 1U
#define COMPARE_LESS 2U
#define COMPARE_GREATER 4U
#include "error.h"
#include "extern.h"
#include "sfcodes.h"
#include "macro.h"
#endif

544
hook/examples/macro.h Normal file
View File

@@ -0,0 +1,544 @@
/**
* These are helper macros for writing hooks, all of them are optional as is including hookmacro.h at all
*/
#include <stdint.h>
#include "hookapi.h"
#include "sfcodes.h"
#ifndef HOOKMACROS_INCLUDED
#define HOOKMACROS_INCLUDED 1
// hook developers should use this guard macro, simply GUARD(<maximum iterations>)
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
#define GUARDM(maxiter, n) _g(((__LINE__ << 16) + n), (maxiter)+1)
#define SBUF(str) (uint32_t)(str), sizeof(str)
#define REQUIRE(cond, str)\
{\
if (!(cond))\
rollback(SBUF(str), __LINE__);\
}
// make a report buffer as a c-string
// provide a name for a buffer to declare (buf)
// provide a static string
// provide an integer to print after the string
#define RBUF(buf, out_len, str, num)\
unsigned char buf[sizeof(str) + 21];\
int out_len = 0;\
{\
int i = 0;\
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
(buf)[i] = str[i];\
if ((buf)[sizeof(str)-1] == 0) i--;\
if ((num) < 0) (buf)[i++] = '-';\
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
uint64_t j = 10000000000000000000ULL;\
int start = 1;\
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
(buf)[i] = '\0';\
out_len = i;\
}
#define RBUF2(buff, out_len, str, num, str2, num2)\
unsigned char buff[sizeof(str) + sizeof(str2) + 42];\
int out_len = 0;\
{\
unsigned char* buf = buff;\
int i = 0;\
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
(buf)[i] = str[i];\
if ((buf)[sizeof(str)-1] == 0) i--;\
if ((num) < 0) (buf)[i++] = '-';\
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
uint64_t j = 10000000000000000000ULL;\
int start = 1;\
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
buf += i;\
out_len += i;\
i = 0;\
for (; GUARDM(sizeof(str2),3),i < sizeof(str2); ++i)\
(buf)[i] = str2[i];\
if ((buf)[sizeof(str2)-1] == 0) i--;\
if ((num2) < 0) (buf)[i++] = '-';\
unsigned_num = (uint64_t)( (num2) < 0 ? (num2) * -1 : (num2) );\
j = 10000000000000000000ULL;\
start = 1;\
for (; GUARDM(20,4), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
(buf)[i] = '\0';\
out_len += i;\
}
#define TRACEVAR(v) trace_num((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
#define TRACEHEX(v) trace((uint32_t)(#v), (uint32_t)(sizeof(#v)), (uint32_t)(v), (uint32_t)(sizeof(v)), 1);
#define TRACEXFL(v) trace_float((uint32_t)(#v), (uint32_t)(sizeof(#v)), (int64_t)v);
#define TRACESTR(v) trace((uint32_t)(#v), (uint32_t)(sizeof(#v)), (uint32_t)(v), sizeof(v), 0);
#define CLEARBUF(b)\
{\
for (int x = 0; GUARD(sizeof(b)), x < sizeof(b); ++x)\
b[x] = 0;\
}
// returns an in64_t, negative if error, non-negative if valid drops
#define AMOUNT_TO_DROPS(amount_buffer)\
(((amount_buffer)[0] >> 7) ? -2 : (\
((((uint64_t)((amount_buffer)[0])) & 0xb00111111) << 56) +\
(((uint64_t)((amount_buffer)[1])) << 48) +\
(((uint64_t)((amount_buffer)[2])) << 40) +\
(((uint64_t)((amount_buffer)[3])) << 32) +\
(((uint64_t)((amount_buffer)[4])) << 24) +\
(((uint64_t)((amount_buffer)[5])) << 16) +\
(((uint64_t)((amount_buffer)[6])) << 8) +\
(((uint64_t)((amount_buffer)[7])))))
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
// when using this macro buf1len may be dynamic but buf2len must be static
// provide n >= 1 to indicate how many times the macro will be hit on the line of code
// e.g. if it is in a loop that loops 10 times n = 10
#define BUFFER_EQUAL_GUARD(output, buf1, buf1len, buf2, buf2len, n)\
{\
output = ((buf1len) == (buf2len) ? 1 : 0);\
for (int x = 0; GUARDM( (buf2len) * (n), 1 ), output && x < (buf2len);\
++x)\
output = (buf1)[x] == (buf2)[x];\
}
#define BUFFER_SWAP(x,y)\
{\
uint8_t* z = x;\
x = y;\
y = z;\
}
#define ACCOUNT_COMPARE(compare_result, buf1, buf2)\
{\
compare_result = 0;\
for (int i = 0; GUARD(20), i < 20; ++i)\
{\
if (buf1[i] > buf2[i])\
{\
compare_result = 1;\
break;\
}\
else if (buf1[i] < buf2[i])\
{\
compare_result = -1;\
break;\
}\
}\
}
#define BUFFER_EQUAL_STR_GUARD(output, buf1, buf1len, str, n)\
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), n)
#define BUFFER_EQUAL_STR(output, buf1, buf1len, str)\
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), 1)
#define BUFFER_EQUAL(output, buf1, buf2, compare_len)\
BUFFER_EQUAL_GUARD(output, buf1, compare_len, buf2, compare_len, 1)
#define UINT16_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT16_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 8) +\
((uint64_t)((buf)[1]) << 0))
#define UINT32_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT32_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 24) +\
((uint64_t)((buf)[1]) << 16) +\
((uint64_t)((buf)[2]) << 8) +\
((uint64_t)((buf)[3]) << 0))
#define UINT64_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 56) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT64_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 56) +\
((uint64_t)((buf)[1]) << 48) +\
((uint64_t)((buf)[2]) << 40) +\
((uint64_t)((buf)[3]) << 32) +\
((uint64_t)((buf)[4]) << 24) +\
((uint64_t)((buf)[5]) << 16) +\
((uint64_t)((buf)[6]) << 8) +\
((uint64_t)((buf)[7]) << 0))
#define INT64_FROM_BUF(buf)\
((((uint64_t)((buf)[0]&7FU) << 56) +\
((uint64_t)((buf)[1]) << 48) +\
((uint64_t)((buf)[2]) << 40) +\
((uint64_t)((buf)[3]) << 32) +\
((uint64_t)((buf)[4]) << 24) +\
((uint64_t)((buf)[5]) << 16) +\
((uint64_t)((buf)[6]) << 8) +\
((uint64_t)((buf)[7]) << 0)) * (buf[0] & 0x80U ? -1 : 1))
#define INT64_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 56) & 0x7FUL;\
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
if (i < 0) buf[0] |= 0x80U;\
}
#define ttPAYMENT 0
#define ttCHECK_CREATE 16
#define ttNFT_ACCEPT_OFFER 29
#define tfCANONICAL 0x80000000UL
#define atACCOUNT 1U
#define atOWNER 2U
#define atDESTINATION 3U
#define atISSUER 4U
#define atAUTHORIZE 5U
#define atUNAUTHORIZE 6U
#define atTARGET 7U
#define atREGULARKEY 8U
#define atPSEUDOCALLBACK 9U
#define amAMOUNT 1U
#define amBALANCE 2U
#define amLIMITAMOUNT 3U
#define amTAKERPAYS 4U
#define amTAKERGETS 5U
#define amLOWLIMIT 6U
#define amHIGHLIMIT 7U
#define amFEE 8U
#define amSENDMAX 9U
#define amDELIVERMIN 10U
#define amMINIMUMOFFER 16U
#define amRIPPLEESCROW 17U
#define amDELIVEREDAMOUNT 18U
/**
* RH NOTE -- PAY ATTENTION
*
* ALL 'ENCODE' MACROS INCREMENT BUF_OUT
* THIS IS TO MAKE CHAINING EASY
* BUF_OUT IS A SACRIFICIAL POINTER
*
* 'ENCODE' MACROS WITH CONSTANTS HAVE
* ALIASING TO ASSIST YOU WITH ORDER
* _TYPECODE_FIELDCODE_ENCODE_MACRO
* TO PRODUCE A SERIALIZED OBJECT
* IN CANONICAL FORMAT YOU MUST ORDER
* FIRST BY TYPE CODE THEN BY FIELD CODE
*
* ALL 'PREPARE' MACROS PRESERVE POINTERS
*
**/
#define ENCODE_TL_SIZE 49
#define ENCODE_TL(buf_out, tlamt, amount_type)\
{\
uint8_t uat = amount_type; \
buf_out[0] = 0x60U +(uat & 0x0FU ); \
for (int i = 1; GUARDM(48, 1), i < 49; ++i)\
buf_out[i] = tlamt[i-1];\
buf_out += ENCODE_TL_SIZE;\
}
#define _06_XX_ENCODE_TL(buf_out, drops, amount_type )\
ENCODE_TL(buf_out, drops, amount_type );
#define ENCODE_TL_AMOUNT(buf_out, drops )\
ENCODE_TL(buf_out, drops, amAMOUNT );
#define _06_01_ENCODE_TL_AMOUNT(buf_out, drops )\
ENCODE_TL_AMOUNT(buf_out, drops );
// Encode drops to serialization format
// consumes 9 bytes
#define ENCODE_DROPS_SIZE 9
#define ENCODE_DROPS(buf_out, drops, amount_type ) \
{\
uint8_t uat = amount_type; \
uint64_t udrops = drops; \
buf_out[0] = 0x60U +(uat & 0x0FU ); \
buf_out[1] = 0b01000000 + (( udrops >> 56 ) & 0b00111111 ); \
buf_out[2] = (udrops >> 48) & 0xFFU; \
buf_out[3] = (udrops >> 40) & 0xFFU; \
buf_out[4] = (udrops >> 32) & 0xFFU; \
buf_out[5] = (udrops >> 24) & 0xFFU; \
buf_out[6] = (udrops >> 16) & 0xFFU; \
buf_out[7] = (udrops >> 8) & 0xFFU; \
buf_out[8] = (udrops >> 0) & 0xFFU; \
buf_out += ENCODE_DROPS_SIZE; \
}
#define _06_XX_ENCODE_DROPS(buf_out, drops, amount_type )\
ENCODE_DROPS(buf_out, drops, amount_type );
#define ENCODE_DROPS_AMOUNT(buf_out, drops )\
ENCODE_DROPS(buf_out, drops, amAMOUNT );
#define _06_01_ENCODE_DROPS_AMOUNT(buf_out, drops )\
ENCODE_DROPS_AMOUNT(buf_out, drops );
#define ENCODE_DROPS_FEE(buf_out, drops )\
ENCODE_DROPS(buf_out, drops, amFEE );
#define _06_08_ENCODE_DROPS_FEE(buf_out, drops )\
ENCODE_DROPS_FEE(buf_out, drops );
#define ENCODE_TT_SIZE 3
#define ENCODE_TT(buf_out, tt )\
{\
uint8_t utt = tt;\
buf_out[0] = 0x12U;\
buf_out[1] =(utt >> 8 ) & 0xFFU;\
buf_out[2] =(utt >> 0 ) & 0xFFU;\
buf_out += ENCODE_TT_SIZE; \
}
#define _01_02_ENCODE_TT(buf_out, tt)\
ENCODE_TT(buf_out, tt);
#define ENCODE_ACCOUNT_SIZE 22
#define ENCODE_ACCOUNT(buf_out, account_id, account_type)\
{\
uint8_t uat = account_type;\
buf_out[0] = 0x80U + uat;\
buf_out[1] = 0x14U;\
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(account_id + 0);\
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(account_id + 8);\
*(uint32_t*)(buf_out + 18) = *(uint32_t*)(account_id + 16);\
buf_out += ENCODE_ACCOUNT_SIZE;\
}
#define _08_XX_ENCODE_ACCOUNT(buf_out, account_id, account_type)\
ENCODE_ACCOUNT(buf_out, account_id, account_type);
#define ENCODE_ACCOUNT_SRC_SIZE 22
#define ENCODE_ACCOUNT_SRC(buf_out, account_id)\
ENCODE_ACCOUNT(buf_out, account_id, atACCOUNT);
#define _08_01_ENCODE_ACCOUNT_SRC(buf_out, account_id)\
ENCODE_ACCOUNT_SRC(buf_out, account_id);
#define ENCODE_ACCOUNT_DST_SIZE 22
#define ENCODE_ACCOUNT_DST(buf_out, account_id)\
ENCODE_ACCOUNT(buf_out, account_id, atDESTINATION);
#define _08_03_ENCODE_ACCOUNT_DST(buf_out, account_id)\
ENCODE_ACCOUNT_DST(buf_out, account_id);
#define ENCODE_ACCOUNT_OWNER_SIZE 22
#define ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
ENCODE_ACCOUNT(buf_out, account_id, atOWNER);
#define _08_02_ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
ENCODE_ACCOUNT_OWNER(buf_out, account_id);
#define ENCODE_UINT32_COMMON_SIZE 5U
#define ENCODE_UINT32_COMMON(buf_out, i, field)\
{\
uint32_t ui = i; \
uint8_t uf = field; \
buf_out[0] = 0x20U +(uf & 0x0FU); \
buf_out[1] =(ui >> 24 ) & 0xFFU; \
buf_out[2] =(ui >> 16 ) & 0xFFU; \
buf_out[3] =(ui >> 8 ) & 0xFFU; \
buf_out[4] =(ui >> 0 ) & 0xFFU; \
buf_out += ENCODE_UINT32_COMMON_SIZE; \
}
#define _02_XX_ENCODE_UINT32_COMMON(buf_out, i, field)\
ENCODE_UINT32_COMMON(buf_out, i, field)\
#define ENCODE_UINT32_UNCOMMON_SIZE 6U
#define ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
{\
uint32_t ui = i; \
uint8_t uf = field; \
buf_out[0] = 0x20U; \
buf_out[1] = uf; \
buf_out[2] =(ui >> 24 ) & 0xFFU; \
buf_out[3] =(ui >> 16 ) & 0xFFU; \
buf_out[4] =(ui >> 8 ) & 0xFFU; \
buf_out[5] =(ui >> 0 ) & 0xFFU; \
buf_out += ENCODE_UINT32_UNCOMMON_SIZE; \
}
#define _02_XX_ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
#define ENCODE_LLS_SIZE 6U
#define ENCODE_LLS(buf_out, lls )\
ENCODE_UINT32_UNCOMMON(buf_out, lls, 0x1B );
#define _02_27_ENCODE_LLS(buf_out, lls )\
ENCODE_LLS(buf_out, lls );
#define ENCODE_FLS_SIZE 6U
#define ENCODE_FLS(buf_out, fls )\
ENCODE_UINT32_UNCOMMON(buf_out, fls, 0x1A );
#define _02_26_ENCODE_FLS(buf_out, fls )\
ENCODE_FLS(buf_out, fls );
#define ENCODE_TAG_SRC_SIZE 5
#define ENCODE_TAG_SRC(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0x3U );
#define _02_03_ENCODE_TAG_SRC(buf_out, tag )\
ENCODE_TAG_SRC(buf_out, tag );
#define ENCODE_TAG_DST_SIZE 5
#define ENCODE_TAG_DST(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0xEU );
#define _02_14_ENCODE_TAG_DST(buf_out, tag )\
ENCODE_TAG_DST(buf_out, tag );
#define ENCODE_SEQUENCE_SIZE 5
#define ENCODE_SEQUENCE(buf_out, sequence )\
ENCODE_UINT32_COMMON(buf_out, sequence, 0x4U );
#define _02_04_ENCODE_SEQUENCE(buf_out, sequence )\
ENCODE_SEQUENCE(buf_out, sequence );
#define ENCODE_FLAGS_SIZE 5
#define ENCODE_FLAGS(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0x2U );
#define _02_02_ENCODE_FLAGS(buf_out, tag )\
ENCODE_FLAGS(buf_out, tag );
#define ENCODE_SIGNING_PUBKEY_SIZE 35
#define ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
{\
buf_out[0] = 0x73U;\
buf_out[1] = 0x21U;\
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(pkey + 0);\
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(pkey + 8);\
*(uint64_t*)(buf_out + 18) = *(uint64_t*)(pkey + 16);\
*(uint64_t*)(buf_out + 26) = *(uint64_t*)(pkey + 24);\
buf[34] = pkey[32];\
buf_out += ENCODE_SIGNING_PUBKEY_SIZE;\
}
#define _07_03_ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
ENCODE_SIGNING_PUBKEY(buf_out, pkey );
#define ENCODE_SIGNING_PUBKEY_NULL_SIZE 35
#define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
{\
buf_out[0] = 0x73U;\
buf_out[1] = 0x21U;\
*(uint64_t*)(buf_out+2) = 0;\
*(uint64_t*)(buf_out+10) = 0;\
*(uint64_t*)(buf_out+18) = 0;\
*(uint64_t*)(buf_out+25) = 0;\
buf_out += ENCODE_SIGNING_PUBKEY_NULL_SIZE;\
}
#define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
ENCODE_SIGNING_PUBKEY_NULL(buf_out );
#define PREPARE_PAYMENT_SIMPLE_SIZE 270
#define PREPARE_PAYMENT_SIMPLE(buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw)\
{\
uint8_t* buf_out = buf_out_master;\
uint8_t acc[20];\
uint64_t drops_amount = (drops_amount_raw);\
uint32_t dest_tag = (dest_tag_raw);\
uint32_t src_tag = (src_tag_raw);\
uint32_t cls = (uint32_t)ledger_seq();\
hook_account(SBUF(acc));\
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
_06_01_ENCODE_DROPS_AMOUNT (buf_out, drops_amount ); /* amount | size 9 */ \
uint8_t* fee_ptr = buf_out;\
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
etxn_details((uint32_t)buf_out, 138); /* emitdet | size 138 */ \
int64_t fee = etxn_fee_base(buf_out_master, 270); \
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
}
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 309
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE(buf_out_master, tlamt, drops_fee_raw, to_address, dest_tag_raw, src_tag_raw)\
{\
uint8_t* buf_out = buf_out_master;\
uint8_t acc[20];\
uint64_t drops_fee = (drops_fee_raw);\
uint32_t dest_tag = (dest_tag_raw);\
uint32_t src_tag = (src_tag_raw);\
uint32_t cls = (uint32_t)ledger_seq();\
hook_account(SBUF(acc));\
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
_06_01_ENCODE_TL_AMOUNT (buf_out, tlamt ); /* amount | size 48 */ \
uint8_t* fee_ptr = buf_out;\
_06_08_ENCODE_DROPS_FEE (buf_out, drops_fee ); /* amount | size 9 */ \
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
etxn_details((uint32_t)buf_out, 138); /* emitdet | size 138 */ \
int64_t fee = etxn_fee_base(buf_out_master, 309); \
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
}
#endif

203
hook/examples/sfcodes.h Normal file
View File

@@ -0,0 +1,203 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_sfcodes.sh
#define sfCloseResolution ((16U << 16U) + 1U)
#define sfMethod ((16U << 16U) + 2U)
#define sfTransactionResult ((16U << 16U) + 3U)
#define sfTickSize ((16U << 16U) + 16U)
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
#define sfHookResult ((16U << 16U) + 18U)
#define sfLedgerEntryType ((1U << 16U) + 1U)
#define sfTransactionType ((1U << 16U) + 2U)
#define sfSignerWeight ((1U << 16U) + 3U)
#define sfTransferFee ((1U << 16U) + 4U)
#define sfVersion ((1U << 16U) + 16U)
#define sfHookStateChangeCount ((1U << 16U) + 17U)
#define sfHookEmitCount ((1U << 16U) + 18U)
#define sfHookExecutionIndex ((1U << 16U) + 19U)
#define sfHookApiVersion ((1U << 16U) + 20U)
#define sfFlags ((2U << 16U) + 2U)
#define sfSourceTag ((2U << 16U) + 3U)
#define sfSequence ((2U << 16U) + 4U)
#define sfPreviousTxnLgrSeq ((2U << 16U) + 5U)
#define sfLedgerSequence ((2U << 16U) + 6U)
#define sfCloseTime ((2U << 16U) + 7U)
#define sfParentCloseTime ((2U << 16U) + 8U)
#define sfSigningTime ((2U << 16U) + 9U)
#define sfExpiration ((2U << 16U) + 10U)
#define sfTransferRate ((2U << 16U) + 11U)
#define sfWalletSize ((2U << 16U) + 12U)
#define sfOwnerCount ((2U << 16U) + 13U)
#define sfDestinationTag ((2U << 16U) + 14U)
#define sfHighQualityIn ((2U << 16U) + 16U)
#define sfHighQualityOut ((2U << 16U) + 17U)
#define sfLowQualityIn ((2U << 16U) + 18U)
#define sfLowQualityOut ((2U << 16U) + 19U)
#define sfQualityIn ((2U << 16U) + 20U)
#define sfQualityOut ((2U << 16U) + 21U)
#define sfStampEscrow ((2U << 16U) + 22U)
#define sfBondAmount ((2U << 16U) + 23U)
#define sfLoadFee ((2U << 16U) + 24U)
#define sfOfferSequence ((2U << 16U) + 25U)
#define sfFirstLedgerSequence ((2U << 16U) + 26U)
#define sfLastLedgerSequence ((2U << 16U) + 27U)
#define sfTransactionIndex ((2U << 16U) + 28U)
#define sfOperationLimit ((2U << 16U) + 29U)
#define sfReferenceFeeUnits ((2U << 16U) + 30U)
#define sfReserveBase ((2U << 16U) + 31U)
#define sfReserveIncrement ((2U << 16U) + 32U)
#define sfSetFlag ((2U << 16U) + 33U)
#define sfClearFlag ((2U << 16U) + 34U)
#define sfSignerQuorum ((2U << 16U) + 35U)
#define sfCancelAfter ((2U << 16U) + 36U)
#define sfFinishAfter ((2U << 16U) + 37U)
#define sfSignerListID ((2U << 16U) + 38U)
#define sfSettleDelay ((2U << 16U) + 39U)
#define sfTicketCount ((2U << 16U) + 40U)
#define sfTicketSequence ((2U << 16U) + 41U)
#define sfNFTokenTaxon ((2U << 16U) + 42U)
#define sfMintedNFTokens ((2U << 16U) + 43U)
#define sfBurnedNFTokens ((2U << 16U) + 44U)
#define sfHookStateCount ((2U << 16U) + 45U)
#define sfEmitGeneration ((2U << 16U) + 46U)
#define sfIndexNext ((3U << 16U) + 1U)
#define sfIndexPrevious ((3U << 16U) + 2U)
#define sfBookNode ((3U << 16U) + 3U)
#define sfOwnerNode ((3U << 16U) + 4U)
#define sfBaseFee ((3U << 16U) + 5U)
#define sfExchangeRate ((3U << 16U) + 6U)
#define sfLowNode ((3U << 16U) + 7U)
#define sfHighNode ((3U << 16U) + 8U)
#define sfDestinationNode ((3U << 16U) + 9U)
#define sfCookie ((3U << 16U) + 10U)
#define sfServerVersion ((3U << 16U) + 11U)
#define sfNFTokenOfferNode ((3U << 16U) + 12U)
#define sfEmitBurden ((3U << 16U) + 13U)
#define sfHookOn ((3U << 16U) + 16U)
#define sfHookInstructionCount ((3U << 16U) + 17U)
#define sfHookReturnCode ((3U << 16U) + 18U)
#define sfReferenceCount ((3U << 16U) + 19U)
#define sfEmailHash ((4U << 16U) + 1U)
#define sfTakerPaysCurrency ((10U << 16U) + 1U)
#define sfTakerPaysIssuer ((10U << 16U) + 2U)
#define sfTakerGetsCurrency ((10U << 16U) + 3U)
#define sfTakerGetsIssuer ((10U << 16U) + 4U)
#define sfLedgerHash ((5U << 16U) + 1U)
#define sfParentHash ((5U << 16U) + 2U)
#define sfTransactionHash ((5U << 16U) + 3U)
#define sfAccountHash ((5U << 16U) + 4U)
#define sfPreviousTxnID ((5U << 16U) + 5U)
#define sfLedgerIndex ((5U << 16U) + 6U)
#define sfWalletLocator ((5U << 16U) + 7U)
#define sfRootIndex ((5U << 16U) + 8U)
#define sfAccountTxnID ((5U << 16U) + 9U)
#define sfNFTokenID ((5U << 16U) + 10U)
#define sfEmitParentTxnID ((5U << 16U) + 11U)
#define sfEmitNonce ((5U << 16U) + 12U)
#define sfEmitHookHash ((5U << 16U) + 13U)
#define sfBookDirectory ((5U << 16U) + 16U)
#define sfInvoiceID ((5U << 16U) + 17U)
#define sfNickname ((5U << 16U) + 18U)
#define sfAmendment ((5U << 16U) + 19U)
#define sfDigest ((5U << 16U) + 21U)
#define sfChannel ((5U << 16U) + 22U)
#define sfConsensusHash ((5U << 16U) + 23U)
#define sfCheckID ((5U << 16U) + 24U)
#define sfValidatedHash ((5U << 16U) + 25U)
#define sfPreviousPageMin ((5U << 16U) + 26U)
#define sfNextPageMin ((5U << 16U) + 27U)
#define sfNFTokenBuyOffer ((5U << 16U) + 28U)
#define sfNFTokenSellOffer ((5U << 16U) + 29U)
#define sfHookStateKey ((5U << 16U) + 30U)
#define sfHookHash ((5U << 16U) + 31U)
#define sfHookNamespace ((5U << 16U) + 32U)
#define sfHookSetTxnID ((5U << 16U) + 33U)
#define sfAmount ((6U << 16U) + 1U)
#define sfBalance ((6U << 16U) + 2U)
#define sfLimitAmount ((6U << 16U) + 3U)
#define sfTakerPays ((6U << 16U) + 4U)
#define sfTakerGets ((6U << 16U) + 5U)
#define sfLowLimit ((6U << 16U) + 6U)
#define sfHighLimit ((6U << 16U) + 7U)
#define sfFee ((6U << 16U) + 8U)
#define sfSendMax ((6U << 16U) + 9U)
#define sfDeliverMin ((6U << 16U) + 10U)
#define sfMinimumOffer ((6U << 16U) + 16U)
#define sfRippleEscrow ((6U << 16U) + 17U)
#define sfDeliveredAmount ((6U << 16U) + 18U)
#define sfNFTokenBrokerFee ((6U << 16U) + 19U)
#define sfHookCallbackFee ((6U << 16U) + 20U)
#define sfPublicKey ((7U << 16U) + 1U)
#define sfMessageKey ((7U << 16U) + 2U)
#define sfSigningPubKey ((7U << 16U) + 3U)
#define sfTxnSignature ((7U << 16U) + 4U)
#define sfURI ((7U << 16U) + 5U)
#define sfSignature ((7U << 16U) + 6U)
#define sfDomain ((7U << 16U) + 7U)
#define sfFundCode ((7U << 16U) + 8U)
#define sfRemoveCode ((7U << 16U) + 9U)
#define sfExpireCode ((7U << 16U) + 10U)
#define sfCreateCode ((7U << 16U) + 11U)
#define sfMemoType ((7U << 16U) + 12U)
#define sfMemoData ((7U << 16U) + 13U)
#define sfMemoFormat ((7U << 16U) + 14U)
#define sfFulfillment ((7U << 16U) + 16U)
#define sfCondition ((7U << 16U) + 17U)
#define sfMasterSignature ((7U << 16U) + 18U)
#define sfUNLModifyValidator ((7U << 16U) + 19U)
#define sfValidatorToDisable ((7U << 16U) + 20U)
#define sfValidatorToReEnable ((7U << 16U) + 21U)
#define sfHookStateData ((7U << 16U) + 22U)
#define sfHookReturnString ((7U << 16U) + 23U)
#define sfHookParameterName ((7U << 16U) + 24U)
#define sfHookParameterValue ((7U << 16U) + 25U)
#define sfAccount ((8U << 16U) + 1U)
#define sfOwner ((8U << 16U) + 2U)
#define sfDestination ((8U << 16U) + 3U)
#define sfIssuer ((8U << 16U) + 4U)
#define sfAuthorize ((8U << 16U) + 5U)
#define sfUnauthorize ((8U << 16U) + 6U)
#define sfRegularKey ((8U << 16U) + 8U)
#define sfNFTokenMinter ((8U << 16U) + 9U)
#define sfEmitCallback ((8U << 16U) + 10U)
#define sfHookAccount ((8U << 16U) + 16U)
#define sfIndexes ((19U << 16U) + 1U)
#define sfHashes ((19U << 16U) + 2U)
#define sfAmendments ((19U << 16U) + 3U)
#define sfNFTokenOffers ((19U << 16U) + 4U)
#define sfHookNamespaces ((19U << 16U) + 5U)
#define sfPaths ((18U << 16U) + 1U)
#define sfTransactionMetaData ((14U << 16U) + 2U)
#define sfCreatedNode ((14U << 16U) + 3U)
#define sfDeletedNode ((14U << 16U) + 4U)
#define sfModifiedNode ((14U << 16U) + 5U)
#define sfPreviousFields ((14U << 16U) + 6U)
#define sfFinalFields ((14U << 16U) + 7U)
#define sfNewFields ((14U << 16U) + 8U)
#define sfTemplateEntry ((14U << 16U) + 9U)
#define sfMemo ((14U << 16U) + 10U)
#define sfSignerEntry ((14U << 16U) + 11U)
#define sfNFToken ((14U << 16U) + 12U)
#define sfEmitDetails ((14U << 16U) + 13U)
#define sfHook ((14U << 16U) + 14U)
#define sfSigner ((14U << 16U) + 16U)
#define sfMajority ((14U << 16U) + 18U)
#define sfDisabledValidator ((14U << 16U) + 19U)
#define sfEmittedTxn ((14U << 16U) + 20U)
#define sfHookExecution ((14U << 16U) + 21U)
#define sfHookDefinition ((14U << 16U) + 22U)
#define sfHookParameter ((14U << 16U) + 23U)
#define sfHookGrant ((14U << 16U) + 24U)
#define sfSigners ((15U << 16U) + 3U)
#define sfSignerEntries ((15U << 16U) + 4U)
#define sfTemplate ((15U << 16U) + 5U)
#define sfNecessary ((15U << 16U) + 6U)
#define sfSufficient ((15U << 16U) + 7U)
#define sfAffectedNodes ((15U << 16U) + 8U)
#define sfMemos ((15U << 16U) + 9U)
#define sfNFTokens ((15U << 16U) + 10U)
#define sfHooks ((15U << 16U) + 11U)
#define sfMajorities ((15U << 16U) + 16U)
#define sfDisabledValidators ((15U << 16U) + 17U)
#define sfHookExecutions ((15U << 16U) + 18U)
#define sfHookParameters ((15U << 16U) + 19U)
#define sfHookGrants ((15U << 16U) + 20U)

View File

@@ -0,0 +1,2 @@
# HookAPI Tests
This test-set pertains to the behaviour of Hook APIs, which are tested by installing and running hooks that invoke those APIs.

View File

@@ -0,0 +1,2 @@
all:
(cd wasm; touch *.c ; make)

21
hook/tests/hookapi/run-all.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
RESULT=""
FAILCOUNT=0
PASSCOUNT=0
for i in `ls test-*.js`; do
echo Running $i
node $i 2>/dev/null >/dev/null;
if [ "$?" -eq "0" ];
then
RESULT=`echo $RESULT'~'$i' -- PASS'`
PASSCOUNT="`echo $PASSCOUNT + 1 | bc`"
else
RESULT=`echo $RESULT'~'$i' -- FAIL'`
FAILCOUNT="`echo $FAILCOUNT + 1 | bc`"
fi
done
echo
echo "Results:"
RESULT=$RESULT~
echo Passed: $PASSCOUNT, Failed: $FAILCOUNT, Total: `echo $PASSCOUNT + $FAILCOUNT | bc`
echo $RESULT | sed 's/.js//g' | tr '~' '\n'

View File

@@ -0,0 +1,40 @@
const wasmFn = 'log.wasm';
require('../hookset/utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm(wasmFn),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
TransactionType: "AccountSet",
Account: account.classicAddress
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,40 @@
const wasmFn = 'root.wasm';
require('../hookset/utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm(wasmFn),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
TransactionType: "AccountSet",
Account: account.classicAddress
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,7 @@
#include <stdint.h>
#include "../../../examples/hookapi.h"
#define ASSERT(x)\
{\
if (!(x))\
rollback(SBUF(#x), __LINE__);\
}

View File

@@ -0,0 +1,19 @@
#include "api.h"
int64_t hook(uint32_t reserved )
{
int64_t x = float_set(0, 1234567890);
int64_t l = float_log(x);
int64_t i = float_int(l, 15, 1);
ASSERT(i == 9091514977169268ULL);
ASSERT(float_log(float_one()) == 0);
// RH TODO: more tests
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,7 @@
all: log.wasm root.wasm
log.wasm: log.c
wasmcc log.c -o log.wasm -O0 -Wl,--allow-undefined -I../
hook-cleaner log.wasm
root.wasm: root.c
wasmcc root.c -o root.wasm -O0 -Wl,--allow-undefined -I../
hook-cleaner root.wasm

View File

@@ -0,0 +1,21 @@
#include "api.h"
int64_t hook(uint32_t reserved )
{
int64_t x = float_set(0, 1234567890);
int64_t l = float_root(x, 2);
TRACEXFL(l);
int64_t i = float_int(l, 6, 1);
TRACEVAR(i);
ASSERT(i == 35136418286444ULL);
// RH TODO: more tests
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,2 @@
all:
(cd wasm; make)

View File

@@ -0,0 +1,18 @@
{
"dependencies": {
"ripple-keypairs": "^1.1.3",
"ripple-lib": "^1.10.0",
"xrpl": "^2.1.1",
"xrpl-binary-codec": "^1.4.2",
"xrpl-hooks": "^2.2.1"
},
"name": "hookset",
"description": "This test set pertains to testing the functionality of installing / creating / updating / deleting hooks. In short: everything except running hooks.",
"version": "1.0.0",
"main": "''",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

21
hook/tests/hookset/run-all.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
RESULT=""
FAILCOUNT=0
PASSCOUNT=0
for i in `ls test-*.js`; do
echo Running $i
node $i 2>/dev/null >/dev/null;
if [ "$?" -eq "0" ];
then
RESULT=`echo $RESULT'~'$i' -- PASS'`
PASSCOUNT="`echo $PASSCOUNT + 1 | bc`"
else
RESULT=`echo $RESULT'~'$i' -- FAIL'`
FAILCOUNT="`echo $FAILCOUNT + 1 | bc`"
fi
done
echo
echo "Results:"
RESULT=$RESULT~
echo Passed: $PASSCOUNT, Failed: $FAILCOUNT, Total: `echo $PASSCOUNT + $FAILCOUNT | bc`
echo $RESULT | sed 's/.js//g' | tr '~' '\n'

View File

@@ -0,0 +1,42 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account1 = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis(account1).then(()=>
{
t.fundFromGenesis(account2).then(()=>
{
t.feeSubmit(account1.seed,
{
Account: account1.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('aaw.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "AccountSet"
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,30 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('blacklist.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,48 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnFailure(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,61 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = (process.argv.length < 3 ? t.randomAccount() :
t.xrpljs.Wallet.fromSeed(process.argv[2]));
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [{Hook:{}}],
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x)
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
Flags: t.hsfOVERRIDE,
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
Flags: t.hsfOVERRIDE,
CreateCode: "" // hook delete
}
}
],
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,53 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
let txn_to_send =
{
SigningPubKey: '',
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
],
SigningPubKey: ''
};
let wal = t.xrpljs.Wallet.fromSeed(account.seed);
t.api.prepareTransaction(txn_to_send, {wallet: wal}).then(txn =>
{
let ser = t.rbc.encode(txn);
t.fee(ser).then(fees =>
{
console.log(fees)
let base_drops = fees.base_fee
console.log("base_drops", base_drops)
delete txn_to_send['SigningPubKey']
txn_to_send['Fee'] = base_drops + '';
t.api.prepareTransaction(txn_to_send, {wallet: wal}).then(txn =>
{
console.log(txn)
t.api.submit(txn, {wallet: wal}).then(s=>
{
t.assertTxnSuccess(s);
console.log(s);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
});
}).catch(t.err);
}).catch(t.err);
});

View File

@@ -0,0 +1,27 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(s => {
t.assertTxnSuccess(s);
console.log(s);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
});

View File

@@ -0,0 +1,38 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('multiguard.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "AccountSet"
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,99 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.fundFromGenesis(account2).then(()=>
{
let hash = t.hookHash('checkstate.wasm')
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x)
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "SetHook",
Fee: "100000",
Hooks: [
{ Hook: {
HookHash: hash
}},
{ Hook: {
}},
{ Hook: {
HookHash: hash
}}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "SetHook",
Flags: 0,
Hooks: [
{ Hook: {
"Flags": t.hsfOVERRIDE,
"CreateCode": "",
}}
]
}).then(x=>
{
console.log(x);
t.assertTxnSuccess(x);
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "SetHook",
Flags: 0,
Hooks: [
{Hook:{}},
{Hook:{}},
{ Hook: {
HookParameters:
[
{HookParameter: {
HookParameterName: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
HookParameterValue: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB"
}}
]
}}
]
}).then(x=>
{
console.log(x);
t.assertTxnSuccess(x);
console.log("account 1 has the creation: ", account.classicAddress);
console.log("account 2 has the install and delete and update: ", account2.classicAddress);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,74 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account1 = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis([account1, account2]).then(()=>
{
t.ledgerAccept(256).then(x=>
{
t.feeSubmitAccept(account1.seed,
{
NFTokenTaxon: 0,
TransactionType: "NFTokenMint",
Account: account1.classicAddress,
TransferFee: 314,
Flags: 8,
URI: "697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E6634646675796C71616266336F636C67747179353566627A6469",
Memos: [
{
"Memo": {
"MemoType":
"687474703A2F2F6578616D706C652E636F6D2F6D656D6F2F67656E65726963",
"MemoData": "72656E74"
}
}
]
}).then(x=>
{
console.log(x)
t.assertTxnSuccess(x)
const id = t.nftid(account1.classicAddress, 8, 314, 0, 0);
t.feeSubmit(account1.seed,
{
TransactionType: "NFTokenCreateOffer",
Account: account1.classicAddress,
NFTokenID: id,
Amount: "1",
Flags: 1
}).then(x=>
{
console.log(x);
t.assertTxnSuccess(x)
t.fetchMeta(x.result.tx_json.hash).then(m=>
{
// RH UPTO
t.log(m);
process.exit(0);
}).catch(t.err);
/*
t.feeSubmit(account1.seed,
{
TransactionType: "AccountDelete",
Account: account1.classicAddress,
Destination: account2.classicAddress,
Flags: 2147483648
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
});
*/
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,34 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account1 = t.randomAccount();
t.fundFromGenesis(account1).then(()=>
{
t.feeSubmit(account1.seed,
{
NFTokenTaxon: 0,
TransactionType: "NFTokenMint",
Account: account1.classicAddress,
TransferFee: 314,
Flags: 8,
URI: "697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E6634646675796C71616266336F636C67747179353566627A6469",
Memos: [
{
"Memo": {
"MemoType":
"687474703A2F2F6578616D706C652E636F6D2F6D656D6F2F67656E65726963",
"MemoData": "72656E74"
}
}
]
}).then(x=>
{
console.log(x);
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,45 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{ Hook: { } },
{ Hook: { } },
{ Hook: { } },
{ Hook: { } }
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,59 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('makestate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{ Hook: {} },
{ Hook: {} },
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
],
Fee: "100000"
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
Flags: t.hsfNSDELETE,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,67 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('makestate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{ Hook: {} },
{ Hook: {} },
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
t.api.submit(
{
Account: account.classicAddress,
TransactionType: "AccountSet", // trigger hooks
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
Flags: t.hsfNSDELETE,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,71 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis([account, account2]).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('makestate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{
Hook: {
CreateCode: t.wasm('makestate2.wasm'),
HookApiVersion: 0,
HookNamespace: "CAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00D",
HookOn: "0000000000000000"
}
},
{ Hook: {} },
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
t.api.submit(
{
Account: account.classicAddress,
TransactionType: "AccountSet", // trigger hooks
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.ledgerAccept(255).then(x=>
{
// account delete
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "AccountDelete",
Destination: account2.classicAddress,
Flags: 2147483648
}).then(x=>
{
console.log(x);
t.assertTxnSuccess(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,83 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('makestate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{ Hook: {} },
{ Hook: {} }
]
}).then(x=>
{
t.assertTxnSuccess(x)
t.api.submit(
{
Account: account.classicAddress,
TransactionType: "AccountSet", // trigger hooks
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm("rmstate.wasm"),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000",
Flags: t.hsfOVERRIDE
},
},
{
Hook: {
Flags: t.hsfOVERRIDE,
CreateCode: ""
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
t.api.submit(
{
Account: account.classicAddress,
TransactionType: "AccountSet", // trigger hooks
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x);
process.exit(0);
});
});
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,55 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account = t.randomAccount();
t.fundFromGenesis(account).then(()=>
{
t.feeSubmit(account.seed,
{
Account: account.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('makestate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
},
{
Hook: {
CreateCode: t.wasm('makestate2.wasm'),
HookApiVersion: 0,
HookNamespace: "CAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00DCAFEF00D",
HookOn: "0000000000000000"
}
},
{ Hook: {} },
{ Hook: {
CreateCode: t.wasm('checkstate.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
t.api.submit(
{
Account: account.classicAddress,
TransactionType: "AccountSet", // trigger hooks
Fee: "100000"
}, {wallet: account}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,53 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account1 = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis(account1).then(()=>
{
t.fundFromGenesis(account2).then(()=>
{
t.feeSubmit(account1.seed,
{
Account: account1.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('rollback.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "SignerListSet",
SignerQuorum: 1,
SignerEntries:
[
{
SignerEntry:
{
Account: account1.classicAddress,
SignerWeight: 1
}
}
]
}).then(x=>
{
t.assertTxnFailure(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,115 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>{
const holder1 = t.randomAccount();
const holder2 = t.randomAccount();
const holder3 = t.randomAccount();
const holder4 = t.randomAccount();
const issuer = t.randomAccount();
t.fundFromGenesis([issuer, holder1, holder2, holder3, holder4]).then(()=>
{
t.setTshCollect([holder1, holder2, holder3, holder4]).then(()=>
{
t.trustSet(issuer, "IOU", 10000, [holder1,holder2,holder3,holder4]).then(()=>
{
t.feeSubmitAcceptMultiple(
{
TransactionType: "SetHook",
Hooks: [
{
Hook:
{
CreateCode: t.wasm('aaw.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000",
Flags: t.hsfCOLLECT
}
}
]
}, [holder1,holder2,holder3,holder4]).then(()=>
{
req = {};
req[holder1.classicAddress] = 500;
req[holder2.classicAddress] = 200;
req[holder3.classicAddress] = 80;
t.issueTokens(issuer, "IOU", req).then(()=>
{
const coffer = (offerer, issuer, currency, iouamount, dropsamount, buying) =>
{
if (typeof(issuer.classicAddress) != 'undefined')
issuer = issuer.classicAddress;
return new Promise((resolve, reject) =>
{
let txn =
{
Account: offerer.classicAddress,
TransactionType: "OfferCreate",
};
let key1 = (buying ? "TakerGets" : "TakerPays");
let key2 = (buying ? "TakerPays" : "TakerGets");
txn[key1] = dropsamount + "";
txn[key2] = {
"currency": currency,
"issuer": issuer,
"value": iouamount + ""
};
t.feeSubmitAccept(offerer.seed, txn).then(x=>
{
console.log(x);
t.assertTxnSuccess(x);
resolve(x);
}).catch(e=>reject(e));
});
};
coffer(holder1, issuer, "IOU", 10, 250000, false).then(()=> // q= 25000
{
coffer(holder2, issuer, "IOU", 12, 100000, false).then(()=> // q= 8333
{
coffer(holder3, issuer, "IOU", 14, 80000, false).then(()=> // q= 5714
{
coffer(holder4, issuer, "IOU", 30, 350000, true).then((x)=>
{
t.ledgerAccept().then(()=>
{
t.fetchMetaHookExecutions(x).then(h=>
{
t.fetchMeta(x).then(m=>
{
t.log(x);
delete m.HookExecutions;
t.log(m);
t.log(h);
console.log("Issuer:", issuer.classicAddress);
console.log("Holder 1: ", holder1.classicAddress);
console.log("Holder 2: ", holder2.classicAddress);
console.log("Holder 3: ", holder3.classicAddress);
console.log("Buyer: ", holder4.classicAddress);
console.log("(cd b; ./rippled book_offers XRP 'IOU/" + issuer.classicAddress + "');");
console.log("(cd b; ./rippled account_lines " + issuer.classicAddress + ");");
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,55 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>{
const holder1 = t.randomAccount();
const issuer = t.randomAccount();
t.fundFromGenesis([issuer, holder1]).then(()=>
{
t.feeSubmitAccept(issuer.seed,
{
Account: issuer.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook:
{
CreateCode: t.wasm('aaw.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000",
Flags: t.hsfCOLLECT
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmitAccept(holder1.seed,
{
Account: holder1.classicAddress,
TransactionType: "TrustSet",
LimitAmount: {
"currency": "IOU",
"issuer": issuer.classicAddress,
"value": "1000"
}
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.fetchMetaHookExecutions(x, t.wasmHash('aaw.wasm')).then(m=>
{
t.assert(m.length == 0, "hook executed when it should not");
console.log(m);
process.exit(0);
}).catch(t.err);
}).catch(t.err);
});
}).catch(t.err);
})

View File

@@ -0,0 +1,65 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>{
const holder1 = t.randomAccount();
const issuer = t.randomAccount();
t.fundFromGenesis([issuer, holder1]).then(()=>
{
t.feeSubmitAccept(issuer.seed,
{
Account: issuer.classicAddress,
TransactionType: "AccountSet",
SetFlag: t.asfTshCollect
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmitAccept(issuer.seed,
{
Account: issuer.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook:
{
CreateCode: t.wasm('aaw.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x);
console.log(x);
t.feeSubmitAccept(holder1.seed,
{
Account: holder1.classicAddress,
TransactionType: "TrustSet",
LimitAmount: {
"currency": "IOU",
"issuer": issuer.classicAddress,
"value": "1000"
}
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.fetchMetaHookExecutions(x, t.wasmHash('aaw.wasm')).then(m=>
{
console.log(m);
t.assert(m.length == 0, "hook executed when it should not");
process.exit(0);
});
}).catch(t.err);
}).catch(t.err);
});
}).catch(t.err);
})

View File

@@ -0,0 +1,67 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>{
const holder1 = t.randomAccount();
const issuer = t.randomAccount();
t.fundFromGenesis([issuer, holder1]).then(()=>
{
t.feeSubmitAccept(issuer.seed,
{
Account: issuer.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook:
{
CreateCode: t.wasm('aaw.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000",
Flags: t.hsfCOLLECT
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmitAccept(issuer.seed,
{
Account: issuer.classicAddress,
TransactionType: "AccountSet",
SetFlag: t.asfTshCollect
}).then(x=>
{
t.assertTxnSuccess(x);
console.log(x);
t.feeSubmitAccept(holder1.seed,
{
Account: holder1.classicAddress,
TransactionType: "TrustSet",
LimitAmount: {
"currency": "IOU",
"issuer": issuer.classicAddress,
"value": "1000"
}
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.fetchMetaHookExecutions(x, t.wasmHash('aaw.wasm')).then(m=>
{
t.assert(m.length == 1, "needed exactly one hook execution");
t.assert(m[0].HookReturnCode == 100, "non-weak execution");
console.log(m);
process.exit(0);
});
}).catch(t.err);
}).catch(t.err);
});
}).catch(t.err);
})

View File

@@ -0,0 +1,53 @@
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
{
const account1 = t.randomAccount();
const account2 = t.randomAccount();
t.fundFromGenesis(account1).then(()=>
{
t.fundFromGenesis(account2).then(()=>
{
t.feeSubmit(account1.seed,
{
Account: account1.classicAddress,
TransactionType: "SetHook",
Hooks: [
{
Hook: {
CreateCode: t.wasm('accept.wasm'),
HookApiVersion: 0,
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
HookOn: "0000000000000000"
}
}
],
}).then(x=>
{
t.assertTxnSuccess(x)
console.log(x);
t.feeSubmit(account2.seed,
{
Account: account2.classicAddress,
TransactionType: "SignerListSet",
SignerQuorum: 1,
SignerEntries:
[
{
SignerEntry:
{
Account: account1.classicAddress,
SignerWeight: 1
}
}
]
}).then(x=>
{
t.assertTxnSuccess(x)
process.exit(0);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
}).catch(t.err);
})

View File

@@ -0,0 +1,52 @@
// RC: 50 : strong execution
// RC: 100 : weak execution (collect call)
// RC: 150 : again as weak (not collect / after strong)
// RC: 200 : callback execution
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t hook_again (void);
extern int64_t trace( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
extern int64_t trace_num (uint32_t, uint32_t, uint64_t);
extern int64_t meta_slot(uint32_t);
extern int64_t slot(uint32_t, uint32_t, uint32_t);
#define SBUF(x) (uint32_t)((void*)x), sizeof(x)
int64_t cbak(uint32_t what)
{
accept (SBUF("Callback execution"),200);
}
int64_t hook(uint32_t reserved )
{
if (reserved == 0)
{
hook_again();
accept (SBUF("Strong execution"),50);
}
int64_t result =
meta_slot(1);
trace_num(SBUF("meta_slot(1): "), result);
uint8_t dump[1024];
result = slot(SBUF(dump), 1);
trace_num(SBUF("slot(1): "), result);
trace(SBUF("dumped txmeta:"), dump, result, 1);
if (reserved == 1)
accept(SBUF("Weak execution (COLLECT)"), 100);
else
accept(SBUF("AAW execution"), 150);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,20 @@
/**
* This hook just accepts any transaction coming through it
*/
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,20 @@
/**
* This hook just accepts any transaction coming through it
*/
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
int64_t cbak(int64_t what)
{
return 0;
}
int64_t hook(int64_t reserved )
{
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,42 @@
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t state (uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
extern int64_t trace_num (uint32_t a, uint32_t b, uint64_t i);
#define SBUF(x) x, sizeof(x)
#define GUARD(n) _g(__LINE__, n+1)
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
uint8_t test[] = "hello world!";
uint8_t test_key[32];
for (int i = 0; GUARD(32), i < 32; ++i)
test_key[i] = i;
uint8_t buf[128];
int64_t result = state(SBUF(buf), SBUF(test_key));
if (result <= 0)
{
trace_num(SBUF("state call failed"), result);
rollback(SBUF("state call failed"), 2);
}
for (int i = 0; GUARD(sizeof(test)+1), i < sizeof(test); ++i)
if (test[i] != buf[i])
rollback(SBUF("hook state did not match expected value"), 1);
accept(SBUF("hook state matched expected value"),0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,16 @@
#include <stdint.h>
extern int32_t volatile _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t trace_num(uint32_t, uint32_t, int64_t);
int64_t hook(uint32_t r)
{
const int x = r;
for (int i = 0; trace_num(0,0,0), _g(11, 12), i < 5; ++i)
{
trace_num("hi", 2, i);
}
accept(0,0,0);
return 0;
}

View File

@@ -0,0 +1,31 @@
all: accept.wasm makestate.wasm makestate2.wasm checkstate.wasm rollback.wasm aaw.wasm rmstate.wasm ginv.wasm multiguard.wasm
accept.wasm: accept.c
wasmcc accept.c -o accept.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner accept.wasm
rollback.wasm: rollback.c
wasmcc rollback.c -o rollback.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner rollback.wasm
makestate.wasm: makestate.c
wasmcc makestate.c -o makestate.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner makestate.wasm
makestate2.wasm: makestate2.c
wasmcc makestate2.c -o makestate2.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner makestate2.wasm
checkstate.wasm: checkstate.c
wasmcc checkstate.c -o checkstate.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner checkstate.wasm
rmstate.wasm: rmstate.c
wasmcc rmstate.c -o rmstate.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner rmstate.wasm
aaw.wasm: aaw.c
wasmcc aaw.c -o aaw.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner aaw.wasm
ginv.wasm: ginv.c
wasmcc ginv.c -o ginv.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner ginv.wasm
multiguard.wasm: multiguard.c
wasmcc multiguard.c -o multiguard.wasm -O2 -Wl,--allow-undefined -I../
hook-cleaner multiguard.wasm

View File

@@ -0,0 +1,31 @@
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t state_set (uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
extern int64_t trace_num (uint32_t a, uint32_t b, uint64_t i);
#define SBUF(x) x, sizeof(x)
#define GUARD(n) _g(__LINE__, n+1)
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
uint8_t test[] = "hello world!";
trace_num(SBUF("location of test[]:"), test);
uint8_t test_key[32];
for (int i = 0; GUARD(32), i < 32; ++i)
test_key[i] = i;
int64_t result = state_set(SBUF(test), SBUF(test_key));
trace_num(SBUF("state_set result:"), result);
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,37 @@
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t state_set (uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
extern int64_t trace_num (uint32_t a, uint32_t b, uint64_t i);
#define SBUF(x) x, sizeof(x)
#define GUARD(n) _g(__LINE__, n+1)
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
uint8_t test[] = "hello world!";
uint8_t test2[] = "this is a much longer test string";
trace_num(SBUF("location of test[]:"), test);
uint8_t test_key[32];
for (int i = 0; GUARD(32), i < 32; ++i)
test_key[i] = i;
int64_t result = state_set(SBUF(test), SBUF(test_key));
trace_num(SBUF("state_set result:"), result);
uint8_t zero_key[32];
result = state_set(SBUF(test2), SBUF(zero_key));
trace_num(SBUF("state_set result:"), result);
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,31 @@
/**
* This hook just accepts any transaction coming through it
*/
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t trace_num(uint32_t, uint32_t, int64_t);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
for (int i = 0; i < 5; ++i)
{
_g(1,60); // every hook needs to import guard function and use it at least once
int c = i * 2;
while(c--)
{
trace_num("hi", 2, c);
_g(2, 60);
}
}
accept (0,0,0);
// unreachable
return 0;
}

View File

@@ -0,0 +1,29 @@
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t state_set (uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
extern int64_t trace_num (uint32_t a, uint32_t b, uint64_t i);
#define SBUF(x) x, sizeof(x)
#define GUARD(n) _g(__LINE__, n+1)
int64_t cbak(uint32_t what)
{
return 0;
}
int64_t hook(uint32_t reserved )
{
uint8_t test_key[32];
for (int i = 0; GUARD(32), i < 32; ++i)
test_key[i] = i;
int64_t result = state_set(0,0, SBUF(test_key));
trace_num(SBUF("state_set result:"), result);
accept (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

View File

@@ -0,0 +1,15 @@
/**
* This hook just accepts any transaction coming through it
*/
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
int64_t hook(uint32_t reserved )
{
rollback (0,0,0);
_g(1,1); // every hook needs to import guard function and use it at least once
// unreachable
return 0;
}

583
hook/utils-tests.js Normal file
View File

@@ -0,0 +1,583 @@
const fs = require('fs')
const xrpljs = require('xrpl-hooks');
const kp = require('ripple-keypairs');
const crypto = require('crypto')
const rbc = require('xrpl-binary-codec')
const rac = require('ripple-address-codec');
const err = (x) =>
{
console.log(x); process.exit(1);
}
// Fails via process.exit
module.exports = {
TestRig: (endpoint)=>
{
return new Promise((resolve, reject)=>
{
const api = new xrpljs.Client(endpoint);
const nftid = (acc, flags, fee, taxon, mintseq) =>
{
if (typeof(acc.classicAddress) != "undefined")
acc = acc.classicAddress;
acc = rac.decodeAccountID(acc);
const ts = mintseq;
const tax =(taxon ^ ((384160001 * ts) + 2459));
const id = Buffer.from([
(flags >> 8) & 0xFF,
flags & 0xFF,
(fee >> 8) & 0xFF,
fee & 0xFF,
acc[0],
acc[1],
acc[2],
acc[3],
acc[4],
acc[5],
acc[6],
acc[7],
acc[8],
acc[9],
acc[10],
acc[11],
acc[12],
acc[13],
acc[14],
acc[15],
acc[16],
acc[17],
acc[18],
acc[19],
(tax >> 24) & 0xFF,
(tax >> 16) & 0xFF,
(tax >> 8) & 0xFF,
tax & 0xFF,
(ts >> 24) & 0xFF,
(ts >> 16) & 0xFF,
(ts >> 8) & 0xFF,
ts & 0xFF
], 'binary').toString('hex').toUpperCase()
return id;
};
const fee = (tx_blob) =>
{
return new Promise((resolve, reject) =>
{
let req = {command: 'fee'};
if (tx_blob)
req['tx_blob'] = tx_blob;
api.request(req).then(resp =>
{
resolve(resp.result.drops);
}).catch(e =>
{
reject(e);
});
});
};
const ledgerAccept = (n) =>
{
return new Promise((resolve, reject) =>
{
const la = (remaining) =>
{
let req = {command: 'ledger_accept'};
api.request(req).then(resp =>
{
if (remaining <= 0)
resolve(resp);
la(remaining - 1);
}).catch(e=>reject(e));
};
la(typeof(n) == 'undefined' ? 1 : n);
});
};
const assertTxnSuccess = x =>
{
if (!x || !x.result || x.result.engine_result_code != 0)
{
console.log("Transaction failed:", x)
process.exit(1);
}
};
const assert = (x, m) =>
{
if (!(x))
{
console.log("Assertion failed: ", m);
console.log(new Error().stack);
process.exit(1);
}
};
const fetchMeta = (hash) =>
{
if (typeof(hash) != 'string')
hash = hash.result.tx_json.hash
return new Promise((resolve, reject) =>
{
api.request(
{
command:"tx",
transaction: hash
}).then(e=>{
resolve(e.result.meta)
}).catch(e=>reject(e));
});
};
const fetchMetaHookExecutions = (hash, hookhash) =>
{
return new Promise((resolve, reject) =>
{
fetchMeta(hash).then(m=>
{
if (typeof(m) == 'undefined' ||
typeof(m.HookExecutions) == 'undefined' ||
typeof(m.HookExecutions.length) == 'undefined')
{
return resolve([])
}
let ret = [];
for (let i = 0; i < m.HookExecutions.length; ++i)
{
if (typeof(hookhash) == 'undefined' ||
m.HookExecutions[i].HookExecution.HookHash == hookhash)
m.HookExecutions[i].HookExecution.HookReturnCode =
parseInt(m.HookExecutions[i].HookExecution.HookReturnCode, 16);
m.HookExecutions[i].HookExecution.HookInstructionCount =
parseInt(m.HookExecutions[i].HookExecution.HookInstructionCount, 16);
let s = m.HookExecutions[i].HookExecution.HookReturnString;
if (s != '')
m.HookExecutions[i].HookExecution.HookReturnString =
Buffer.from(s, 'hex').toString('utf-8')
ret.push(m.HookExecutions[i].HookExecution);
}
resolve(ret);
}).catch(e=>reject(e));
});
};
const assertTxnFailure = x =>
{
if (!x || !x.result || x.result.engine_result_code == 0)
{
console.log("Transaction failed:", x)
process.exit(1);
}
};
const wasm = (x) =>
{
console.log('wasm(' + x + ')');
try
{
return fs.readFileSync(x).toString('hex').toUpperCase();
}
catch (e) {}
try
{
return fs.readFileSync('wasm/' + x).toString('hex').toUpperCase();
}
catch (e) {}
console.log("Could not find " + x)
process.exit(1);
};
const wasmHash = (x)=>
{
const blob = wasm(x);
return crypto.createHash('SHA512').
update(Buffer.from(blob, 'hex')).
digest().slice(0,32).toString('hex').toUpperCase();
}
const feeCompute = (account_seed, txn_org) =>
{
return new Promise((resolve, reject) =>
{
txn_to_send = { ... txn_org };
txn_to_send['SigningPubKey'] = '';
let wal = xrpljs.Wallet.fromSeed(account_seed);
api.prepareTransaction(txn_to_send, {wallet: wal}).then(txn =>
{
let ser = rbc.encode(txn);
fee(ser).then(fees =>
{
let base_drops = fees.base_fee
delete txn_to_send['SigningPubKey']
txn_to_send['Fee'] = base_drops + '';
api.request(
{
command: "account_info",
account: txn.Account
}).then(y=>
{
let seq = (y.result.account_data.Sequence);
txn_to_send.Sequence = seq;
api.prepareTransaction(txn_to_send, {wallet: wal}).then(txn =>
{
resolve(txn);
}).catch(e=>{reject(e);});
}).catch(e=>{reject(e);});
}).catch(e=>{reject(e);});
}).catch(e=>{reject(e);});
});
}
const feeSubmitAccept = (seed, txn) =>
{
return new Promise((resolve, reject) =>
{
feeSubmit(seed, txn).then(x=>
{
ledgerAccept().then(()=>
{
resolve(x);
}).catch(e=>
{
reject(e);
});
}).catch(e =>
{
reject(e);
});
});
}
const feeSubmit = (seed, txn) =>
{
return new Promise((resolve, reject) =>
{
feeCompute(seed, txn).then(txn=>
{
api.submit(txn,
{wallet: xrpljs.Wallet.fromSeed(seed)}).then(s=>
{
resolve(s);
}).catch(e=>{reject(e);});
}).catch(e=>{reject(e);});
});
}
const genesisseed = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
const genesisaddr = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh';
const genesis = xrpljs.Wallet.fromSeed(genesisseed);
const randomAccount = ()=>
{
const acc = xrpljs.Wallet.fromSeed(kp.generateSeed());
console.log(acc)
return acc
};
const pay_mock = (seed, amt, dest) =>
{
if (dest.classicAddress != undefined)
dest = dest.classicAddress;
return new Promise((resolve, reject) =>
{
let wal = xrpljs.Wallet.fromSeed(seed);
api.prepareTransaction({
Account: wal.classicAddress,
TransactionType: "Payment",
Amount: ''+amt,
Destination: dest,
SigningPubKey: ''
}, {wallet: wal}).then(txn =>
{
resolve(rbc.encode(txn));
}).catch(e=>
{
reject(e);
});
});
}
const pay = (seed, amt, dest) =>
{
if (dest.classicAddress != undefined)
dest = dest.classicAddress;
return new Promise((resolve, reject) =>
{
let wal = xrpljs.Wallet.fromSeed(seed);
feeSubmit(seed, {
Account: wal.classicAddress,
TransactionType: "Payment",
Amount: ''+amt,
Destination: dest
}).then(x=>
{
assertTxnSuccess(x);
resolve(x);
}).catch(err);
});
};
const hookHash = fn =>
{
let b = fs.readFileSync('wasm/' + fn);
return crypto.createHash('SHA512').update(b).digest().slice(0,32).toString('hex').toUpperCase()
}
const fundFromGenesis = (acc) =>
{
return new Promise((resolve, reject) =>
{
const ffg = (acc, after) =>
{
if (typeof(acc) != 'string')
acc = acc.classicAddress;
console.log('ffg: ' + acc);
feeSubmitAccept(genesis.seed, {
Account: genesis.classicAddress, // fund account from genesis
TransactionType: "Payment",
Amount: "1000000000",
Destination: acc,
}).then(x=>
{
assertTxnSuccess(x);
if (after)
return after();
else
resolve();
}).catch(err);
};
const doFfg = (acc) =>
{
if (typeof(acc.length) == 'undefined')
return ffg(acc);
else if (acc.length == 1)
return ffg(acc[0]);
else
{
return ffg(acc[0],
((acc)=>{
return ()=>{
acc.shift();
return doFfg(acc);
};
})(acc));
}
}
return doFfg(acc);
});
};
const trustSet = (issuer, currency, limit, holders) =>
{
if (typeof(issuer.classicAddress) != 'undefined')
issuer = issuer.classicAddress;
return new Promise((resolve, reject)=>
{
const doTs = (holder) =>
{
if (holder.length == 0)
return resolve();
let h = holder.shift();
feeSubmitAccept(h.seed,
{
Account: h.classicAddress,
TransactionType: "TrustSet",
LimitAmount: {
"currency": currency + "",
"issuer": issuer,
"value": limit + ""
}
}).then(x=>
{
console.log(x)
assertTxnSuccess(x);
return doTs(holder);
}).catch(e=>reject(e));
};
doTs(holders);
});
};
const issueTokens = (issuer, currency, toWhom) =>
{
return new Promise((resolve, reject) =>
{
const itf = (issuer, currency, toWhom) =>
{
let c = 0;
for (let next in toWhom)
{
c++;
let addr = next;
let amt = toWhom[addr];
delete toWhom[addr];
let txn =
{
Account: issuer.classicAddress,
TransactionType: "Payment",
Amount: {
"currency": currency,
"value": amt + "",
"issuer": issuer.classicAddress
},
Destination: addr
};
feeSubmitAccept(issuer.seed, txn).then(x=>
{
console.log(x);
assertTxnSuccess(x);
return itf(issuer, currency, toWhom);
}).catch(e=>reject(e));
break;
}
if (c == 0)
resolve();
};
return itf(issuer, currency, toWhom);
});
};
const setTshCollect = (accounts) =>
{
return new Promise((resolve, reject) =>
{
const stc = (accounts) =>
{
if (accounts.length == 0)
return resolve();
let acc = accounts.shift();
feeSubmitAccept(acc.seed,
{
Account: acc.classicAddress,
TransactionType: "AccountSet",
SetFlag: 11
}).then(x=>
{
console.log(x);
assertTxnSuccess(x);
return stc(accounts);
}).catch(e=>reject(e));
};
stc(accounts);
});
}
const feeSubmitAcceptMultiple = (txn, accounts) =>
{
return new Promise((resolve, reject) =>
{
const stc = (accounts) =>
{
if (accounts.length == 0)
return resolve();
let acc = accounts.shift();
let txn_to_submit = { ... txn };
txn_to_submit['Account'] = acc.classicAddress;
feeSubmitAccept(acc.seed, txn_to_submit).then(x=>
{
console.log(x);
assertTxnSuccess(x);
return stc(accounts);
}).catch(e=>reject(e));
};
stc(accounts);
});
}
const log = m =>
{
// console.log(JSON.stringify(m, null, 4));
console.dir(m, {depth:null});
}
api.connect().then(()=>
{
resolve({
rbc: rbc,
api: api,
xrpljs: xrpljs,
assertTxnSuccess: assertTxnSuccess,
assertTxnFailure: assertTxnFailure,
wasm: wasm,
kp: kp,
genesis: genesis,
randomAccount: randomAccount,
fundFromGenesis: fundFromGenesis,
err: err,
hsfOVERRIDE: 1,
hsfNSDELETE: 2,
hsfCOLLECT: 4,
asfTshCollect: 11,
hookHash: hookHash,
pay: pay,
pay_mock: pay_mock,
fee: fee,
genesisseed: genesisseed,
genesisaddr: genesisaddr,
feeCompute: feeCompute,
feeSubmit: feeSubmit,
feeSubmitAccept: feeSubmitAccept,
ledgerAccept: ledgerAccept,
fetchMeta: fetchMeta,
fetchMetaHookExecutions: fetchMetaHookExecutions,
wasmHash: wasmHash,
assert: assert,
trustSet: trustSet,
issueTokens: issueTokens,
log: log,
setTshCollect: setTshCollect,
feeSubmitAcceptMultiple: feeSubmitAcceptMultiple,
nftid: nftid
});
}).catch(err);
});
}
};