diff --git a/.env b/.env index 5ddee9d..779bf5d 100644 --- a/.env +++ b/.env @@ -1,3 +1,4 @@ -HOOKS_COMPILE_HOST=https://hook-buildbox.xrpl.org +HOOKS_COMPILE_HOST=http://0.0.0.0:9000 +# HOOKS_COMPILE_HOST=https://hook-buildbox.xrpl.org HOOKS_DEBUG_HOST=wss://xahau-test.net/debugstream XAHAU_ENV=standalone diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6996ca..2c93512 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,9 +16,15 @@ You can also build a single hook with; ## Compile JS Hooks -You can ONLY build a single js hook at a time; +## Compile C FHooks -`$ hooks-cli compile-js contracts-js/toolbox/base.ts build` +Run this command to locally compile an XAHL Hook source file (inside ./contracts) from .c to .wasm code: + +`$ hooks-cli compile-c contracts-cf build` + +You can also build a single hook with; + +`$ hooks-cli compile-c contracts-c/toolbox/base.c build` ## Test the Hook Library @@ -46,4 +52,26 @@ Run JS Hooks Integration tests Run single JS Hooks Integration test -`$ yarn run test:integration-js test/integration-js/toolbox/base.test.ts` \ No newline at end of file +`$ yarn run test:integration-js test/integration-js/toolbox/base.test.ts` + +## JS Hooks + +### Standalone + +`$ xrpld-netgen up:standalone --version=2025.2.24-HEAD+1366` + +### Compile + +You can ONLY build a single js hook at a time; + +`$ hooks-cli compile-js contracts-js/toolbox/base.ts build` + +## Functional Hooks + +### Standalone + +`$ xrpld-netgen up:standalone --version=2025.5.4-HEAD+1765` + +### Compile + +`$ hooks-cli compile-c contracts-func/toolbox/base.c build` \ No newline at end of file diff --git a/contracts-func/toolbox/base.c b/contracts-func/toolbox/base.c new file mode 100644 index 0000000..96358ec --- /dev/null +++ b/contracts-func/toolbox/base.c @@ -0,0 +1,13 @@ +#include "hookapi.h" + +int64_t func_one(uint32_t reserved) { + TRACESTR("func_one.c: Called."); + _g(1,1); + return accept(SBUF("func_one: Finished."), __LINE__); +} + +int64_t func_two(uint32_t reserved) { + TRACESTR("func_two.c: Called."); + _g(1,1); + return accept(SBUF("func_two: Finished."), __LINE__); +} \ No newline at end of file diff --git a/contracts-func/utils/hook/error.h b/contracts-func/utils/hook/error.h new file mode 100644 index 0000000..2d7060e --- /dev/null +++ b/contracts-func/utils/hook/error.h @@ -0,0 +1,51 @@ +// 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 XFL_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 INVALID_KEY -41 +#define NOT_A_STRING -42 +#define MEM_OVERLAP -43 +#define TOO_MANY_STATE_MODIFICATIONS -44 +#define TOO_MANY_NAMESPACES -45 +#define HOOK_ERROR_CODES +#endif //HOOK_ERROR_CODES \ No newline at end of file diff --git a/contracts-func/utils/hook/extern.h b/contracts-func/utils/hook/extern.h new file mode 100644 index 0000000..baf0e6d --- /dev/null +++ b/contracts-func/utils/hook/extern.h @@ -0,0 +1,354 @@ +// For documentation please see: https://xrpl-hooks.readme.io/reference/ +// Generated using generate_extern.sh +#include +#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 +rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code); + +// UTIL + +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_accid( + 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); + +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_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); + +// STO + +extern int64_t +sto_validate(uint32_t tread_ptr, uint32_t tread_len); + +extern int64_t +sto_subfield(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_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); + +// EMITTED TXN + +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_reserve(uint32_t count); + +extern int64_t +etxn_generation(void); + +extern int64_t +etxn_nonce(uint32_t write_ptr, uint32_t write_len); + +extern int64_t +emit( + uint32_t write_ptr, + uint32_t write_len, + uint32_t read_ptr, + uint32_t read_len); + +// FLOAT + +extern int64_t +float_set(int32_t exponent, int64_t mantissa); + +extern int64_t +float_multiply(int64_t float1, int64_t float2); + +extern int64_t +float_mulratio( + int64_t float1, + uint32_t round_up, + uint32_t numerator, + uint32_t denominator); + +extern int64_t +float_negate(int64_t float1); + +extern int64_t +float_compare(int64_t float1, int64_t float2, uint32_t mode); + +extern int64_t +float_sum(int64_t float1, int64_t float2); + +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_invert(int64_t float1); + +extern int64_t +float_divide(int64_t float1, int64_t float2); + +extern int64_t +float_one(void); + +extern int64_t +float_mantissa(int64_t float1); + +extern int64_t +float_sign(int64_t float1); + +extern int64_t +float_int(int64_t float1, uint32_t decimal_places, uint32_t abs); + +extern int64_t +float_log(int64_t float1); + +extern int64_t +float_root(int64_t float1, uint32_t n); + +// LEDGER + +extern int64_t +fee_base(void); + +extern int64_t +ledger_seq(void); + +extern int64_t +ledger_last_time(void); + +extern int64_t +ledger_last_hash(uint32_t write_ptr, uint32_t write_len); + +extern int64_t +ledger_nonce(uint32_t write_ptr, uint32_t write_len); + +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); + +// HOOK + +extern int64_t +hook_account(uint32_t write_ptr, uint32_t write_len); + +extern int64_t +hook_hash(uint32_t write_ptr, uint32_t write_len, int32_t hook_no); + +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_param( + uint32_t write_ptr, + uint32_t write_len, + uint32_t read_ptr, + uint32_t read_len); + +extern int64_t +hook_again(void); + +extern int64_t +hook_skip(uint32_t read_ptr, uint32_t read_len, uint32_t flags); + +extern int64_t +hook_pos(void); + +// SLOT + +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_set(uint32_t read_ptr, uint32_t read_len, uint32_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 +slot_float(uint32_t slot_no); + +// STATE + +extern int64_t +state_set( + uint32_t read_ptr, + uint32_t read_len, + uint32_t kread_ptr, + uint32_t kread_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( + 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); + +// TRACE + +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_num(uint32_t read_ptr, uint32_t read_len, int64_t number); + +extern int64_t +trace_float(uint32_t read_ptr, uint32_t read_len, int64_t float1); + +// OTXN + +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_generation(void); + +extern int64_t +otxn_id(uint32_t write_ptr, uint32_t write_len, uint32_t flags); + +extern int64_t +otxn_type(void); + +extern int64_t +otxn_slot(uint32_t slot_no); + +extern int64_t +otxn_param( + uint32_t write_ptr, + uint32_t write_len, + uint32_t read_ptr, + uint32_t read_len); + +extern int64_t +meta_slot(uint32_t slot_no); + +// featureHooks1 + +extern int64_t xpop_slot(uint32_t, uint32_t); + +#define HOOK_EXTERN +#endif // HOOK_EXTERN diff --git a/contracts-func/utils/hook/hookapi.h b/contracts-func/utils/hook/hookapi.h new file mode 100644 index 0000000..766a26c --- /dev/null +++ b/contracts-func/utils/hook/hookapi.h @@ -0,0 +1,51 @@ +/** + * 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 KEYLET_HOOK_DEFINITION 24 +#define KEYLET_HOOK_STATE_DIR 25 + +#define COMPARE_EQUAL 1U +#define COMPARE_LESS 2U +#define COMPARE_GREATER 4U + +#include "error.h" +#include "extern.h" +#include "sfcodes.h" +#include "macro.h" +#include "tts.h" + +#endif diff --git a/contracts-func/utils/hook/macro.h b/contracts-func/utils/hook/macro.h new file mode 100644 index 0000000..838c2b5 --- /dev/null +++ b/contracts-func/utils/hook/macro.h @@ -0,0 +1,381 @@ +/** + * These are helper macros for writing hooks, all of them are optional as is including macro.h at all + */ + +#include +#include "hookapi.h" +#include "sfcodes.h" + +#ifndef HOOKMACROS_INCLUDED +#define HOOKMACROS_INCLUDED 1 + +#ifdef NDEBUG +#define DEBUG 0 +#else +#define DEBUG 1 +#endif + +#define DONEEMPTY()\ + accept(0,0,__LINE__) + +#define DONEMSG(msg)\ + accept(msg, sizeof(msg),__LINE__) + +#define DONE(x)\ + accept(SVAR(x),(uint32_t)__LINE__); + +#define ASSERT(x)\ +{\ + if (!(x))\ + rollback(0,0,__LINE__);\ +} + +#define NOPE(x)\ +{\ + return rollback((x), sizeof(x), __LINE__);\ +} + +#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() +#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 SVAR(x) &x, sizeof(x) + +#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)) + +#define BUFFER_EQUAL_20(buf1, buf2)\ + (\ + *(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\ + *(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\ + *(((uint32_t*)(buf1)) + 4) == *(((uint32_t*)(buf2)) + 4)) + +#define BUFFER_EQUAL_32(buf1, buf2)\ + (\ + *(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\ + *(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\ + *(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\ + *(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3)) + +#define BUFFER_EQUAL_64(buf1, buf2) \ + ( \ + (*((uint64_t*)(buf1) + 0) == *((uint64_t*)(buf2) + 0)) && \ + (*((uint64_t*)(buf1) + 1) == *((uint64_t*)(buf2) + 1)) && \ + (*((uint64_t*)(buf1) + 2) == *((uint64_t*)(buf2) + 2)) && \ + (*((uint64_t*)(buf1) + 3) == *((uint64_t*)(buf2) + 3)) && \ + (*((uint64_t*)(buf1) + 4) == *((uint64_t*)(buf2) + 4)) && \ + (*((uint64_t*)(buf1) + 5) == *((uint64_t*)(buf2) + 5)) && \ + (*((uint64_t*)(buf1) + 6) == *((uint64_t*)(buf2) + 6)) && \ + (*((uint64_t*)(buf1) + 7) == *((uint64_t*)(buf2) + 7)) \ + ) + +// 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 = *(((uint8_t*)(buf1)) + x) == *(((uint8_t*)(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 UINT8_TO_BUF(buf_raw, i)\ +{\ + unsigned char* buf = (unsigned char*)buf_raw;\ + buf[0] = (((uint8_t)i) >> 0) & 0xFFUL;\ + if (i < 0) buf[0] |= 0x80U;\ +} + +#define UINT8_FROM_BUF(buf)\ + (((uint8_t)((buf)[0]) << 0)) + + +#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_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 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 BYTES20_TO_BUF(buf_raw, i)\ +{\ + unsigned char* buf = (unsigned char*)buf_raw;\ + *(uint64_t*)(buf + 0) = *(uint64_t*)(i + 0);\ + *(uint64_t*)(buf + 8) = *(uint64_t*)(i + 8);\ + *(uint32_t*)(buf + 16) = *(uint32_t*)(i + 16);\ +} + +#define BYTES20_FROM_BUF(buf_raw, i)\ +{\ + const unsigned char* buf = (const unsigned char*)buf_raw;\ + *(uint64_t*)(i + 0) = *(const uint64_t*)(buf + 0);\ + *(uint64_t*)(i + 8) = *(const uint64_t*)(buf + 8);\ + *(uint32_t*)(i + 16) = *(const uint32_t*)(buf + 16);\ +} + +#define BYTES32_TO_BUF(buf_raw, i)\ +{\ + unsigned char* buf = (unsigned char*)buf_raw;\ + *(uint64_t*)(buf + 0) = *(uint64_t*)(i + 0);\ + *(uint64_t*)(buf + 8) = *(uint64_t*)(i + 8);\ + *(uint64_t*)(buf + 16) = *(uint64_t*)(i + 16);\ + *(uint64_t*)(buf + 24) = *(uint64_t*)(i + 24);\ +} + +#define BYTES32_FROM_BUF(buf_raw, i)\ +{\ + const unsigned char* buf = (const unsigned char*)buf_raw;\ + *(uint64_t*)(i + 0) = *(const uint64_t*)(buf + 0);\ + *(uint64_t*)(i + 8) = *(const uint64_t*)(buf + 8);\ + *(uint64_t*)(i + 16) = *(const uint64_t*)(buf + 16);\ + *(uint64_t*)(i + 24) = *(const uint64_t*)(buf + 24);\ +} + +#define FLIP_ENDIAN_32(n) ((uint32_t) (((n & 0xFFU) << 24U) | \ + ((n & 0xFF00U) << 8U) | \ + ((n & 0xFF0000U) >> 8U) | \ + ((n & 0xFF000000U) >> 24U))) + +#define FLIP_ENDIAN_64(n) ((uint64_t)(((n & 0xFFULL) << 56ULL) | \ + ((n & 0xFF00ULL) << 40ULL) | \ + ((n & 0xFF0000ULL) << 24ULL) | \ + ((n & 0xFF000000ULL) << 8ULL) | \ + ((n & 0xFF00000000ULL) >> 8ULL) | \ + ((n & 0xFF0000000000ULL) >> 24ULL) | \ + ((n & 0xFF000000000000ULL) >> 40ULL) | \ + ((n & 0xFF00000000000000ULL) >> 56ULL))) + +#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 + +#endif + + diff --git a/contracts-func/utils/hook/sfcodes.h b/contracts-func/utils/hook/sfcodes.h new file mode 100644 index 0000000..a88278d --- /dev/null +++ b/contracts-func/utils/hook/sfcodes.h @@ -0,0 +1,238 @@ +// 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 sfNetworkID ((2U << 16U) + 1U) +#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 sfLockCount ((2U << 16U) + 49U) +#define sfFirstNFTokenSequence ((2U << 16U) + 50U) +#define sfXahauActivationLgrSeq ((2U << 16U) + 96U) +#define sfImportSequence ((2U << 16U) + 97U) +#define sfRewardTime ((2U << 16U) + 98U) +#define sfRewardLgrFirst ((2U << 16U) + 99U) +#define sfRewardLgrLast ((2U << 16U) + 100U) +#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 sfHookInstructionCount ((3U << 16U) + 17U) +#define sfHookReturnCode ((3U << 16U) + 18U) +#define sfReferenceCount ((3U << 16U) + 19U) +#define sfAccountIndex ((3U << 16U) + 98U) +#define sfAccountCount ((3U << 16U) + 99U) +#define sfRewardAccumulator ((3U << 16U) + 100U) +#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 sfHookOn ((5U << 16U) + 20U) +#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 sfOfferID ((5U << 16U) + 34U) +#define sfEscrowID ((5U << 16U) + 35U) +#define sfURITokenID ((5U << 16U) + 36U) +#define sfGovernanceFlags ((5U << 16U) + 99U) +#define sfGovernanceMarks ((5U << 16U) + 98U) +#define sfEmittedTxnID ((5U << 16U) + 97U) +#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 sfLockedBalance ((6U << 16U) + 21U) +#define sfBaseFeeDrops ((6U << 16U) + 22U) +#define sfReserveBaseDrops ((6U << 16U) + 23U) +#define sfReserveIncrementDrops ((6U << 16U) + 24U) +#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 sfBlob ((7U << 16U) + 26U) +#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 sfInform ((8U << 16U) + 99U) +#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 sfURITokenIDs ((19U << 16U) + 99U) +#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 sfGenesisMint ((14U << 16U) + 96U) +#define sfActiveValidator ((14U << 16U) + 95U) +#define sfImportVLKey ((14U << 16U) + 94U) +#define sfHookEmission ((14U << 16U) + 93U) +#define sfMintURIToken ((14U << 16U) + 92U) +#define sfAmountEntry ((14U << 16U) + 91U) +#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) +#define sfGenesisMints ((15U << 16U) + 96U) +#define sfActiveValidators ((15U << 16U) + 95U) +#define sfImportVLKeys ((15U << 16U) + 94U) +#define sfHookEmissions ((15U << 16U) + 93U) +#define sfAmounts ((15U << 16U) + 92U) \ No newline at end of file diff --git a/contracts-func/utils/hook/tts.h b/contracts-func/utils/hook/tts.h new file mode 100644 index 0000000..0973fa1 --- /dev/null +++ b/contracts-func/utils/hook/tts.h @@ -0,0 +1,43 @@ +// For documentation please see: https://xrpl-hooks.readme.io/reference/ +#define ttPAYMENT 0 +#define ttESCROW_CREATE 1 +#define ttESCROW_FINISH 2 +#define ttACCOUNT_SET 3 +#define ttESCROW_CANCEL 4 +#define ttREGULAR_KEY_SET 5 +// #define ttNICKNAME_SET 6 // deprecated +#define ttOFFER_CREATE 7 +#define ttOFFER_CANCEL 8 +#define ttTICKET_CREATE 10 +// #define ttSPINAL_TAP 11 // deprecated +#define ttSIGNER_LIST_SET 12 +#define ttPAYCHAN_CREATE 13 +#define ttPAYCHAN_FUND 14 +#define ttPAYCHAN_CLAIM 15 +#define ttCHECK_CREATE 16 +#define ttCHECK_CASH 17 +#define ttCHECK_CANCEL 18 +#define ttDEPOSIT_PREAUTH 19 +#define ttTRUST_SET 20 +#define ttACCOUNT_DELETE 21 +#define ttHOOK_SET 22 +#define ttNFTOKEN_MINT 25 +#define ttNFTOKEN_BURN 26 +#define ttNFTOKEN_CREATE_OFFER 27 +#define ttNFTOKEN_CANCEL_OFFER 28 +#define ttNFTOKEN_ACCEPT_OFFER 29 +#define ttURITOKEN_MINT 45 +#define ttURITOKEN_BURN 46 +#define ttURITOKEN_BUY 47 +#define ttURITOKEN_CREATE_SELL_OFFER 48 +#define ttURITOKEN_CANCEL_SELL_OFFER 49 +#define ttREMIT 95 +#define ttGENESIS_MINT 96 +#define ttIMPORT 97 +#define ttCLAIM_REWARD 98 +#define ttINVOKE 99 +#define ttAMENDMENT 100 +#define ttFEE 101 +#define ttUNL_MODIFY 102 +#define ttEMIT_FAILURE 103 +#define ttUNL_REPORT 104 \ No newline at end of file diff --git a/jest.config.integration-func.js b/jest.config.integration-func.js new file mode 100644 index 0000000..a7fe9be --- /dev/null +++ b/jest.config.integration-func.js @@ -0,0 +1,9 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/test/integration-func/**/*.test.ts'], + + // Set the timeout value for all tests to 2 minutes (default is 5 seconds) + testTimeout: 120000, +} diff --git a/package.json b/package.json index cf9bc1a..d069e12 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build": "tsc", "test:unit": "jest --config=jest.config.unit.js", "test:integration-c": "LOG_LEVEL=error jest --config=jest.config.integration-c.js --runInBand", + "test:integration-func": "LOG_LEVEL=error jest --config=jest.config.integration-func.js --runInBand", "test:integration-js": "LOG_LEVEL=error jest --config=jest.config.integration-js.js --runInBand", "lint": "eslint ./src/**/* --ext .ts", "format": "npx prettier --write ./src" @@ -28,7 +29,8 @@ "lodash": "^4.17.21", "reconnecting-websocket": "^4.4.0", "winston": "^3.10.0", - "xahau": "^4.0.0" + "xahau": "npm:@tequ/xahau@4.0.0-beta.1", + "xahau-binary-codec": "npm:@tequ/xahau-binary-codec@2.1.0-beta.1" }, "devDependencies": { "@tsconfig/node16": "^16.1.0", diff --git a/src/libs/xrpl-helpers/transaction.ts b/src/libs/xrpl-helpers/transaction.ts index 7f2bd4e..c762e13 100644 --- a/src/libs/xrpl-helpers/transaction.ts +++ b/src/libs/xrpl-helpers/transaction.ts @@ -18,6 +18,8 @@ import { } from 'xahau' import { hashSignedTx } from 'xahau/dist/npm/utils/hashes' import { appLogger } from '../logger' +// import { sign } from 'xahau-keypairs' +// import { encode, encodeForSigning, XrplDefinitions } from 'xahau-binary-codec' interface ServerStateRPCResult { state: { @@ -155,6 +157,24 @@ export async function submitTransaction({ }): Promise { let response: SubmitResponse try { + // transaction.SigningPubKey = wallet.publicKey + // const liveDefinitions = await client.request({ + // command: 'server_definitions', + // }) + // const _liveDefinitions = JSON.parse(JSON.stringify(liveDefinitions.result)) + // const definitions = new XrplDefinitions(_liveDefinitions) + + // const preparedTx = await client.autofill(transaction) + // console.log(JSON.stringify(preparedTx, null, 2)) + // const encoded = encodeForSigning(preparedTx, definitions) + // const signed = sign(encoded, wallet.privateKey) + // preparedTx.TxnSignature = signed + // const txBlob = encode(preparedTx, definitions) + // response = await client.request({ + // command: 'submit', + // tx_blob: txBlob, + // }) + const preparedTx = await client.autofill(transaction) response = await client.submit(preparedTx, { wallet }) @@ -352,7 +372,11 @@ export async function testTransaction( // check that the transaction is on the ledger const signedTx = omit(response.result.tx_json, 'hash') await ledgerAccept(client) - return await verifySubmittedTransaction(client, signedTx as Transaction) + return await verifySubmittedTransaction( + client, + signedTx as Transaction, + response.result.tx_json.hash + ) // return response } diff --git a/src/models/iFunctionParamName.ts b/src/models/iFunctionParamName.ts new file mode 100644 index 0000000..d82581a --- /dev/null +++ b/src/models/iFunctionParamName.ts @@ -0,0 +1,19 @@ +import { convertHexToString, convertStringToHex } from 'xahau' + +export class iFunctionParamName { + value: string + isHex: boolean + + constructor(value: string, isHex?: boolean) { + this.value = value + this.isHex = isHex ? isHex : false + } + + static fromHex(hexValue: string): iFunctionParamName { + return new iFunctionParamName(convertHexToString(hexValue)) + } + + toHex(): string { + return convertStringToHex(this.value) + } +} diff --git a/src/models/iFunctionParamType.ts b/src/models/iFunctionParamType.ts new file mode 100644 index 0000000..e3b4e1b --- /dev/null +++ b/src/models/iFunctionParamType.ts @@ -0,0 +1,11 @@ +export class iFunctionParamType { + type: string + + constructor(type: string) { + this.type = type + } + + static from(value: string): iFunctionParamType { + return new iFunctionParamType(value) + } +} diff --git a/src/models/iFunctionParamTypeEntries.ts b/src/models/iFunctionParamTypeEntries.ts new file mode 100644 index 0000000..a2a3bf2 --- /dev/null +++ b/src/models/iFunctionParamTypeEntries.ts @@ -0,0 +1,9 @@ +import { iFunctionParamTypeEntry } from './iFunctionParamTypeEntry' + +export class iFunctionParamTypeEntries { + parameters: iFunctionParamTypeEntry[] + + constructor(parameters: iFunctionParamTypeEntry[]) { + this.parameters = parameters + } +} diff --git a/src/models/iFunctionParamTypeEntry.ts b/src/models/iFunctionParamTypeEntry.ts new file mode 100644 index 0000000..deb6285 --- /dev/null +++ b/src/models/iFunctionParamTypeEntry.ts @@ -0,0 +1,23 @@ +import { iFunctionParamName } from './iFunctionParamName' +import { iFunctionParamType } from './iFunctionParamType' +import { FunctionParameter } from 'xahau/dist/npm/models/common/xahau' + +export class iFunctionParamTypeEntry { + name: iFunctionParamName + type: iFunctionParamType + + constructor(name: iFunctionParamName, type: iFunctionParamType) { + this.name = name + this.type = type + } + toXrpl(): FunctionParameter { + return { + FunctionParameter: { + FunctionParameterName: !this.name.isHex + ? this.name.toHex() + : this.name.value, + FunctionParameterType: { type: this.type.type }, + }, + } as FunctionParameter + } +} diff --git a/src/models/iFunctionParamValue.ts b/src/models/iFunctionParamValue.ts new file mode 100644 index 0000000..04dbfdd --- /dev/null +++ b/src/models/iFunctionParamValue.ts @@ -0,0 +1,28 @@ +import { convertHexToString, convertStringToHex } from 'xahau' + +export class iFunctionParamValue { + type: string + value: string + isHex: boolean + + constructor(type: string, value: string, isHex?: boolean) { + this.type = type + this.value = value + this.isHex = isHex ? isHex : false + } + + static from(type: string, value: string): iFunctionParamValue { + return new iFunctionParamValue(type, value) + } + + static fromHex(type: string, hexValue: string): iFunctionParamValue { + return new iFunctionParamValue(type, convertHexToString(hexValue)) + } + + toHex(): Record { + return { + type: this.type, + value: convertStringToHex(this.value), + } + } +} diff --git a/src/models/iFunctionParamValueEntries.ts b/src/models/iFunctionParamValueEntries.ts new file mode 100644 index 0000000..c7eb77c --- /dev/null +++ b/src/models/iFunctionParamValueEntries.ts @@ -0,0 +1,9 @@ +import { iFunctionParamValueEntry } from './iFunctionParamValueEntry' + +export class iFunctionParamValueEntries { + parameters: iFunctionParamValueEntry[] + + constructor(parameters: iFunctionParamValueEntry[]) { + this.parameters = parameters + } +} diff --git a/src/models/iFunctionParamValueEntry.ts b/src/models/iFunctionParamValueEntry.ts new file mode 100644 index 0000000..af0d87e --- /dev/null +++ b/src/models/iFunctionParamValueEntry.ts @@ -0,0 +1,31 @@ +import { iFunctionParamName } from './iFunctionParamName' +import { iFunctionParamValue } from './iFunctionParamValue' +import { FunctionParameter } from 'xahau/dist/npm/models/common/xahau' + +export class iFunctionParamValueEntry { + name: iFunctionParamName + value?: iFunctionParamValue + + constructor(name: iFunctionParamName, value?: iFunctionParamValue) { + this.name = name + this.value = value + } + + fromHex(name: string, type: string, value: string) { + this.name = new iFunctionParamName(name) + this.value = new iFunctionParamValue(type, value) + } + + toXrpl(): FunctionParameter { + return { + FunctionParameter: { + FunctionParameterName: !this.name.isHex + ? this.name.toHex() + : this.name.value, + FunctionParameterValue: !this.value.isHex + ? this.value.toHex() + : { type: this.value.type, value: this.value.value }, + }, + } as FunctionParameter + } +} diff --git a/src/models/iHookFunctionEntries.ts b/src/models/iHookFunctionEntries.ts new file mode 100644 index 0000000..4be7df7 --- /dev/null +++ b/src/models/iHookFunctionEntries.ts @@ -0,0 +1,9 @@ +import { iHookFunctionEntry } from './iHookFunctionEntry' + +export class iHookFunctionEntries { + functions: iHookFunctionEntry[] + + constructor(functions: iHookFunctionEntry[]) { + this.functions = functions + } +} diff --git a/src/models/iHookFunctionEntry.ts b/src/models/iHookFunctionEntry.ts new file mode 100644 index 0000000..cab1dff --- /dev/null +++ b/src/models/iHookFunctionEntry.ts @@ -0,0 +1,49 @@ +import { iFunctionParamTypeEntries } from './iFunctionParamTypeEntries' +import { iFunctionParamValueEntries } from './iFunctionParamValueEntries' +import { iHookFunctionName } from './iHookFunctionName' +import { HookFunction } from './tmp' + +export interface iHookFunction { + FunctionName: string + FunctionParameters: string + Flags: number + Fee: number +} + +export class iHookFunctionEntry { + name: iHookFunctionName + parameters?: iFunctionParamTypeEntries | iFunctionParamValueEntries + + constructor( + name: iHookFunctionName, + parameters?: iFunctionParamTypeEntries | iFunctionParamValueEntries + ) { + this.name = name + this.parameters = parameters + } + + fromHex(name: string) { + this.name = new iHookFunctionName(name) + } + + toXrpl(): HookFunction { + const hookFunction: HookFunction = { + HookFunction: { + FunctionName: !this.name.isHex ? this.name.toHex() : this.name.value, + }, + } + if (this.parameters && this.parameters.parameters.length > 0) { + // console.log( + // this.parameters.parameters.map((param: any) => { + // return param.toXrpl() + // }) + // ) + + hookFunction.HookFunction.FunctionParameters = + this.parameters.parameters.map((param: any) => param.toXrpl()) + } + console.log(hookFunction) + + return hookFunction + } +} diff --git a/src/models/iHookFunctionName.ts b/src/models/iHookFunctionName.ts new file mode 100644 index 0000000..411a28a --- /dev/null +++ b/src/models/iHookFunctionName.ts @@ -0,0 +1,19 @@ +import { convertHexToString, convertStringToHex } from 'xahau' + +export class iHookFunctionName { + value: string + isHex: boolean + + constructor(value: string, isHex?: boolean) { + this.value = value + this.isHex = isHex ? isHex : false + } + + static fromHex(hexValue: string): iHookFunctionName { + return new iHookFunctionName(convertHexToString(hexValue)) + } + + toHex(): string { + return convertStringToHex(this.value) + } +} diff --git a/src/models/index.ts b/src/models/index.ts index e9b0326..24555b9 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,5 +1,15 @@ export * from './iHookEmittedTxs' export * from './iHookExecutions' +export * from './iFunctionParamName' +export * from './iFunctionParamType' +export * from './iFunctionParamTypeEntries' +export * from './iFunctionParamTypeEntry' +export * from './iFunctionParamValue' +export * from './iFunctionParamValueEntries' +export * from './iFunctionParamValueEntry' +export * from './iHookFunctionEntries' +export * from './iHookFunctionEntry' +export * from './iHookFunctionName' export * from './iHookGrantAuthorize' export * from './iHookGrantEntries' export * from './iHookGrantEntry' diff --git a/src/models/tmp.ts b/src/models/tmp.ts new file mode 100644 index 0000000..93ccf82 --- /dev/null +++ b/src/models/tmp.ts @@ -0,0 +1,8 @@ +export interface HookFunction { + HookFunction: { + FunctionName: string + FunctionParameters?: string[] + Flags?: number + Fee?: string + } +} diff --git a/src/setHooks.ts b/src/setHooks.ts index da5590c..3c3e602 100644 --- a/src/setHooks.ts +++ b/src/setHooks.ts @@ -9,6 +9,40 @@ import { HookGrant, HookParameter } from 'xahau/dist/npm/models/common/xahau' import { readHookBinaryHexFromNS, hexNamespace } from './utils' import { appTransaction } from './libs/xrpl-helpers/transaction' import { appLogger } from './libs/logger' +import { HookFunction } from './models/tmp' + +function isHex(value: string): boolean { + return /^[0-9A-F]+$/iu.test(value) +} + +function hexValue(value: string): string { + return Buffer.from(value, 'utf8').toString('hex').toUpperCase() +} + +/** + * Calculate the hex of the hook parameters + * + * @param data - the hook parameters + * @returns the hex of the hook parameters + */ +export function hexHookFunctions(data: HookFunction[]): HookFunction[] { + const hookFunctions: HookFunction[] = [] + for (const hookFunction of data) { + let hookFName = hookFunction.HookFunction.FunctionName + + if (!isHex(hookFName)) { + hookFName = hexValue(hookFName) + } + + hookFunctions.push({ + HookFunction: { + FunctionName: hookFName, + FunctionParameters: hookFunction.HookFunction.FunctionParameters, + }, + }) + } + return hookFunctions +} export interface SetHookPayload { version?: number | null @@ -20,6 +54,7 @@ export interface SetHookPayload { hookParams?: HookParameter[] | null hookGrants?: HookGrant[] | null fee?: string | null + functions?: HookFunction[] | null } export function createHookPayload(payload: SetHookPayload): iHook { @@ -62,11 +97,14 @@ export function createHookPayload(payload: SetHookPayload): iHook { if (payload.hookGrants) { hook.HookGrants = payload.hookGrants } + if (payload.functions) { + // @ts-expect-error -- TODO: Fix this type error + hook.HookFunctions = hexHookFunctions(payload.functions) + } // DA: validate return hook } - export async function setHooksV3({ client, wallet, hooks }: SetHookParams) { const tx: SetHook = { TransactionType: `SetHook`, @@ -87,7 +125,6 @@ export async function setHooksV3({ client, wallet, hooks }: SetHookParams) { appLogger.debug(`\n3. SetHook Success...`) } - export async function clearAllHooksV3({ client, wallet }: SetHookParams) { const hook = { CreateCode: '', diff --git a/test/integration-func/hooks/toolbox/base.test.ts b/test/integration-func/hooks/toolbox/base.test.ts new file mode 100644 index 0000000..2f65bfe --- /dev/null +++ b/test/integration-func/hooks/toolbox/base.test.ts @@ -0,0 +1,91 @@ +// xrpl +import { + convertStringToHex, + Invoke, + SetHookFlags, + TransactionMetadata, +} from 'xahau' +import { + // Testing + XrplIntegrationTestContext, + setupClient, + teardownClient, + serverUrl, + // Main + Xrpld, + SetHookParams, + ExecutionUtility, + createHookPayload, + setHooksV3, + // clearAllHooksV3, + iHookFunctionEntry, + iHookFunctionName, + iFunctionParamTypeEntry, + iFunctionParamName, + iFunctionParamType, + iFunctionParamTypeEntries, +} from '../../../../dist/npm/src' + +describe('base', () => { + let testContext: XrplIntegrationTestContext + + beforeAll(async () => { + testContext = await setupClient(serverUrl) + const hook1Func1Param1 = new iFunctionParamTypeEntry( + new iFunctionParamName('amount'), + new iFunctionParamType('UINT8') + ) + const hook1Func1Params = new iFunctionParamTypeEntries([hook1Func1Param1]) + const hook1Func1 = new iHookFunctionEntry( + new iHookFunctionName('func_one'), + hook1Func1Params + ) + const hook1Func2 = new iHookFunctionEntry(new iHookFunctionName('func_two')) + const hook = createHookPayload({ + version: 3, + createFile: 'base', + namespace: 'base', + flags: SetHookFlags.hsfOverride, + hookOnArray: ['Invoke'], + functions: [hook1Func1.toXrpl(), hook1Func2.toXrpl()], + }) + console.log(JSON.stringify(hook, null, 2)) + + await setHooksV3({ + client: testContext.client, + wallet: testContext.hook1, + hooks: [{ Hook: hook }], + } as SetHookParams) + }) + afterAll(async () => { + // await clearAllHooksV3({ + // client: testContext.client, + // wallet: testContext.hook1, + // } as SetHookParams) + await teardownClient(testContext) + }) + + it('basic hook', async () => { + // INVOKE IN + const aliceWallet = testContext.alice + const hookWallet = testContext.hook1 + + const builtTx: Invoke = { + TransactionType: 'Invoke', + Account: aliceWallet.classicAddress, + Destination: hookWallet.classicAddress, + FunctionName: convertStringToHex('func_one'), + } + const result = await Xrpld.submit(testContext.client, { + wallet: aliceWallet, + tx: builtTx, + }) + const hookExecutions = await ExecutionUtility.getHookExecutionsFromMeta( + testContext.client, + result.meta as TransactionMetadata + ) + expect(hookExecutions.executions[0].HookReturnString).toMatch( + 'base: Finished.' + ) + }) +}) diff --git a/yarn.lock b/yarn.lock index 7fc82b6..e38376a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -708,6 +708,15 @@ dependencies: "@sinonjs/commons" "^3.0.0" +"@tequ/xahau-binary-codec@^2.1.0-beta.1": + version "2.1.0-beta.1" + resolved "https://registry.yarnpkg.com/@tequ/xahau-binary-codec/-/xahau-binary-codec-2.1.0-beta.1.tgz#c285adc7cb3357669890ae398f418e333bc3d731" + integrity sha512-iSOSS6Uxm9CBOXbHfBstzJONS6nqziE1vhycLeseNPcmma0a9Vox3/2B8+Cgogc2vs/B1HUtSHFMlhOtfaxi7A== + dependencies: + "@xrplf/isomorphic" "^1.0.1" + bignumber.js "^9.0.0" + xahau-address-codec "^5.0.0" + "@transia/binary-models@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@transia/binary-models/-/binary-models-1.1.0.tgz#48c9f4d0be8296e024467db82e0621f6f871da1a" @@ -3361,10 +3370,10 @@ xahau-address-codec@^5.0.0: "@scure/base" "^1.1.3" "@xrplf/isomorphic" "^1.0.0" -xahau-binary-codec@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/xahau-binary-codec/-/xahau-binary-codec-2.1.0.tgz#6a696767000512a1c43980a93e139d5b6f4f5fd5" - integrity sha512-pb3YR6GQW6v/G3g/kDfgY5egT4XU6lqfEzYzf1LdoqmdS+UjmiVqz9UMQBNd5nKMrSYQuzy2ExfaAK5srRr5nQ== +"xahau-binary-codec@npm:@tequ/xahau-binary-codec@2.1.0-beta.1": + version "2.1.0-beta.1" + resolved "https://registry.yarnpkg.com/@tequ/xahau-binary-codec/-/xahau-binary-codec-2.1.0-beta.1.tgz#c285adc7cb3357669890ae398f418e333bc3d731" + integrity sha512-iSOSS6Uxm9CBOXbHfBstzJONS6nqziE1vhycLeseNPcmma0a9Vox3/2B8+Cgogc2vs/B1HUtSHFMlhOtfaxi7A== dependencies: "@xrplf/isomorphic" "^1.0.1" bignumber.js "^9.0.0" @@ -3379,19 +3388,19 @@ xahau-keypairs@^2.0.0: "@xrplf/isomorphic" "^1.0.0" xahau-address-codec "^5.0.0" -xahau@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xahau/-/xahau-4.0.0.tgz#36decff11c1a2b0ef4fdf4d7c944599bd4654c4a" - integrity sha512-IWk6gdrJTm8FvAtlY5TY3ofyD4n5143WP/GBYD/cByhR4iiygfVLtLyeB2Ujwzre/PjJZIEFqWR8eXKBie8oaw== +"xahau@npm:@tequ/xahau@4.0.0-beta.1": + version "4.0.0-beta.1" + resolved "https://registry.yarnpkg.com/@tequ/xahau/-/xahau-4.0.0-beta.1.tgz#1606273b9e0910dc66e002fdb4b088b7d24a55c7" + integrity sha512-urPioutWZHfngS3X1+ftBgGfAnbx/xO4AZLCiLTTLaggnyrMTO+InUC+aCWDVa8oN4L6YpAd4hMyKBQGOgaFZw== dependencies: "@scure/bip32" "^1.3.1" "@scure/bip39" "^1.2.1" + "@tequ/xahau-binary-codec" "^2.1.0-beta.1" "@xrplf/isomorphic" "^1.0.1" "@xrplf/secret-numbers" "^1.0.0" bignumber.js "^9.0.0" eventemitter3 "^5.0.1" xahau-address-codec "^5.0.0" - xahau-binary-codec "^2.1.0" xahau-keypairs "^2.0.0" y18n@^5.0.5: