Skip to content

Instantly share code, notes, and snippets.

@muzam1l
Forked from xrplfgists/README.md
Created August 12, 2022 10:10
Show Gist options
  • Save muzam1l/953662b22d065449f8ab6f69bc2afe41 to your computer and use it in GitHub Desktop.
Save muzam1l/953662b22d065449f8ab6f69bc2afe41 to your computer and use it in GitHub Desktop.

Carbon

Carbon hook sends a percentage of outgoing payments to a dedicated account.

The beneficiary account is hard-coded, so while the default version of carbon.c works, it works with an account that cannot be imported into Hooks Builder (unless you know its secret key). See later examples for how to parametrize a hook.

to test:

  • make sure Hooks Builder has at least 3 accounts: Alice, Bob and Carol
  • in carbon.c, change hardcoded beneficiary to Carol account
  • compile carbon.c and deploy it to Alice account
  • set up payment transaction from Alice to Bob
  • open debug stream filtered on Carol
  • run the transaction and see incoming payment

Other hook changes, such as removing the cbak function (which is included just as an example and not essential to the hook functionality), or fixing the hooks-raddr-conv-pure warning, are left as an exercise for the reader.

#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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment