mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-28 09:30:10 +00:00
remove js tests for hooks
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* This hook just accepts any transaction coming through it
|
||||
*/
|
||||
#define HAS_CALLBACK
|
||||
#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;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
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));
|
||||
@@ -1,5 +0,0 @@
|
||||
all:
|
||||
wasmcc accept.c -o /tmp/accept.wasm -O0 -Wl,--allow-undefined -I../
|
||||
wasm-opt -O2 /tmp/accept.wasm -o accept.wasm
|
||||
hook-cleaner accept.wasm
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#define HAS_CALLBACK
|
||||
#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;
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
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));
|
||||
@@ -1,5 +0,0 @@
|
||||
all:
|
||||
wasmcc carbon.c -o /tmp/carbon.wasm -O0 -Wl,--allow-undefined -I../
|
||||
wasm-opt -O2 /tmp/carbon.wasm -o carbon.wasm
|
||||
hook-cleaner carbon.wasm
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
//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;
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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));
|
||||
@@ -1,5 +0,0 @@
|
||||
all:
|
||||
wasmcc doubler.c -o /tmp/doubler.wasm -O0 -Wl,--allow-undefined -I../
|
||||
wasm-opt -O2 /tmp/doubler.wasm -o doubler.wasm
|
||||
hook-cleaner doubler.wasm
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// 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
|
||||
@@ -1,540 +0,0 @@
|
||||
// For documentation please see: https://xrpl-hooks.readme.io/reference/
|
||||
// Generated using generate_extern.sh
|
||||
#include <stdint.h>
|
||||
#ifndef HOOK_EXTERN
|
||||
|
||||
extern int32_t
|
||||
__attribute__((noduplicate))
|
||||
_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
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
headergen/generate_error.sh > error.h
|
||||
headergen/generate_extern.sh > extern.h
|
||||
headergen/generate_sfcodes.sh > sfcodes.h
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Bash scripts herein will generate up to date headers from the Hooks source.
|
||||
You must pipe them into the desired output file.
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/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'
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/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' | sed -E 's/^(_g\()/__attribute__((noduplicate))\n\1/g'
|
||||
echo '#define HOOK_EXTERN'
|
||||
echo '#endif //HOOK_EXTERN'
|
||||
@@ -1,30 +0,0 @@
|
||||
#/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)")}'
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* 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 KEYLET_NFT_OFFER 23
|
||||
|
||||
#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
|
||||
@@ -1,559 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG 0
|
||||
#else
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#define TRACEVAR(v) if (DEBUG) trace_num((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
#define TRACEHEX(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), (uint32_t)(sizeof(v)), 1);
|
||||
#define TRACEXFL(v) if (DEBUG) trace_float((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
#define TRACESTR(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), sizeof(v), 0);
|
||||
|
||||
// hook developers should use this guard macro, simply GUARD(<maximum iterations>)
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
#define GUARDM(maxiter, n) _g(( (1ULL << 31U) + (__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 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] & 0x7FU) << 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 );
|
||||
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 248U
|
||||
#endif
|
||||
|
||||
#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 */ \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 309
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 287
|
||||
#endif
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE(buf_out_master, tlamt, to_address, dest_tag_raw, src_tag_raw)\
|
||||
{\
|
||||
uint8_t* buf_out = buf_out_master;\
|
||||
uint8_t acc[20];\
|
||||
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, 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, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
all:
|
||||
wasmcc notary.c -o /tmp/notary.wasm -O0 -Wl,--allow-undefined -I../
|
||||
wasm-opt -O2 /tmp/notary.wasm -o notary.wasm
|
||||
hook-cleaner notary.wasm
|
||||
|
||||
@@ -1,454 +0,0 @@
|
||||
/**
|
||||
* Notary.c - An example hook for collecting signatures for multi-sign transactions without blocking sequence number
|
||||
* on the account.
|
||||
*
|
||||
* Author: Richard Holland
|
||||
* Date: 11 Feb 2021
|
||||
*
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../hookapi.h"
|
||||
|
||||
// maximum tx blob
|
||||
#define MAX_MEMO_SIZE 4096
|
||||
// LastLedgerSeq must be this far ahead of current to submit a new txn blob
|
||||
#define MINIMUM_FUTURE_LEDGER 60
|
||||
|
||||
|
||||
/**
|
||||
* Notary - easy multisign with Hooks
|
||||
* Two modes of operation:
|
||||
* 1. Attach a proposed transaction to a memo and send it to the hook account
|
||||
* 2. Endorse an already proposed transaction by using its unique ID as invoice ID and sending a 1 drop payment
|
||||
* to the hook.
|
||||
*
|
||||
* This hook relies on the signer list on the account the hook is running on.
|
||||
* Only accounts on this list can propse and endorse multisign transactions through this Hook.
|
||||
*/
|
||||
|
||||
int64_t hook(uint32_t reserved)
|
||||
{
|
||||
// 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);
|
||||
|
||||
etxn_reserve(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);
|
||||
if (account_field_len < 20) // negative values indicate errors from every api
|
||||
rollback(SBUF("Notary: sfAccount field missing!!!"), 10); // 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)
|
||||
accept(SBUF("Notary: Outgoing transaction"), 20);
|
||||
|
||||
|
||||
uint8_t tx_blob[MAX_MEMO_SIZE];
|
||||
int64_t tx_len = 0;
|
||||
uint8_t invoice_id[32];
|
||||
|
||||
int64_t invoice_id_len =
|
||||
otxn_field(SBUF(invoice_id), sfInvoiceID);
|
||||
|
||||
// check if an invoice ID was provided... this would be mode 2 above
|
||||
if (invoice_id_len == 32)
|
||||
{
|
||||
// it was, so this is an attempt at endorsing an existing proposed multisig transaction
|
||||
|
||||
// attempt to retrieve the proposed txn blob from the Hook State by setting the last nibble of the invoice ID
|
||||
// to `F` and using it as state key
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + 0x0FU;
|
||||
tx_len = state(SBUF(tx_blob), SBUF(invoice_id));
|
||||
if (tx_len < 0)
|
||||
rollback(SBUF("Notary: Received invoice id that did not correspond to a submitted multisig txn."), 1);
|
||||
|
||||
|
||||
// proposed txn exists... but it may have expired so we need to check that first
|
||||
int64_t lls_lookup = sto_subfield(tx_blob, tx_len, sfLastLedgerSequence);
|
||||
uint8_t* lls_ptr = SUB_OFFSET(lls_lookup) + tx_blob;
|
||||
uint32_t lls_len = SUB_LENGTH(lls_lookup);
|
||||
|
||||
if (lls_len != 4 || UINT32_FROM_BUF(lls_ptr) < ledger_seq())
|
||||
{
|
||||
// expired or invalid tx, purging
|
||||
if (state_set(0, 0, SBUF(invoice_id)) < 0)
|
||||
rollback(SBUF("Notary: Error erasing old txn blob."), 40);
|
||||
|
||||
accept(SBUF("Notary: Multisig txn was too old (last ledger seq passed) and was erased."), 1);
|
||||
}
|
||||
// execution to here means the invoice ID corresponded to a currently valid proposed multisig transaction
|
||||
// that exists in the Hook State for this account
|
||||
// however we still need to check if this user is on the signer list before proceeding.
|
||||
}
|
||||
|
||||
|
||||
// check for the presence of a memo
|
||||
uint8_t memos[MAX_MEMO_SIZE];
|
||||
int64_t memos_len = otxn_field(SBUF(memos), sfMemos);
|
||||
|
||||
uint32_t payload_len = 0;
|
||||
uint8_t* payload_ptr = 0;
|
||||
|
||||
// if there is a memo present then we are in mode 1 above, but we need to ensure the user isn't invoking
|
||||
// undefined behaviour by making them pick either mode 1 or mode 2:
|
||||
|
||||
if (memos_len <= 0 && invoice_id_len <= 0)
|
||||
accept(SBUF("Notary: Incoming txn with neither memo nor invoice ID, passing."), 0);
|
||||
|
||||
if (memos_len > 0 && invoice_id_len > 0)
|
||||
rollback(SBUF("Notary: Incoming txn with both memo and invoice ID, abort."), 0);
|
||||
|
||||
// now check if the sender is on the signer list
|
||||
// we can do this by first creating a keylet that describes the signer list on the hook account
|
||||
uint8_t keylet[34];
|
||||
CLEARBUF(keylet);
|
||||
if (util_keylet(SBUF(keylet), KEYLET_SIGNERS, SBUF(hook_accid), 0, 0, 0, 0) != 34)
|
||||
rollback(SBUF("Notary: Internal error, could not generate keylet"), 10);
|
||||
|
||||
// then requesting XRPLD slot that keylet into a new slot for us
|
||||
int64_t slot_no = slot_set(SBUF(keylet), 0);
|
||||
TRACEVAR(slot_no);
|
||||
if (slot_no < 0)
|
||||
rollback(SBUF("Notary: Could not set keylet in slot"), 10);
|
||||
|
||||
// once slotted we can examine the signer list object
|
||||
// the first field we are interested in is the required quorum to actually pass a multisign transaction
|
||||
int64_t result = slot_subfield(slot_no, sfSignerQuorum, 0);
|
||||
if (result < 0)
|
||||
rollback(SBUF("Notary: Could not find sfSignerQuorum on hook account"), 20);
|
||||
|
||||
// we will retrieve the 4 byte quorum into a buffer, in future the will be a shortcut for this
|
||||
uint32_t signer_quorum = 0;
|
||||
uint8_t buf[4];
|
||||
result = slot(SBUF(buf), result);
|
||||
if (result != 4)
|
||||
rollback(SBUF("Notary: Could not fetch sfSignerQuorum from sfSignerEntries."), 80);
|
||||
|
||||
// then conver the four byte buffer to an unsigned 32 bit integer
|
||||
signer_quorum = UINT32_FROM_BUF(buf);
|
||||
TRACEVAR(signer_quorum); // print the integer for debugging purposes
|
||||
|
||||
// next we want to examine the signer entries, we can do this by loading the signer entries field into a new slot
|
||||
// or in this case we'll just reuse the existing slot since we're done with the parent object.
|
||||
result = slot_subfield(slot_no, sfSignerEntries, slot_no);
|
||||
if (result < 0)
|
||||
rollback(SBUF("Notary: Could not find sfSignerEntries on hook account"), 20);
|
||||
|
||||
// since sfSignerEntries is an array type we can request its length with slot_count
|
||||
int64_t signer_count = slot_count(slot_no);
|
||||
if (signer_count < 0)
|
||||
rollback(SBUF("Notary: Could not fetch sfSignerEntries count"), 30);
|
||||
|
||||
|
||||
// now we need to iterate through all the signers in the signer entries array
|
||||
// if the account that created the originating transaction is in the list then we can pass here
|
||||
// otherwise we must rollback because the account is unauthorized
|
||||
int subslot = 0;
|
||||
uint8_t found = 0;
|
||||
uint16_t signer_weight = 0;
|
||||
|
||||
for (int i = 0; GUARD(8), i < signer_count + 1; ++i)
|
||||
{
|
||||
// load the next array entry into a slot
|
||||
subslot = slot_subarray(slot_no, i, subslot);
|
||||
if (subslot < 0)
|
||||
rollback(SBUF("Notary: Could not fetch one of the sfSigner entries [subarray]."), 40);
|
||||
|
||||
// load the account field from that entry into a new slot
|
||||
result = slot_subfield(subslot, sfAccount, 0);
|
||||
if (result < 0)
|
||||
rollback(SBUF("Notary: Could not fetch one of the account entires in sfSigner."), 50);
|
||||
|
||||
// dump the new slot into a buffer
|
||||
uint8_t signer_account[20];
|
||||
result = slot(SBUF(signer_account), result);
|
||||
if (result != 20)
|
||||
rollback(SBUF("Notary: Could not fetch one of the sfSigner entries [slot sfAccount]."), 60);
|
||||
|
||||
// load the weight field into a new slot
|
||||
result = slot_subfield(subslot, sfSignerWeight, 0);
|
||||
if (result < 0)
|
||||
rollback(SBUF("Notary: Could not fetch sfSignerWeight from sfSignerEntry."), 70);
|
||||
|
||||
// dump the weight field into a buffer
|
||||
result = slot(buf, 2, result);
|
||||
|
||||
if (result != 2)
|
||||
rollback(SBUF("Notary: Could not fetch sfSignerWeight from sfSignerEntry."), 80);
|
||||
|
||||
// convert weight buffer to an integer
|
||||
signer_weight = UINT16_FROM_BUF(buf);
|
||||
|
||||
// some debug output to see the progress
|
||||
TRACEVAR(signer_weight);
|
||||
TRACEHEX(account_field);
|
||||
TRACEHEX(signer_account);
|
||||
|
||||
// compare the signer account for this signer entry against the originating transaction (sending) account
|
||||
int equal = 0;
|
||||
BUFFER_EQUAL_GUARD(equal, signer_account, 20, account_field, 20, 8);
|
||||
if (equal)
|
||||
{
|
||||
// if the otxn account was in the signer list we can stop iterating
|
||||
found = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the otxn account is authed
|
||||
if (!found)
|
||||
rollback(SBUF("Notary: Your account was not present in the signer list."), 70);
|
||||
|
||||
// execution to this point means the following:
|
||||
// 1. the originating transaction (sending) account is authorized as one of the signers on the hook account
|
||||
// 2. either an invoice ID or a memo was sent to the hook (but not both).
|
||||
|
||||
// if a memo was sent to the hook it must be mode 1 above (proposing a new multisign transaction)
|
||||
if (memos_len > 0)
|
||||
{
|
||||
// this is a defensive check, it is actually never executed due to an identical condition above
|
||||
if (invoice_id_len > 0)
|
||||
rollback(SBUF("Notary: Incoming transaction with both invoice id and memo. Aborting."), 0);
|
||||
|
||||
// since our memos are in a buffer inside the hook (as opposed to being a slot) we use the sto api with it
|
||||
// the sto apis probe into a serialized object returning offsets and lengths of subfields or array entries
|
||||
int64_t memo_lookup = sto_subarray(memos, memos_len, 0);
|
||||
uint8_t* memo_ptr = SUB_OFFSET(memo_lookup) + memos;
|
||||
uint32_t memo_len = SUB_LENGTH(memo_lookup);
|
||||
|
||||
// memos are nested inside an actual memo object, so we need to subfield
|
||||
// equivalently in JSON this would look like memo_array[i]["Memo"]
|
||||
memo_lookup = sto_subfield(memo_ptr, memo_len, sfMemo);
|
||||
memo_ptr = SUB_OFFSET(memo_lookup) + memo_ptr;
|
||||
memo_len = SUB_LENGTH(memo_lookup);
|
||||
|
||||
if (memo_lookup < 0)
|
||||
rollback(SBUF("Notary: Incoming txn had a blank sfMemos, abort."), 1);
|
||||
|
||||
int64_t format_lookup = sto_subfield(memo_ptr, memo_len, sfMemoFormat);
|
||||
uint8_t* format_ptr = SUB_OFFSET(format_lookup) + memo_ptr;
|
||||
uint32_t format_len = SUB_LENGTH(format_lookup);
|
||||
|
||||
int is_unsigned_payload = 0;
|
||||
BUFFER_EQUAL_STR_GUARD(is_unsigned_payload, format_ptr, format_len, "unsigned/payload+1", 1);
|
||||
if (!is_unsigned_payload)
|
||||
accept(SBUF("Notary: Memo is an invalid format. Passing txn."), 50);
|
||||
|
||||
int64_t data_lookup = sto_subfield(memo_ptr, memo_len, sfMemoData);
|
||||
uint8_t* data_ptr = SUB_OFFSET(data_lookup) + memo_ptr;
|
||||
uint32_t data_len = SUB_LENGTH(data_lookup);
|
||||
|
||||
if (data_len > MAX_MEMO_SIZE)
|
||||
rollback(SBUF("Notary: Memo too large (4kib max)."), 4);
|
||||
|
||||
// inspect unsigned payload
|
||||
// first check that sfTransactionType appears in the memo... if it doesn't then it can't be a transaction
|
||||
int64_t txtype_lookup = sto_subfield(data_ptr, data_len, sfTransactionType);
|
||||
if (txtype_lookup < 0)
|
||||
rollback(SBUF("Notary: Memo is invalid format. Should be an unsigned transaction."), 2);
|
||||
|
||||
// next check the lastLedgerSequence is sensibly set otherwise there will be no chance for the other signers
|
||||
// to endorse the txn before it expires
|
||||
int64_t lls_lookup = sto_subfield(data_ptr, data_len, sfLastLedgerSequence);
|
||||
uint8_t* lls_ptr = SUB_OFFSET(lls_lookup) + data_ptr;
|
||||
uint32_t lls_len = SUB_LENGTH(lls_lookup);
|
||||
|
||||
// check for expired txn
|
||||
if (lls_len != 4 || UINT32_FROM_BUF(lls_ptr) < ledger_seq() + MINIMUM_FUTURE_LEDGER)
|
||||
rollback(SBUF("Notary: Provided txn blob expires too soo (LastLedgerSeq)."), 3);
|
||||
|
||||
// compute txn hash, this becomes the ID passed as an invoice ID by the endorsers (other signers)
|
||||
if (util_sha512h(SBUF(invoice_id), data_ptr, data_len) < 0)
|
||||
rollback(SBUF("Notary: Could not compute sha512 over the submitted txn."), 5);
|
||||
|
||||
TRACEHEX(invoice_id);
|
||||
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + 0x0FU;
|
||||
|
||||
// write blob to state... the state key for the txn blob is the txn ID with `F` as the last nibble.
|
||||
if (state_set(data_ptr, data_len, SBUF(invoice_id)) != data_len)
|
||||
rollback(SBUF("Notary: Could not write txn to hook state."), 6);
|
||||
|
||||
}
|
||||
|
||||
// execution to here means if we were in mode 1 we now drop into mode 2, because the proposed txn is now recorded
|
||||
// so we simply treat this as an endorsement (mode 2) from here...
|
||||
|
||||
// record the signature... the state key for this is the txn ID with (1 + signer number) as the last nibble
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + found;
|
||||
|
||||
// the value we record against the signer is his/her signer weight at the time the endorsement or proposal happened
|
||||
UINT16_TO_BUF(buf, signer_weight);
|
||||
if (state_set(buf, 2, SBUF(invoice_id)) != 2)
|
||||
rollback(SBUF("Notary: Could not write signature to hook state."), 7);
|
||||
|
||||
|
||||
// check if we have managed to achieve a quorum by loading all current signatures and adding together the signer
|
||||
// weights (stored as the HookState values)
|
||||
uint32_t total = 0;
|
||||
for (uint8_t i = 1; GUARD(8), i < 9; ++i)
|
||||
{
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + i;
|
||||
if (state(buf, 2, SBUF(invoice_id)) == 2)
|
||||
total += UINT16_FROM_BUF(buf);
|
||||
}
|
||||
|
||||
TRACEVAR(total);
|
||||
TRACEVAR(signer_quorum);
|
||||
|
||||
// if we haven't achieved a quorum we will output the ID as the hook result string so it can be given to the
|
||||
// other endorsers
|
||||
if (total < signer_quorum)
|
||||
{
|
||||
uint8_t header[] = "Notary: Accepted waiting for other signers...: ";
|
||||
uint8_t returnval[112];
|
||||
uint8_t* ptr = returnval;
|
||||
for (int i = 0; GUARD(47), i < 47; ++i)
|
||||
*ptr++ = header[i];
|
||||
for (int i = 0; GUARD(32),i < 32; ++i)
|
||||
{
|
||||
uint8_t hi = (invoice_id[i] >> 4U);
|
||||
uint8_t lo = (invoice_id[i] & 0xFU);
|
||||
|
||||
hi += ( hi > 9 ? ('A'-10) : '0' );
|
||||
lo += ( lo > 9 ? ('A'-10) : '0' );
|
||||
*ptr++ = hi;
|
||||
*ptr++ = lo;
|
||||
}
|
||||
accept(SBUF(returnval), 0);
|
||||
}
|
||||
|
||||
// execution to here means we achieved a quorum on a proposed txn
|
||||
// therefore we must now emit the txn then garbage collect the old state
|
||||
int should_emit = 1;
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + 0x0FU;
|
||||
tx_len = state(SBUF(tx_blob), SBUF(invoice_id));
|
||||
if (tx_len < 0)
|
||||
should_emit = 0;
|
||||
|
||||
// delete everything from state before emitting
|
||||
state_set(0, 0, SBUF(invoice_id));
|
||||
for (uint8_t i = 1; GUARD(8), i < 9; ++i)
|
||||
{
|
||||
invoice_id[31] = ( invoice_id[31] & 0xF0U ) + i;
|
||||
state_set(0, 0, SBUF(invoice_id));
|
||||
}
|
||||
|
||||
if (!should_emit)
|
||||
rollback(SBUF("Notary: Tried to emit multisig txn but it was msising"), 1);
|
||||
|
||||
// blob exists, check expiry
|
||||
int64_t lls_lookup = sto_subfield(tx_blob, tx_len, sfLastLedgerSequence);
|
||||
uint8_t* lls_ptr = SUB_OFFSET(lls_lookup) + tx_blob;
|
||||
uint32_t lls_len = SUB_LENGTH(lls_lookup);
|
||||
if (lls_len != 4)
|
||||
rollback(SBUF("Notary: Was about to emit txn but it doesn't have LastLedgerSequence"), 1);
|
||||
|
||||
uint32_t lls_old = UINT32_FROM_BUF(lls_ptr);
|
||||
if (lls_old < ledger_seq())
|
||||
rollback(SBUF("Notary: Was about to emit txn but it's too old now"), 1);
|
||||
|
||||
// modify the txn for emission
|
||||
// we need to remove sfSigners if it exists
|
||||
// we need to zero sfSequence sfSigningPubKey and sfTxnSignature
|
||||
// we need to correctly set sfFirstLedgerSequence
|
||||
|
||||
// first do the erasure, this can fail if there is no such sfSigner field, so swap buffers to immitate success
|
||||
|
||||
uint8_t buffer[MAX_MEMO_SIZE];
|
||||
uint8_t* buffer2 = buffer;
|
||||
uint8_t* buffer1 = tx_blob;
|
||||
|
||||
result = sto_erase(buffer2, MAX_MEMO_SIZE, buffer1, tx_len, sfSigners);
|
||||
if (result > 0)
|
||||
tx_len = result;
|
||||
else
|
||||
BUFFER_SWAP(buffer1, buffer2);
|
||||
|
||||
// next zero sfSequence
|
||||
uint8_t zeroed[6];
|
||||
CLEARBUF(zeroed);
|
||||
zeroed[0] = 0x24U; // this is the lead byte for sfSequence
|
||||
|
||||
tx_len = sto_emplace(buffer1, MAX_MEMO_SIZE, buffer2, tx_len, zeroed, 5, sfSequence);
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfSequence failed."), 1);
|
||||
|
||||
|
||||
// next set sfTxnSignature to 0
|
||||
zeroed[0] = 0x74U; // lead byte for sfTxnSignature, next byte is length which is 0
|
||||
tx_len = sto_emplace(buffer2, MAX_MEMO_SIZE, buffer1, tx_len, zeroed, 2, sfTxnSignature);
|
||||
TRACEVAR(tx_len);
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfTxnSignature failed."), 1);
|
||||
|
||||
// next set sfSigningPubKey to 0
|
||||
zeroed[0] = 0x73U; // this is the lead byte for sfSigningPubkey, note that the next byte is 0 which is the length
|
||||
tx_len = sto_emplace(buffer1, MAX_MEMO_SIZE, buffer2, tx_len, zeroed, 2, sfSigningPubKey);
|
||||
TRACEVAR(tx_len);
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfSigningPubKey failed."), 1);
|
||||
|
||||
// finally set FirstLedgerSeq appropriately
|
||||
uint32_t fls = ledger_seq() + 1;
|
||||
zeroed[0] = 0x20U;
|
||||
zeroed[1] = 0x1AU;
|
||||
UINT32_TO_BUF(zeroed + 2, fls);
|
||||
tx_len = sto_emplace(buffer2, MAX_MEMO_SIZE, buffer1, tx_len, zeroed, 6, sfFirstLedgerSequence);
|
||||
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfFirstLedgerSequence failed."), 1);
|
||||
|
||||
uint32_t lls_new = fls + 4;
|
||||
if (lls_old > lls_new) {
|
||||
trace("fixing", 6, buffer2, tx_len, 1);
|
||||
|
||||
tx_len = sto_erase(buffer1, MAX_MEMO_SIZE, buffer2, tx_len, sfLastLedgerSequence);
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Erasing sfLastLedgerSequence failed."), 1);
|
||||
|
||||
trace("before", 6, buffer1, tx_len, 1);
|
||||
|
||||
zeroed[1] = 0x1BU;
|
||||
UINT32_TO_BUF(zeroed + 2, lls_new);
|
||||
tx_len = sto_emplace(buffer2, MAX_MEMO_SIZE, buffer1, tx_len, zeroed, 6, sfLastLedgerSequence);
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfLastLedgerSequence failed."), 1);
|
||||
|
||||
trace("after", 5, buffer2, tx_len, 1);
|
||||
}
|
||||
|
||||
// finally add emit details
|
||||
uint8_t emitdet[138];
|
||||
result = etxn_details(SBUF(emitdet));
|
||||
|
||||
if (result < 0)
|
||||
rollback(SBUF("Notary: EmitDetails failed to generate."), 1);
|
||||
|
||||
tx_len = sto_emplace(buffer1, MAX_MEMO_SIZE, buffer2, tx_len, emitdet, result, sfEmitDetails);
|
||||
if (tx_len < 0)
|
||||
rollback(SBUF("Notary: Emplacing sfEmitDetails failed."), 1);
|
||||
|
||||
// replace fee with something currently appropriate
|
||||
uint8_t fee[ENCODE_DROPS_SIZE];
|
||||
uint8_t* fee_ptr = fee; // this ptr is incremented by the macro, so just throw it away
|
||||
int64_t fee_to_pay = etxn_fee_base(buffer1, tx_len);
|
||||
ENCODE_DROPS(fee_ptr, fee_to_pay, amFEE);
|
||||
tx_len = sto_emplace(buffer2, MAX_MEMO_SIZE, buffer1, tx_len, SBUF(fee), sfFee);
|
||||
|
||||
if (tx_len <= 0)
|
||||
rollback(SBUF("Notary: Emplacing sfFee failed."), 1);
|
||||
|
||||
uint8_t emithash[32];
|
||||
if (emit(SBUF(emithash), buffer2, tx_len) < 0)
|
||||
accept(SBUF("Notary: All conditions met but emission failed: proposed txn was malformed."), 1);
|
||||
|
||||
accept(SBUF("Notary: Emitted multisigned txn"), 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
const wasm = 'notary.wasm'
|
||||
if (process.argv.length < 5)
|
||||
{
|
||||
console.log("Usage: node notary <source family seed> <quorum> <signer 1> < ... signer n> ")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const quorum = parseInt(process.argv[3]);
|
||||
|
||||
let signers = [];
|
||||
for (let i = 4; i < process.argv.length; ++i)
|
||||
{
|
||||
signers.push({
|
||||
SignerEntry: {
|
||||
Account: process.argv[i],
|
||||
SignerWeight: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
|
||||
const account = t.xrpljs.Wallet.fromSeed(process.argv[2]);
|
||||
t.fundFromGenesis([account.classicAddress]).then(x=>
|
||||
{
|
||||
t.feeSubmit(process.argv[2],
|
||||
{
|
||||
Account: account.classicAddress,
|
||||
Flags: 0,
|
||||
TransactionType: "SignerListSet",
|
||||
SignerQuorum: quorum,
|
||||
SignerEntries: signers
|
||||
}).then(x=>
|
||||
{
|
||||
console.log(x);
|
||||
t.assertTxnSuccess(x);
|
||||
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(t.err);
|
||||
}).catch(e=>console.log(e));
|
||||
@@ -1,56 +0,0 @@
|
||||
if (process.argv.length < 6)
|
||||
{
|
||||
console.log("Usage: node propose-txn \n" +
|
||||
"<first signer family seed> <multisig hook account> <xrp amount> " +
|
||||
"<destination account> [destination tag]")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const hook_account = process.argv[3];
|
||||
const amount = BigInt(process.argv[4]) * 1000000n
|
||||
const dest_acc = process.argv[5];
|
||||
const dest_tag = (process.argv.length < 7 ? parseInt(process.argv[6]) : null);
|
||||
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
const account = t.xrpljs.Wallet.fromSeed(process.argv[2]);
|
||||
let proposed_txn =
|
||||
{
|
||||
TransactionType: "Payment",
|
||||
Account: hook_account,
|
||||
Destination: dest_acc,
|
||||
Amount: '' + amount,
|
||||
LastLedgerSequence: "4000000000",
|
||||
Fee: "10000"
|
||||
}
|
||||
|
||||
if (dest_tag !== null)
|
||||
proposed_txn["DestinationTag"] = dest_tag;
|
||||
|
||||
proposed_txn = t.rbc.encode(proposed_txn);
|
||||
|
||||
let host_txn =
|
||||
{
|
||||
Account: account.classicAddress,
|
||||
TransactionType: "Payment",
|
||||
Amount: "1",
|
||||
Destination: hook_account,
|
||||
Fee: "10000",
|
||||
Memos: [
|
||||
{
|
||||
Memo:{
|
||||
MemoData: proposed_txn,
|
||||
MemoFormat: "unsigned/payload+1",
|
||||
MemoType: "notary/proposed"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
t.hex_memos(host_txn);
|
||||
t.feeSubmit(process.argv[2], host_txn).then(x=>
|
||||
{
|
||||
console.log(x);
|
||||
t.assertTxnSuccess(x);
|
||||
process.exit(0);
|
||||
}).catch(t.err);
|
||||
}).catch(e=>console.log(e));
|
||||
@@ -1,30 +0,0 @@
|
||||
if (process.argv.length < 5)
|
||||
{
|
||||
console.log("Usage: node sign <signer family seed> <notary hook account> <proposal id>")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const secret = process.argv[2];
|
||||
const hook_account = process.argv[3];
|
||||
const proposal = process.argv[4];
|
||||
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
const account = t.xrpljs.Wallet.fromSeed(process.argv[2]);
|
||||
t.fundFromGenesis([account.classicAddress]).then(()=>
|
||||
{
|
||||
t.feeSubmit(process.argv[2],
|
||||
{
|
||||
Account: account.classicAddress,
|
||||
TransactionType: "Payment",
|
||||
Amount: "1",
|
||||
Destination: hook_account,
|
||||
InvoiceID: proposal
|
||||
}).then(x=>
|
||||
{
|
||||
console.log(x);
|
||||
t.assertTxnSuccess(x);
|
||||
process.exit(0);
|
||||
}).catch(t.err);
|
||||
}).catch(t.err);
|
||||
}).catch(e=>console.log(e));
|
||||
@@ -1,31 +0,0 @@
|
||||
if (process.argv.length < 4)
|
||||
{
|
||||
console.log("Usage: node addtrustline <family seed> <peggy hook account> ")
|
||||
process.exit(1)
|
||||
}
|
||||
const keypairs = require('ripple-keypairs');
|
||||
const secret = process.argv[2];
|
||||
const address = keypairs.deriveAddress(keypairs.deriveKeypair(secret).publicKey)
|
||||
const hook_account = process.argv[3];
|
||||
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
t.feeSubmit(secret,
|
||||
{
|
||||
Account: address,
|
||||
TransactionType: "TrustSet",
|
||||
Flags: 262144,
|
||||
LimitAmount: {
|
||||
currency: "USD",
|
||||
issuer: hook_account,
|
||||
value: "1000000000000000"
|
||||
},
|
||||
}).then(x=>
|
||||
{
|
||||
console.log(x);
|
||||
t.assertTxnSuccess(x);
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
all:
|
||||
wasmcc peggy.c -o /tmp/peggy.wasm -O0 -Wl,--allow-undefined -I../
|
||||
wasm-opt -O2 /tmp/peggy.wasm -o peggy.wasm
|
||||
hook-cleaner peggy.wasm
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
if (process.argv.length < 5)
|
||||
{
|
||||
console.log("Usage: node payusd <family seed> <amount> <peggy hook account> [destination] [dest tag]")
|
||||
process.exit(1)
|
||||
}
|
||||
const keypairs = require('ripple-keypairs');
|
||||
const secret = process.argv[2];
|
||||
const address = keypairs.deriveAddress(keypairs.deriveKeypair(secret).publicKey)
|
||||
const amount = process.argv[3]
|
||||
const hook_account = process.argv[4];
|
||||
|
||||
const dest_acc = (process.argv.length >= 6 ? process.argv[5] : hook_account);
|
||||
const dest_tag = (process.argv.length == 7 ? process.argv[6] : null);
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
t.feeSubmit(secret,
|
||||
{
|
||||
Account: address,
|
||||
TransactionType: "Payment",
|
||||
Amount: {
|
||||
currency: "USD",
|
||||
value: amount + '',
|
||||
issuer: hook_account
|
||||
},
|
||||
Destination: dest_acc
|
||||
}).then(x=>
|
||||
{
|
||||
console.log(x);
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
/**
|
||||
* Peggy.c - An oracle based stable coin hook
|
||||
*
|
||||
* Author: Richard Holland
|
||||
* Date: 1 Mar 2021
|
||||
*
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../hookapi.h"
|
||||
|
||||
// your vault starts at 150% collateralization
|
||||
#define NEW_COLLATERALIZATION_NUMERATOR 2
|
||||
#define NEW_COLLATERALIZATION_DENOMINATOR 3
|
||||
|
||||
// at 120% collateralization your vault may be taken over
|
||||
#define LIQ_COLLATERALIZATION_NUMERATOR 5
|
||||
#define LIQ_COLLATERALIZATION_DENOMINATOR 6
|
||||
|
||||
|
||||
// the oracle is the limit set on a trustline established between two special oracle accounts
|
||||
|
||||
uint8_t oracle_lo[20] = { // require('ripple-address-codec').decodeAccountID('rXUMMaPpZqPutoRszR29jtC8amWq3APkx')
|
||||
0x05U, 0xb5U, 0xf4U, 0x3aU, 0xf7U,
|
||||
0x17U, 0xb8U, 0x19U, 0x48U, 0x49U, 0x1fU, 0xb7U, 0x07U, 0x9eU, 0x4fU, 0x17U, 0x3fU, 0x4eU, 0xceU, 0xb3U};
|
||||
|
||||
uint8_t oracle_hi[20] = { // require('ripple-address-codec').decodeAccountID('r9PfV3sQpKLWxccdg3HL2FXKxGW2orAcLE')
|
||||
0x5bU, 0xefU, 0x92U, 0x1aU, 0x21U,
|
||||
0x7dU, 0x57U, 0xfdU, 0xa5U, 0xb5U, 0x6dU, 0x5bU, 0x40U, 0xbeU, 0xe4U, 0x0dU, 0x1aU, 0xc1U, 0x12U, 0x7fU};
|
||||
|
||||
int64_t hook(uint32_t reserved)
|
||||
{
|
||||
|
||||
etxn_reserve(1);
|
||||
|
||||
uint8_t currency[20] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 'U', 'S', 'D', 0,0,0,0,0};
|
||||
|
||||
// get the account the hook is running on and the account that created the txn
|
||||
uint8_t hook_accid[20];
|
||||
hook_account(SBUF(hook_accid));
|
||||
|
||||
uint8_t otxn_accid[20];
|
||||
int32_t otxn_accid_len = otxn_field(SBUF(otxn_accid), sfAccount);
|
||||
if (otxn_accid_len < 20)
|
||||
rollback(SBUF("Peggy: sfAccount field missing!!!"), 10);
|
||||
|
||||
// get the source tag if any... negative means it wasn't provided
|
||||
int64_t source_tag = otxn_field(0,0, sfSourceTag);
|
||||
if (source_tag < 0)
|
||||
source_tag = 0xFFFFFFFFU;
|
||||
|
||||
// compare the "From Account" (sfAccount) on the transaction with the account the hook is running on
|
||||
int equal = 0; BUFFER_EQUAL(equal, hook_accid, otxn_accid, 20);
|
||||
if (equal)
|
||||
accept(SBUF("Peggy: Outgoing transaction"), 20);
|
||||
|
||||
// invoice id if present is used for taking over undercollateralized vaults
|
||||
// format: { 20 byte account id | 4 byte tag [FFFFFFFFU if absent] | 8 bytes of 0 }
|
||||
uint8_t invoice_id[32];
|
||||
int64_t invoice_id_len = otxn_field(SBUF(invoice_id), sfInvoiceID);
|
||||
|
||||
// check if a trustline exists between the sender and the hook for the USD currency [ PUSD ]
|
||||
uint8_t keylet[34];
|
||||
if (util_keylet(SBUF(keylet), KEYLET_LINE, SBUF(hook_accid), SBUF(otxn_accid), SBUF(currency)) != 34)
|
||||
rollback(SBUF("Peggy: Internal error, could not generate keylet"), 10);
|
||||
|
||||
int64_t user_peggy_trustline_slot = slot_set(SBUF(keylet), 0);
|
||||
TRACEVAR(user_peggy_trustline_slot);
|
||||
if (user_peggy_trustline_slot < 0)
|
||||
rollback(SBUF("Peggy: You must have a trustline set for USD to this account."), 10);
|
||||
|
||||
|
||||
// because the trustline is actually a ripplestate object with a 'high' and a 'low' account
|
||||
// we need to compare the hook account with the user's account to determine which side of the line to
|
||||
// examine for an adequate limit
|
||||
int compare_result = 0;
|
||||
ACCOUNT_COMPARE(compare_result, hook_accid, otxn_accid);
|
||||
if (compare_result == 0)
|
||||
rollback(SBUF("Peggy: Invalid trustline set hi=lo?"), 1);
|
||||
|
||||
int64_t lim_slot = slot_subfield(user_peggy_trustline_slot, (compare_result > 1 ? sfLowLimit : sfHighLimit), 0);
|
||||
if (lim_slot < 0)
|
||||
rollback(SBUF("Peggy: Could not find sfLowLimit on oracle trustline"), 20);
|
||||
|
||||
int64_t user_trustline_limit = slot_float(lim_slot);
|
||||
if (user_trustline_limit < 0)
|
||||
rollback(SBUF("Peggy: Could not parse user trustline limit"), 1);
|
||||
|
||||
int64_t required_limit = float_set(10, 1);
|
||||
if (float_compare(user_trustline_limit, required_limit, COMPARE_EQUAL | COMPARE_GREATER) != 1)
|
||||
rollback(SBUF("Peggy: You must set a trustline for USD to peggy for limit of at least 10B"), 1);
|
||||
|
||||
// execution to here means the invoking account has the required trustline with the required limit
|
||||
// now fetch the price oracle data (which also lives in a trustline)
|
||||
|
||||
|
||||
CLEARBUF(keylet);
|
||||
if (util_keylet(SBUF(keylet), KEYLET_LINE, SBUF(oracle_lo), SBUF(oracle_hi), SBUF(currency)) != 34)
|
||||
rollback(SBUF("Peggy: Internal error, could not generate keylet"), 10);
|
||||
|
||||
TRACEHEX(keylet);
|
||||
int64_t slot_no = slot_set(SBUF(keylet), 0);
|
||||
TRACEVAR(slot_no);
|
||||
if (slot_no < 0)
|
||||
rollback(SBUF("Peggy: Could not find oracle trustline"), 10);
|
||||
|
||||
lim_slot = slot_subfield(slot_no, sfLowLimit, 0);
|
||||
if (lim_slot < 0)
|
||||
rollback(SBUF("Peggy: Could not find sfLowLimit on oracle trustline"), 20);
|
||||
|
||||
int64_t exchange_rate = slot_float(lim_slot);
|
||||
if (exchange_rate < 0)
|
||||
rollback(SBUF("Peggy: Could not get exchange rate float"), 20);
|
||||
|
||||
// execution to here means we have retrieved the exchange rate from the oracle
|
||||
TRACEXFL(exchange_rate);
|
||||
|
||||
// process the amount sent, which could be either xrp or pusd
|
||||
// to do this we 'slot' the originating txn, that is: we place it into a slot so we can use the slot api
|
||||
// to examine its internals
|
||||
int64_t oslot = otxn_slot(0);
|
||||
if (oslot < 0)
|
||||
rollback(SBUF("Peggy: Could not slot originating txn."), 1);
|
||||
|
||||
// specifically we're interested in the amount sent
|
||||
int64_t amt_slot = slot_subfield(oslot, sfAmount, 0);
|
||||
if (amt_slot < 0)
|
||||
rollback(SBUF("Peggy: Could not slot otxn.sfAmount"), 2);
|
||||
|
||||
int64_t amt = slot_float(amt_slot);
|
||||
if (amt < 0)
|
||||
rollback(SBUF("Peggy: Could not parse amount."), 1);
|
||||
|
||||
// the slot_type api allows determination of fields and subtypes of fields according to the doco
|
||||
// in this case we're examining an amount field to see if it's a native (xrp) amount or an iou amount
|
||||
// this means passing flag=1
|
||||
int64_t is_xrp = slot_type(amt_slot, 1);
|
||||
if (is_xrp < 0)
|
||||
rollback(SBUF("Peggy: Could not determine sent amount type"), 3);
|
||||
|
||||
|
||||
// In addition to determining the amount sent (and its type) we also need to handle the "recollateralization"
|
||||
// takeover mode. This is where another user, not the original vault owner, passes the vault ID as invoice ID
|
||||
// and sends a payment that brings the vault back into a valid state. We then assign ownership to this person
|
||||
// as a reward for stablising the vault. So account for this and record whether or not we are proceeding as
|
||||
// the original vault owner (or a new vault) or in takeover mode.
|
||||
uint8_t is_vault_owner = 1;
|
||||
uint8_t vault_key[24];
|
||||
if (invoice_id_len != 32)
|
||||
{
|
||||
// this is normal mode
|
||||
for (int i = 0; GUARD(20), i < 20; ++i)
|
||||
vault_key[i] = otxn_accid[i];
|
||||
|
||||
vault_key[20] = (uint8_t)((source_tag >> 24U) & 0xFFU);
|
||||
vault_key[21] = (uint8_t)((source_tag >> 16U) & 0xFFU);
|
||||
vault_key[22] = (uint8_t)((source_tag >> 8U) & 0xFFU);
|
||||
vault_key[23] = (uint8_t)((source_tag >> 0U) & 0xFFU);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is the takeover mode
|
||||
for (int i = 0; GUARD(24), i < 24; ++i)
|
||||
vault_key[i] = invoice_id[i];
|
||||
is_vault_owner = 0;
|
||||
}
|
||||
|
||||
// check if state currently exists
|
||||
uint8_t vault[16];
|
||||
int64_t vault_pusd = 0;
|
||||
int64_t vault_xrp = 0;
|
||||
uint8_t vault_exists = 0;
|
||||
if (state(SBUF(vault), SBUF(vault_key)) == 16)
|
||||
{
|
||||
vault_pusd = float_sto_set(vault, 8);
|
||||
vault_xrp = float_sto_set(vault + 8, 8);
|
||||
vault_exists = 1;
|
||||
}
|
||||
else if (is_vault_owner == 0)
|
||||
rollback(SBUF("Peggy: You cannot takeover a vault that does not exist!"), 1);
|
||||
|
||||
if (is_xrp)
|
||||
{
|
||||
// XRP INCOMING
|
||||
|
||||
// decide whether the vault is liquidatable
|
||||
int64_t required_vault_xrp = float_divide(vault_pusd, exchange_rate);
|
||||
required_vault_xrp =
|
||||
float_mulratio(required_vault_xrp, 0, LIQ_COLLATERALIZATION_DENOMINATOR, LIQ_COLLATERALIZATION_NUMERATOR);
|
||||
uint8_t can_liq = (required_vault_xrp < vault_xrp);
|
||||
|
||||
// compute new vault xrp by adding the xrp they just sent
|
||||
vault_xrp = float_sum(amt, vault_xrp);
|
||||
|
||||
// compute the maximum amount of pusd that can be out according to the collateralization
|
||||
int64_t max_vault_pusd = float_multiply(vault_xrp, exchange_rate);
|
||||
max_vault_pusd =
|
||||
float_mulratio(max_vault_pusd, 0, NEW_COLLATERALIZATION_NUMERATOR, NEW_COLLATERALIZATION_DENOMINATOR);
|
||||
|
||||
// compute the amount we can send them
|
||||
int64_t pusd_to_send =
|
||||
float_sum(max_vault_pusd, float_negate(vault_pusd));
|
||||
if (pusd_to_send < 0)
|
||||
rollback(SBUF("Peggy: Error computing pusd to send"), 1);
|
||||
|
||||
// is the amount to send negative, that means the vault is undercollateralized
|
||||
if (float_compare(pusd_to_send, 0, COMPARE_LESS))
|
||||
{
|
||||
if (!is_vault_owner)
|
||||
rollback(SBUF("Peggy: Vault is undercollateralized and your deposit would not redeem it."), 1);
|
||||
else
|
||||
{
|
||||
if (float_sto(vault + 8, 8, 0,0,0,0, vault_xrp, -1) != 8)
|
||||
rollback(SBUF("Peggy: Internal error writing vault"), 1);
|
||||
if (state_set(SBUF(vault), SBUF(vault_key)) != 16)
|
||||
rollback(SBUF("Peggy: Could not set state"), 1);
|
||||
accept(SBUF("Peggy: Vault is undercollateralized, absorbing without sending anything."), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_vault_owner && !can_liq)
|
||||
rollback(SBUF("Peggy: Vault is not sufficiently undercollateralized to take over yet."), 2);
|
||||
|
||||
// execution to here means we will send out pusd
|
||||
|
||||
// update the vault
|
||||
vault_pusd = float_sum(vault_pusd, pusd_to_send);
|
||||
|
||||
// if this is a takeover we destroy the vault on the old key and recreate it on the new key
|
||||
if (!is_vault_owner)
|
||||
{
|
||||
// destroy
|
||||
if (state_set(0,0,SBUF(vault_key)) < 0)
|
||||
rollback(SBUF("Peggy: Could not destroy old vault."), 1);
|
||||
|
||||
// reset the key
|
||||
CLEARBUF(vault_key);
|
||||
for (int i = 0; GUARD(20), i < 20; ++i)
|
||||
vault_key[i] = otxn_accid[i];
|
||||
|
||||
vault_key[20] = (uint8_t)((source_tag >> 24U) & 0xFFU);
|
||||
vault_key[21] = (uint8_t)((source_tag >> 16U) & 0xFFU);
|
||||
vault_key[22] = (uint8_t)((source_tag >> 8U) & 0xFFU);
|
||||
vault_key[23] = (uint8_t)((source_tag >> 0U) & 0xFFU);
|
||||
}
|
||||
|
||||
// set / update the vault
|
||||
if (float_sto(vault, 8, 0,0,0,0, vault_pusd, -1) != 8 ||
|
||||
float_sto(vault + 8, 8, 0,0,0,0, vault_xrp, -1) != 8)
|
||||
rollback(SBUF("Peggy: Internal error writing vault"), 1);
|
||||
|
||||
if (state_set(SBUF(vault), SBUF(vault_key)) != 16)
|
||||
rollback(SBUF("Peggy: Could not set state"), 1);
|
||||
|
||||
// we need to dump the iou amount into a buffer
|
||||
// by supplying -1 as the fieldcode we tell float_sto not to prefix an actual STO header on the field
|
||||
uint8_t amt_out[48];
|
||||
if (float_sto(SBUF(amt_out), SBUF(currency), SBUF(hook_accid), pusd_to_send, -1) < 0)
|
||||
rollback(SBUF("Peggy: Could not dump pusd amount into sto"), 1);
|
||||
|
||||
// set the currency code and issuer in the amount field
|
||||
for (int i = 0; GUARD(20),i < 20; ++i)
|
||||
{
|
||||
amt_out[i + 28] = hook_accid[i];
|
||||
amt_out[i + 8] = currency[i];
|
||||
}
|
||||
|
||||
// finally create the outgoing txn
|
||||
uint8_t txn_out[PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE];
|
||||
PREPARE_PAYMENT_SIMPLE_TRUSTLINE(txn_out, amt_out, otxn_accid, source_tag, source_tag);
|
||||
|
||||
uint8_t emithash[32];
|
||||
if (emit(SBUF(emithash), SBUF(txn_out)) < 0)
|
||||
rollback(SBUF("Peggy: Emitting txn failed"), 1);
|
||||
|
||||
accept(SBUF("Peggy: Sent you PUSD!"), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// NON-XRP incoming
|
||||
if (!vault_exists)
|
||||
rollback(SBUF("Peggy: Can only send PUSD back to an existing vault."), 1);
|
||||
|
||||
uint8_t amount_buffer[48];
|
||||
if (slot(SBUF(amount_buffer), amt_slot) != 48)
|
||||
rollback(SBUF("Peggy: Could not dump sfAmount"), 1);
|
||||
|
||||
// ensure the issuer is us
|
||||
for (int i = 28; GUARD(20), i < 48; ++i)
|
||||
{
|
||||
if (amount_buffer[i] != hook_accid[i - 28])
|
||||
rollback(SBUF("Peggy: A currency we didn't issue was sent to us."), 1);
|
||||
}
|
||||
|
||||
// ensure the currency is PUSD
|
||||
for (int i = 8; GUARD(20), i < 28; ++i)
|
||||
{
|
||||
if (amount_buffer[i] != currency[i - 8])
|
||||
rollback(SBUF("Peggy: A non USD currency was sent to us."), 1);
|
||||
}
|
||||
|
||||
TRACEVAR(vault_pusd);
|
||||
|
||||
// decide whether the vault is liquidatable
|
||||
int64_t required_vault_xrp = float_divide(vault_pusd, exchange_rate);
|
||||
required_vault_xrp =
|
||||
float_mulratio(required_vault_xrp, 0, LIQ_COLLATERALIZATION_DENOMINATOR, LIQ_COLLATERALIZATION_NUMERATOR);
|
||||
uint8_t can_liq = (required_vault_xrp < vault_xrp);
|
||||
|
||||
|
||||
// compute new vault pusd by adding the pusd they just sent
|
||||
vault_pusd = float_sum(float_negate(amt), vault_pusd);
|
||||
|
||||
// compute the maximum amount of pusd that can be out according to the collateralization
|
||||
int64_t max_vault_xrp = float_divide(vault_pusd, exchange_rate);
|
||||
max_vault_xrp =
|
||||
float_mulratio(max_vault_xrp, 0, NEW_COLLATERALIZATION_DENOMINATOR, NEW_COLLATERALIZATION_NUMERATOR);
|
||||
|
||||
|
||||
// compute the amount we can send them
|
||||
int64_t xrp_to_send =
|
||||
float_sum(float_negate(max_vault_xrp), vault_xrp);
|
||||
|
||||
if (xrp_to_send < 0)
|
||||
rollback(SBUF("Peggy: Error computing xrp to send"), 1);
|
||||
|
||||
// is the amount to send negative, that means the vault is undercollateralized
|
||||
if (float_compare(xrp_to_send, 0, COMPARE_LESS))
|
||||
{
|
||||
if (!is_vault_owner)
|
||||
rollback(SBUF("Peggy: Vault is undercollateralized and your deposit would not redeem it."), 1);
|
||||
else
|
||||
{
|
||||
if (float_sto(vault, 8, 0,0,0,0, vault_pusd, -1) != 8)
|
||||
rollback(SBUF("Peggy: Internal error writing vault"), 1);
|
||||
|
||||
if (state_set(SBUF(vault), SBUF(vault_key)) != 16)
|
||||
rollback(SBUF("Peggy: Could not set state"), 1);
|
||||
|
||||
accept(SBUF("Peggy: Vault is undercollateralized, absorbing without sending anything."), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_vault_owner && !can_liq)
|
||||
rollback(SBUF("Peggy: Vault is not sufficiently undercollateralized to take over yet."), 2);
|
||||
|
||||
// execution to here means we will send out pusd
|
||||
|
||||
// update the vault
|
||||
vault_xrp = float_sum(vault_xrp, xrp_to_send);
|
||||
|
||||
// if this is a takeover we destroy the vault on the old key and recreate it on the new key
|
||||
if (!is_vault_owner)
|
||||
{
|
||||
// destroy
|
||||
if (state_set(0,0,SBUF(vault_key)) < 0)
|
||||
rollback(SBUF("Peggy: Could not destroy old vault."), 1);
|
||||
|
||||
// reset the key
|
||||
CLEARBUF(vault_key);
|
||||
for (int i = 0; GUARD(20), i < 20; ++i)
|
||||
vault_key[i] = otxn_accid[i];
|
||||
|
||||
vault_key[20] = (uint8_t)((source_tag >> 24U) & 0xFFU);
|
||||
vault_key[21] = (uint8_t)((source_tag >> 16U) & 0xFFU);
|
||||
vault_key[22] = (uint8_t)((source_tag >> 8U) & 0xFFU);
|
||||
vault_key[23] = (uint8_t)((source_tag >> 0U) & 0xFFU);
|
||||
}
|
||||
|
||||
// set / update the vault
|
||||
if (float_sto(vault, 8, 0,0,0,0, vault_pusd, -1) != 8 ||
|
||||
float_sto(vault + 8, 8, 0,0,0,0, max_vault_xrp, -1) != 8)
|
||||
rollback(SBUF("Peggy: Internal error writing vault"), 1);
|
||||
|
||||
if (state_set(SBUF(vault), SBUF(vault_key)) != 16)
|
||||
rollback(SBUF("Peggy: Could not set state"), 1);
|
||||
|
||||
// RH TODO: check the balance of the hook account
|
||||
|
||||
|
||||
// finally create the outgoing txn
|
||||
uint8_t txn_out[PREPARE_PAYMENT_SIMPLE_SIZE];
|
||||
PREPARE_PAYMENT_SIMPLE(txn_out, float_int(xrp_to_send, 6, 0), otxn_accid, source_tag, source_tag);
|
||||
|
||||
uint8_t emithash[32];
|
||||
if (emit(SBUF(emithash), SBUF(txn_out)) < 0)
|
||||
rollback(SBUF("Peggy: Emitting txn failed"), 1);
|
||||
|
||||
accept(SBUF("Peggy: Sent you XRP!"), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
const wasm = 'peggy.wasm'
|
||||
if (process.argv.length < 3)
|
||||
{
|
||||
console.log("Usage: node peggy <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));
|
||||
@@ -1,203 +0,0 @@
|
||||
// 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)
|
||||
@@ -1,2 +0,0 @@
|
||||
# HookAPI Tests
|
||||
This test-set pertains to the behaviour of Hook APIs, which are tested by installing and running hooks that invoke those APIs.
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
(cd wasm; touch *.c ; make)
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/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'
|
||||
@@ -1,40 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include "../../../examples/hookapi.h"
|
||||
#define ASSERT(x)\
|
||||
{\
|
||||
if (!(x))\
|
||||
rollback(SBUF(#x), __LINE__);\
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
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
|
||||
@@ -1,21 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
(cd wasm; make)
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/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'
|
||||
@@ -1,42 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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('concat.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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
require('../../utils-tests.js').TestRig('ws://localhost:6005').then(t=>
|
||||
{
|
||||
const account = t.randomAccount();
|
||||
const account2 = t.randomAccount();
|
||||
t.fundFromGenesis([account]).then(()=>
|
||||
{
|
||||
t.feeSubmit(account.seed,
|
||||
{
|
||||
Account: account.classicAddress,
|
||||
TransactionType: "SetHook",
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
CreateCode: t.wasm('multiescrow.wasm'),
|
||||
HookApiVersion: 0,
|
||||
HookNamespace: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
|
||||
HookOn: "0000000000000000"
|
||||
}
|
||||
}
|
||||
]
|
||||
}).then(x=>
|
||||
{
|
||||
t.assertTxnSuccess(x)
|
||||
console.log(x);
|
||||
t.feeSubmit(account.seed,
|
||||
{
|
||||
Account: account.classicAddress,
|
||||
TransactionType: "Payment",
|
||||
Destination: "rfCarbonVNTuXckX6x2qTMFmFSnm6dEWGX",
|
||||
Amount: "10000000000"
|
||||
}).then(x=>
|
||||
{
|
||||
t.assertTxnSuccess(x)
|
||||
t.ledgerAccept(10).then(()=>{
|
||||
t.fundFromGenesis([account2]).then(()=>
|
||||
{
|
||||
process.exit(0);
|
||||
}).catch(t.err);
|
||||
}).catch(t.err);
|
||||
}).catch(t.err);
|
||||
}).catch(t.err);
|
||||
}).catch(t.err);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
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);
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* 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);
|
||||
extern int64_t str_concat(
|
||||
uint32_t write_ptr, uint32_t write_len,
|
||||
uint32_t read_ptr, uint32_t read_len,
|
||||
uint64_t operand, uint32_t operand_type);
|
||||
|
||||
extern int64_t str_find(
|
||||
uint32_t hread_ptr, uint32_t hread_len,
|
||||
uint32_t nread_ptr, uint32_t nread_len,
|
||||
uint32_t mode, uint32_t n);
|
||||
|
||||
#define SBUF(x) x, sizeof(x)
|
||||
|
||||
int64_t cbak(uint32_t what)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t hook(uint32_t reserved )
|
||||
{
|
||||
|
||||
char x[1024];
|
||||
|
||||
int64_t bytes = str_concat(SBUF(x), SBUF("testing "), 5, 1);
|
||||
accept (x, str_find(SBUF(x), 0,0,0,0), 1);
|
||||
_g(1,1); // every hook needs to import guard function and use it at least once
|
||||
// unreachable
|
||||
return 0;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
all: accept.wasm makestate.wasm makestate2.wasm checkstate.wasm rollback.wasm aaw.wasm rmstate.wasm ginv.wasm multiguard.wasm multiescrow.wasm metacbak.wasm concat.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
|
||||
multiescrow.wasm: multiescrow.c
|
||||
wasmcc multiescrow.c -o multiescrow.wasm -O2 -Wl,--allow-undefined -I../
|
||||
hook-cleaner multiescrow.wasm
|
||||
metacbak.wasm: metacbak.c
|
||||
wasmcc metacbak.c -o metacbak.wasm -O2 -Wl,--allow-undefined -I../
|
||||
hook-cleaner metacbak.wasm
|
||||
concat.wasm: concat.c
|
||||
wasmcc concat.c -o concat.wasm -O2 -Wl,--allow-undefined -I../
|
||||
hook-cleaner concat.wasm
|
||||
@@ -1,31 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// escrows are made to destination: rfCarbonVNTuXckX6x2qTMFmFSnm6dEWGX
|
||||
|
||||
#include "../../../examples/hookapi.h"
|
||||
|
||||
#define ttESCROW_CREATE 1U
|
||||
|
||||
/*
|
||||
{
|
||||
8114 <accid> "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
120001 "TransactionType": "EscrowCreate",
|
||||
61 amt "Amount": "10000",
|
||||
|
||||
"Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
2024 "CancelAfter": 533257958,
|
||||
2025 "FinishAfter": 533171558,
|
||||
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
||||
"DestinationTag": 23480,
|
||||
"SourceTag": 11747
|
||||
}
|
||||
*/
|
||||
|
||||
#define ENCODE_CANAFTER_SIZE 6U
|
||||
#define ENCODE_CANAFTER(buf_out, caf )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, caf, 36U );
|
||||
#define _02_36_ENCODE_CANAFTER(buf_out, caf )\
|
||||
ENCODE_CANAFTER(buf_out, caf );
|
||||
|
||||
#define ENCODE_FINAFTER_SIZE 6U
|
||||
#define ENCODE_FINAFTER(buf_out, faf )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, faf, 37U );
|
||||
#define _02_37_ENCODE_FINAFTER(buf_out, faf )\
|
||||
ENCODE_FINAFTER(buf_out, faf );
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_ESCROW_SIMPLE_SIZE 282U
|
||||
#else
|
||||
#define PREPARE_ESCROW_SIMPLE_SIZE 260U
|
||||
#endif
|
||||
|
||||
#define PREPARE_ESCROW_SIMPLE(\
|
||||
buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw, finish_after, cancel_after)\
|
||||
{\
|
||||
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();\
|
||||
int64_t llt = ledger_last_time();\
|
||||
hook_account(SBUF(acc));\
|
||||
_01_02_ENCODE_TT (buf_out, ttESCROW_CREATE ); /* 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 */ \
|
||||
_02_36_ENCODE_CANAFTER (buf_out, llt + cancel_after ); /* uint32 | size 6 */ \
|
||||
_02_37_ENCODE_FINAFTER (buf_out, llt + finish_after ); /* 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 */ \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_ESCROW_SIMPLE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_ESCROW_SIMPLE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
int64_t hook(uint32_t reserved)
|
||||
{
|
||||
etxn_reserve(2);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
uint8_t txhash[32];
|
||||
uint8_t txout[PREPARE_ESCROW_SIMPLE_SIZE];
|
||||
|
||||
PREPARE_ESCROW_SIMPLE(txout, 1, carbon_accid, 0, 0, 1000, 2000);
|
||||
emit(SBUF(txhash), SBUF(txout));
|
||||
|
||||
PREPARE_ESCROW_SIMPLE(txout, 1, carbon_accid, 0, 0, 1000, 2000);
|
||||
emit(SBUF(txhash), SBUF(txout));
|
||||
|
||||
accept(0,0,0);
|
||||
|
||||
_g(1,1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user