#pragma once
#ifndef __LP64__
#error LP64 data model required
#endif
#define SUCCESS 0
#define TO_BUILTIN(error) ((uint64_t)(error) << 32)
#define ERROR_CUSTOM_ZERO TO_BUILTIN(1)
#define ERROR_INVALID_ARGUMENT TO_BUILTIN(2)
#define ERROR_INVALID_INSTRUCTION_DATA TO_BUILTIN(3)
#define ERROR_INVALID_ACCOUNT_DATA TO_BUILTIN(4)
#define ERROR_ACCOUNT_DATA_TOO_SMALL TO_BUILTIN(5)
#define ERROR_INSUFFICIENT_FUNDS TO_BUILTIN(6)
#define ERROR_INCORRECT_PROGRAM_ID TO_BUILTIN(7)
#define ERROR_MISSING_REQUIRED_SIGNATURES TO_BUILTIN(8)
#define ERROR_ACCOUNT_ALREADY_INITIALIZED TO_BUILTIN(9)
#define ERROR_UNINITIALIZED_ACCOUNT TO_BUILTIN(10)
#define ERROR_NOT_ENOUGH_ACCOUNT_KEYS TO_BUILTIN(11)
#define ERROR_ACCOUNT_BORROW_FAILED TO_BUILTIN(12)
#define MAX_SEED_LENGTH_EXCEEDED TO_BUILTIN(13)
#define INVALID_SEEDS TO_BUILTIN(14)
#define ERROR_NEW_ACCOUNT_NEEDED TO_BUILTIN(15)
#ifndef __cplusplus
#include <stdbool.h>
#endif
void sol_log_(const char *, uint64_t);
#define sol_log(message) sol_log_(message, sol_strlen(message))
void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
#define sol_log_64 sol_log_64_
#define SIZE_PUBKEY 32
typedef struct
{
uint8_t x[SIZE_PUBKEY];
} SolPubkey;
static bool SolPubkey_same(const SolPubkey *one, const SolPubkey *two)
{
for (int i = 0; i < sizeof(*one); i++)
{
if (one->x[i] != two->x[i])
{
return false;
}
}
return true;
}
typedef struct
{
SolPubkey *key;
uint64_t *lamports;
uint64_t data_len;
uint8_t *data;
SolPubkey *owner;
uint64_t rent_epoch;
bool is_signer;
bool is_writable;
bool executable;
} SolAccountInfo;
static void sol_memcpy(void *dst, const void *src, int len)
{
for (int i = 0; i < len; i++)
{
*((uint8_t *)dst + i) = *((const uint8_t *)src + i);
}
}
static int sol_memcmp(const void *s1, const void *s2, int n)
{
for (int i = 0; i < n; i++)
{
uint8_t diff = *((uint8_t *)s1 + i) - *((const uint8_t *)s2 + i);
if (diff)
{
return diff;
}
}
return 0;
}
static void sol_memset(void *b, int c, size_t len)
{
uint8_t *a = (uint8_t *)b;
while (len > 0)
{
*a = c;
a++;
len--;
}
}
static size_t sol_strlen(const char *s)
{
size_t len = 0;
while (*s)
{
len++;
s++;
}
return len;
}
#define SOL_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
void sol_panic_(const char *, uint64_t, uint64_t, uint64_t);
#define sol_panic() sol_panic_(__FILE__, sizeof(__FILE__), __LINE__, 0)
#define sol_assert(expr) \
if (!(expr)) \
{ \
sol_panic(); \
}
typedef struct
{
const uint8_t *addr;
uint64_t len;
} SolSignerSeed;
typedef struct
{
SolAccountInfo ka[10];
uint64_t ka_num;
const uint8_t *input;
uint64_t input_len;
SolPubkey *program_id;
const SolAccountInfo *ka_clock;
const SolAccountInfo *ka_instructions;
} SolParameters;
#define MAX_PERMITTED_DATA_INCREASE (1024 * 10)
static uint64_t sol_deserialize(const uint8_t *input, SolParameters *params)
{
if (NULL == input || NULL == params)
{
return ERROR_INVALID_ARGUMENT;
}
uint64_t max_accounts = SOL_ARRAY_SIZE(params->ka);
params->ka_num = *(uint64_t *)input;
input += sizeof(uint64_t);
for (int i = 0; i < params->ka_num; i++)
{
uint8_t dup_info = input[0];
input += sizeof(uint8_t);
if (i >= max_accounts)
{
if (dup_info == UINT8_MAX)
{
input += sizeof(uint8_t);
input += sizeof(uint8_t);
input += sizeof(uint8_t);
input += 4; input += sizeof(SolPubkey);
input += sizeof(SolPubkey);
input += sizeof(uint64_t);
uint64_t data_len = *(uint64_t *)input;
input += sizeof(uint64_t);
input += data_len;
input += MAX_PERMITTED_DATA_INCREASE;
input = (uint8_t *)(((uint64_t)input + 8 - 1) & ~(8 - 1)); input += sizeof(uint64_t);
}
else
{
input += 7; }
continue;
}
if (dup_info == UINT8_MAX)
{
params->ka[i].is_signer = *(uint8_t *)input != 0;
input += sizeof(uint8_t);
params->ka[i].is_writable = *(uint8_t *)input != 0;
input += sizeof(uint8_t);
params->ka[i].executable = *(uint8_t *)input;
input += sizeof(uint8_t);
input += 4;
params->ka[i].key = (SolPubkey *)input;
input += sizeof(SolPubkey);
params->ka[i].owner = (SolPubkey *)input;
input += sizeof(SolPubkey);
params->ka[i].lamports = (uint64_t *)input;
input += sizeof(uint64_t);
params->ka[i].data_len = *(uint64_t *)input;
input += sizeof(uint64_t);
params->ka[i].data = (uint8_t *)input;
input += params->ka[i].data_len;
input += MAX_PERMITTED_DATA_INCREASE;
input = (uint8_t *)(((uint64_t)input + 8 - 1) & ~(8 - 1));
params->ka[i].rent_epoch = *(uint64_t *)input;
input += sizeof(uint64_t);
}
else
{
params->ka[i].is_signer = params->ka[dup_info].is_signer;
params->ka[i].is_writable = params->ka[dup_info].is_writable;
params->ka[i].executable = params->ka[dup_info].executable;
params->ka[i].key = params->ka[dup_info].key;
params->ka[i].owner = params->ka[dup_info].owner;
params->ka[i].lamports = params->ka[dup_info].lamports;
params->ka[i].data_len = params->ka[dup_info].data_len;
params->ka[i].data = params->ka[dup_info].data;
params->ka[i].rent_epoch = params->ka[dup_info].rent_epoch;
input += 7; }
}
uint64_t data_len = *(uint64_t *)input;
input += sizeof(uint64_t);
params->input_len = data_len;
params->input = input;
input += data_len;
params->program_id = (SolPubkey *)input;
input += sizeof(SolPubkey);
if (params->ka_num > max_accounts)
params->ka_num = max_accounts;
return 0;
}
typedef struct
{
const uint8_t *addr;
uint64_t len;
} SolBytes;
#define SHA256_RESULT_LENGTH 32
static uint64_t sol_sha256(const SolBytes *bytes, int bytes_len, const uint8_t *result);
typedef struct
{
SolPubkey *pubkey;
bool is_writable;
bool is_signer;
} SolAccountMeta;
typedef struct
{
SolPubkey *program_id;
SolAccountMeta *accounts;
uint64_t account_len;
uint8_t *data;
uint64_t data_len;
} SolInstruction;
typedef struct
{
const SolSignerSeed *addr;
uint64_t len;
} SolSignerSeeds;
static uint64_t sol_create_program_address(const SolSignerSeed *seeds, int seeds_len, const SolPubkey *program_id,
const SolPubkey *address);
static uint64_t sol_invoke_signed(const SolInstruction *instruction, const SolAccountInfo *account_infos,
int account_infos_len, const SolSignerSeeds *signers_seeds, int signers_seeds_len)
{
uint64_t sol_invoke_signed_c(const SolInstruction *instruction, const SolAccountInfo *account_infos,
int account_infos_len, const SolSignerSeeds *signers_seeds, int signers_seeds_len);
return sol_invoke_signed_c(instruction, account_infos, account_infos_len, signers_seeds, signers_seeds_len);
}
static uint64_t sol_invoke(const SolInstruction *instruction, const SolAccountInfo *account_infos,
int account_infos_len)
{
const SolSignerSeeds signers_seeds[] = {{}};
return sol_invoke_signed(instruction, account_infos, account_infos_len, signers_seeds, 0);
}
void sol_log_pubkey(const SolPubkey *pubkey);
static void sol_log_array(const uint8_t *array, int len)
{
for (int j = 0; j < len; j++)
{
sol_log_64(0, 0, 0, j, array[j]);
}
}
static void sol_log_params(const SolParameters *params)
{
sol_log("- Program identifier:");
sol_log_pubkey(params->program_id);
sol_log("- Number of KeyedAccounts");
sol_log_64(0, 0, 0, 0, params->ka_num);
for (int i = 0; i < params->ka_num; i++)
{
sol_log(" - Is signer");
sol_log_64(0, 0, 0, 0, params->ka[i].is_signer);
sol_log(" - Is writable");
sol_log_64(0, 0, 0, 0, params->ka[i].is_writable);
sol_log(" - Key");
sol_log_pubkey(params->ka[i].key);
sol_log(" - Lamports");
sol_log_64(0, 0, 0, 0, *params->ka[i].lamports);
sol_log(" - data");
sol_log_array(params->ka[i].data, params->ka[i].data_len);
sol_log(" - Owner");
sol_log_pubkey(params->ka[i].owner);
sol_log(" - Executable");
sol_log_64(0, 0, 0, 0, params->ka[i].executable);
sol_log(" - Rent Epoch");
sol_log_64(0, 0, 0, 0, params->ka[i].rent_epoch);
}
sol_log("- Eth abi Instruction data\0");
sol_log_array(params->input, params->input_len);
}
uint64_t entrypoint(const uint8_t *input);
#ifdef SOL_TEST
#include <stdio.h>
void sol_log_(const char *s, uint64_t len)
{
printf("sol_log: %s\n", s);
}
void sol_log_64(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5)
{
printf("sol_log_64: %llu, %llu, %llu, %llu, %llu\n", arg1, arg2, arg3, arg4, arg5);
}
#endif
#ifdef __cplusplus
}
#endif