mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 06:48:16 +00:00
feat(solana): add solana templates
- code is broken because depending modules are added in the next commit
This commit is contained in:
parent
bf45d51af6
commit
b3f4b6ac2b
10
Makefile
10
Makefile
@ -112,6 +112,12 @@ templates: icons ## rebuild coin lists from definitions in common
|
|||||||
templates_check: ## check that coin lists are up to date
|
templates_check: ## check that coin lists are up to date
|
||||||
./core/tools/build_templates --check
|
./core/tools/build_templates --check
|
||||||
|
|
||||||
|
solana_templates: ## rebuild Solana instruction template file
|
||||||
|
./core/tools/build_solana_templates
|
||||||
|
|
||||||
|
solana_templates_check: ## check that Solana instruction template file is up to date
|
||||||
|
./core/tools/build_solana_templates --check
|
||||||
|
|
||||||
icons: ## generate FIDO service icons
|
icons: ## generate FIDO service icons
|
||||||
python3 core/tools/build_icons.py
|
python3 core/tools/build_icons.py
|
||||||
|
|
||||||
@ -138,6 +144,6 @@ vendorheader: ## generate vendor header
|
|||||||
vendorheader_check: ## check that vendor header is up to date
|
vendorheader_check: ## check that vendor header is up to date
|
||||||
./core/embed/vendorheader/generate.sh --quiet --check
|
./core/embed/vendorheader/generate.sh --quiet --check
|
||||||
|
|
||||||
gen: mocks icons templates protobuf ci_docs vendorheader ## regenerate auto-generated files from sources
|
gen: mocks icons templates protobuf ci_docs vendorheader solana_templates ## regenerate auto-generated files from sources
|
||||||
|
|
||||||
gen_check: mocks_check icons_check templates_check protobuf_check ci_docs_check vendorheader_check ## check validity of auto-generated files
|
gen_check: mocks_check icons_check templates_check protobuf_check ci_docs_check vendorheader_check solana_templates_check ## check validity of auto-generated files
|
||||||
|
@ -166,6 +166,12 @@ templates: ## render Mako templates (for lists of coins, tokens, etc.)
|
|||||||
templates_check: ## check that Mako-rendered files match their templates
|
templates_check: ## check that Mako-rendered files match their templates
|
||||||
./tools/build_templates --check
|
./tools/build_templates --check
|
||||||
|
|
||||||
|
solana_templates: ## rebuild Solana instruction template file
|
||||||
|
./tools/build_solana_templates
|
||||||
|
|
||||||
|
solana_templates_check: ## check that Solana instruction template file is up to date
|
||||||
|
./tools/build_solana_templates --check
|
||||||
|
|
||||||
## build commands:
|
## build commands:
|
||||||
|
|
||||||
build: build_boardloader build_bootloader build_firmware build_prodtest build_unix ## build all
|
build: build_boardloader build_bootloader build_firmware build_prodtest build_unix ## build all
|
||||||
|
@ -689,6 +689,8 @@ if not utils.BITCOIN_ONLY:
|
|||||||
import apps.solana.get_public_key
|
import apps.solana.get_public_key
|
||||||
apps.solana.sign_tx
|
apps.solana.sign_tx
|
||||||
import apps.solana.sign_tx
|
import apps.solana.sign_tx
|
||||||
|
apps.solana.transaction.instructions
|
||||||
|
import apps.solana.transaction.instructions
|
||||||
apps.stellar
|
apps.stellar
|
||||||
import apps.stellar
|
import apps.stellar
|
||||||
apps.stellar.consts
|
apps.stellar.consts
|
||||||
|
5370
core/src/apps/solana/transaction/instructions.py
Normal file
5370
core/src/apps/solana/transaction/instructions.py
Normal file
File diff suppressed because it is too large
Load Diff
225
core/src/apps/solana/transaction/instructions.py.mako
Normal file
225
core/src/apps/solana/transaction/instructions.py.mako
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
# generated from instructions.py.mako
|
||||||
|
# do not edit manually!
|
||||||
|
<%def name="getProgramId(program)">${"_".join(program["name"].upper().split(" ") + ["ID"])}</%def>\
|
||||||
|
<%def name="getInstructionIdText(program, instruction)">${"_".join([getProgramId(program)] + ["INS"] + instruction["name"].upper().split(" "))}</%def>\
|
||||||
|
<%def name="getClassName(program, instruction)">${program["name"].replace(" ", "")}${instruction["name"].replace(" ", "")}Instruction</%def>\
|
||||||
|
<%def name="getReferenceName(reference)">${"_".join(reference["name"].lower().split(" "))}</%def>\
|
||||||
|
<%def name="getReferenceOptionalType(reference)">\
|
||||||
|
% if reference["optional"]:
|
||||||
|
| None\
|
||||||
|
% endif
|
||||||
|
</%def>\
|
||||||
|
<%def name="getReferenceOptionalTemplate(reference)">\
|
||||||
|
% if reference["optional"]:
|
||||||
|
, True\
|
||||||
|
% else:
|
||||||
|
, False\
|
||||||
|
% endif
|
||||||
|
</%def>\
|
||||||
|
<%def name="getPythonType(type)">\
|
||||||
|
% if type in ("u32", "u64", "i32", "i64", "timestamp", "lamports", "token_amount"):
|
||||||
|
int\
|
||||||
|
% elif type in ("pubKey", "authority"):
|
||||||
|
Account\
|
||||||
|
% elif type in ("string", "memo"):
|
||||||
|
str\
|
||||||
|
% else:
|
||||||
|
int\
|
||||||
|
% endif
|
||||||
|
</%def>\
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor.wire import DataError
|
||||||
|
|
||||||
|
from apps.common.readers import read_uint32_le, read_uint64_le
|
||||||
|
|
||||||
|
from ..types import AccountTemplate, PropertyTemplate, UIProperty
|
||||||
|
from ..format import (
|
||||||
|
format_int,
|
||||||
|
format_lamports,
|
||||||
|
format_pubkey,
|
||||||
|
format_identity,
|
||||||
|
format_token_amount,
|
||||||
|
format_unix_timestamp,
|
||||||
|
)
|
||||||
|
from .instruction import Instruction
|
||||||
|
from .parse import (
|
||||||
|
parse_byte,
|
||||||
|
parse_memo,
|
||||||
|
parse_pubkey,
|
||||||
|
parse_string,
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Type
|
||||||
|
|
||||||
|
from ..types import Account, InstructionId, InstructionData
|
||||||
|
|
||||||
|
% for program in programs["programs"]:
|
||||||
|
${getProgramId(program)} = "${program["id"]}"
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% for program in programs["programs"]:
|
||||||
|
% for instruction in program["instructions"]:
|
||||||
|
${getInstructionIdText(program, instruction)} = ${instruction["id"]}
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
def __getattr__(name: str) -> Type[Instruction]:
|
||||||
|
def get_id(name: str) -> tuple[str, InstructionId]:
|
||||||
|
%for program in programs["programs"]:
|
||||||
|
%for instruction in program["instructions"]:
|
||||||
|
if name == "${getClassName(program, instruction)}":
|
||||||
|
return ("${program["id"]}", ${instruction["id"]})
|
||||||
|
%endfor
|
||||||
|
%endfor
|
||||||
|
raise AttributeError # Unknown instruction
|
||||||
|
|
||||||
|
id = get_id(name)
|
||||||
|
|
||||||
|
class FakeClass(Instruction):
|
||||||
|
@classmethod
|
||||||
|
def is_type_of(cls, ins: Any):
|
||||||
|
return ins.program_id == id[0] and ins.instruction_id == id[1]
|
||||||
|
|
||||||
|
return FakeClass
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
% for program in programs["programs"]:
|
||||||
|
## generates classes for instructions
|
||||||
|
% for instruction in program["instructions"]:
|
||||||
|
class ${getClassName(program, instruction)}(Instruction):
|
||||||
|
## generates properties for instruction parameters
|
||||||
|
% for parameter in instruction["parameters"]:
|
||||||
|
${parameter["name"]}: ${getPythonType(parameter["type"])}
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
## generates properties for reference accounts
|
||||||
|
% for reference in instruction["references"]:
|
||||||
|
${getReferenceName(reference)}: Account${getReferenceOptionalType(reference)}
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
def get_instruction_id_length(program_id: str) -> int:
|
||||||
|
% for program in programs["programs"]:
|
||||||
|
if program_id == ${getProgramId(program)}:
|
||||||
|
return ${program["instruction_id_length"]}
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
% for _, type in programs["types"].items():
|
||||||
|
% if "is_enum" in type and type["is_enum"]:
|
||||||
|
def ${type["format"]}(_: Instruction, value: int) -> str:
|
||||||
|
% for variant in type["fields"]:
|
||||||
|
if value == ${variant["value"]}:
|
||||||
|
return "${variant["name"]}"
|
||||||
|
% endfor
|
||||||
|
raise DataError("Unknown value")
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
<%def name="getOptionalString(obj, string)">\
|
||||||
|
% if string in obj:
|
||||||
|
"${obj[string]}"\
|
||||||
|
%else:
|
||||||
|
None\
|
||||||
|
% endif
|
||||||
|
</%def>\
|
||||||
|
|
||||||
|
<%
|
||||||
|
# Make sure that all required parameters are present in the instruction.
|
||||||
|
for program in programs["programs"]:
|
||||||
|
for instruction in program["instructions"]:
|
||||||
|
for parameter in instruction["parameters"]:
|
||||||
|
if "required_parameters" in programs["types"][parameter["type"]]:
|
||||||
|
for required_parameter in programs["types"][parameter["type"]]["required_parameters"]:
|
||||||
|
instruction_parameter_names = [parameter["name"] for parameter in instruction["parameters"]]
|
||||||
|
if required_parameter not in instruction_parameter_names:
|
||||||
|
raise Exception(f"Instruction \"{instruction['name']}\" is missing the required parameter \"{required_parameter}\" from paremeter \"{parameter['name']}\".")
|
||||||
|
%>
|
||||||
|
|
||||||
|
def get_instruction(
|
||||||
|
program_id: str, instruction_id: InstructionId, instruction_accounts: list[Account], instruction_data: InstructionData
|
||||||
|
) -> Instruction:
|
||||||
|
% for program in programs["programs"]:
|
||||||
|
% if len(program["instructions"]) > 0:
|
||||||
|
if program_id == ${getProgramId(program)}:
|
||||||
|
% for instruction in program["instructions"]:
|
||||||
|
if instruction_id == ${getInstructionIdText(program, instruction)}:
|
||||||
|
return Instruction(
|
||||||
|
instruction_data,
|
||||||
|
program_id,
|
||||||
|
instruction_accounts,
|
||||||
|
${getInstructionIdText(program, instruction)},
|
||||||
|
[
|
||||||
|
% for parameter in instruction["parameters"]:
|
||||||
|
PropertyTemplate(
|
||||||
|
"${parameter["name"]}",
|
||||||
|
${parameter["type"] == "authority"},
|
||||||
|
${parameter["optional"]},
|
||||||
|
${programs["types"][parameter["type"]]["parse"]},
|
||||||
|
${programs["types"][parameter["type"]]["format"]},
|
||||||
|
),
|
||||||
|
% endfor
|
||||||
|
],
|
||||||
|
[
|
||||||
|
% for reference in instruction["references"]:
|
||||||
|
AccountTemplate(
|
||||||
|
"${reference["name"]}",
|
||||||
|
${reference["is_authority"]},
|
||||||
|
${reference["optional"]},
|
||||||
|
),
|
||||||
|
% endfor
|
||||||
|
],
|
||||||
|
[
|
||||||
|
% for ui_property in instruction["ui_properties"]:
|
||||||
|
UIProperty(
|
||||||
|
${getOptionalString(ui_property, "parameter")},
|
||||||
|
${getOptionalString(ui_property, "account")},
|
||||||
|
"${ui_property["display_name"]}",
|
||||||
|
${ui_property["is_authority"] if "is_authority" in ui_property else False},
|
||||||
|
${ui_property["default_value_to_hide"] if "default_value_to_hide" in ui_property else None},
|
||||||
|
),
|
||||||
|
% endfor
|
||||||
|
],
|
||||||
|
"${program["name"]}: ${instruction["name"]}",
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
${instruction["is_multisig"]},
|
||||||
|
${getOptionalString(instruction, "is_deprecated_warning")},
|
||||||
|
)
|
||||||
|
% endfor
|
||||||
|
return Instruction(
|
||||||
|
instruction_data,
|
||||||
|
program_id,
|
||||||
|
instruction_accounts,
|
||||||
|
instruction_id,
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
"${program["name"]}",
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
False
|
||||||
|
)
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
return Instruction(
|
||||||
|
instruction_data,
|
||||||
|
program_id,
|
||||||
|
instruction_accounts,
|
||||||
|
0,
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
"Unsupported program",
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
False
|
||||||
|
)
|
||||||
|
|
3255
core/src/apps/solana/transaction/programs.json
Normal file
3255
core/src/apps/solana/transaction/programs.json
Normal file
File diff suppressed because it is too large
Load Diff
70
core/tools/build_solana_templates
Executable file
70
core/tools/build_solana_templates
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CWD=`dirname "$0"`
|
||||||
|
RENDER="python3 $CWD/build_solana_templates.py"
|
||||||
|
|
||||||
|
PROGRAMS_FILE_PATH="$CWD/../src/apps/solana/transaction/programs.json"
|
||||||
|
|
||||||
|
FW_PATH="$CWD/../src/apps/solana/transaction"
|
||||||
|
FW_TEMPLATE_PATH="$FW_PATH/instructions.py.mako"
|
||||||
|
FW_OUTPUT_PATH="$FW_PATH/instructions.py"
|
||||||
|
|
||||||
|
TESTS_PATH="$CWD/../../tests/device_tests/solana/construct"
|
||||||
|
TESTS_TEMPLATE_PATH="$TESTS_PATH/instructions.py.mako"
|
||||||
|
TESTS_OUTPUT_PATH="$TESTS_PATH/instructions.py"
|
||||||
|
|
||||||
|
format() {
|
||||||
|
isort $1 -q
|
||||||
|
black $1 -q
|
||||||
|
flake8 $1 -q
|
||||||
|
}
|
||||||
|
|
||||||
|
check_results() {
|
||||||
|
TEMPLATE_PATH=$1
|
||||||
|
OUTPUT_PATH=$2
|
||||||
|
|
||||||
|
CHECK_FAIL=0
|
||||||
|
|
||||||
|
TMP="./core/tools/solana_template_check$(date +%s).py"
|
||||||
|
touch $TMP
|
||||||
|
|
||||||
|
TARGET=$OUTPUT_PATH
|
||||||
|
$RENDER $TEMPLATE_PATH -p $PROGRAMS_FILE_PATH -o $TMP
|
||||||
|
format $TMP
|
||||||
|
|
||||||
|
if ! diff -u "$TARGET" "$TMP"; then
|
||||||
|
CHECK_FAIL=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm $TMP
|
||||||
|
|
||||||
|
exit $CHECK_FAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
set_output_timestamp() {
|
||||||
|
TEMPLATE_PATH=$1
|
||||||
|
OUTPUT_PATH=$2
|
||||||
|
|
||||||
|
PROGRAMS_FILE_TIMESTAMP=$(date -r $PROGRAMS_FILE_PATH)
|
||||||
|
TEMPLATE_TIMESTAMP=$(date -r $TEMPLATE_PATH)
|
||||||
|
|
||||||
|
if [[ "$PROGRAMS_FILE_TIMESTAMP" > "$TEMPLATE_TIMESTAMP" ]]; then
|
||||||
|
touch $OUTPUT_PATH -r $PROGRAMS_FILE_PATH
|
||||||
|
else
|
||||||
|
touch $OUTPUT_PATH -r $TEMPLATE_PATH
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$1" = "--check" ]; then
|
||||||
|
check_results $FW_PATH $FW_OUTPUT_PATH
|
||||||
|
check_results $TESTS_PATH $TESTS_OUTPUT_PATH
|
||||||
|
else
|
||||||
|
$RENDER $FW_PATH -p $PROGRAMS_FILE_PATH -o $FW_OUTPUT_PATH
|
||||||
|
format $FW_OUTPUT_PATH
|
||||||
|
set_output_timestamp $FW_TEMPLATE_PATH $FW_OUTPUT_PATH
|
||||||
|
|
||||||
|
$RENDER $TESTS_PATH -p "$PROGRAMS_FILE_PATH" -o $TESTS_OUTPUT_PATH
|
||||||
|
format $TESTS_OUTPUT_PATH
|
||||||
|
set_output_timestamp $TESTS_TEMPLATE_PATH $TESTS_OUTPUT_PATH
|
||||||
|
fi
|
22
core/tools/build_solana_templates.py
Executable file
22
core/tools/build_solana_templates.py
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
# !/usr/bin/env python3
|
||||||
|
from json import load
|
||||||
|
|
||||||
|
import click
|
||||||
|
from mako.template import Template
|
||||||
|
from munch import munchify
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.argument("template_path", type=str)
|
||||||
|
@click.option("-p", "--programs-file", type=click.File(mode="r"), default="-")
|
||||||
|
@click.option("-o", "--out-file", type=click.File(mode="w"), default="-")
|
||||||
|
def render(template_path, programs_file, out_file):
|
||||||
|
programs = munchify(load(programs_file))
|
||||||
|
|
||||||
|
template = Template(filename=f"{template_path}/instructions.py.mako")
|
||||||
|
|
||||||
|
out_file.write(template.render(programs=programs))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
render()
|
@ -4,8 +4,8 @@ set -e
|
|||||||
CWD=`dirname "$0"`
|
CWD=`dirname "$0"`
|
||||||
RENDER="$CWD/../vendor/trezor-common/tools/cointool.py render"
|
RENDER="$CWD/../vendor/trezor-common/tools/cointool.py render"
|
||||||
|
|
||||||
# Search both in `core/src` and `core/embed`
|
# Search both in `core/src` and `core/embed` - Solana templates are excluded since those are handled separately
|
||||||
FIND_TEMPLATES="find $CWD/.. -name *.mako -not -name _proto*"
|
FIND_TEMPLATES="find $CWD/.. -name *.mako -not -name _proto* -not -path *solana*"
|
||||||
|
|
||||||
check_results() {
|
check_results() {
|
||||||
CHECK_FAIL=0
|
CHECK_FAIL=0
|
||||||
|
1404
tests/device_tests/solana/construct/instructions.py
Normal file
1404
tests/device_tests/solana/construct/instructions.py
Normal file
File diff suppressed because it is too large
Load Diff
123
tests/device_tests/solana/construct/instructions.py.mako
Normal file
123
tests/device_tests/solana/construct/instructions.py.mako
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# generated from __init__.py.mako
|
||||||
|
# do not edit manually!
|
||||||
|
|
||||||
|
<%
|
||||||
|
CONSTRUCT_TYPES = {
|
||||||
|
"u64": "Int64ul",
|
||||||
|
"i64": "Int64ul",
|
||||||
|
"unix_timestamp": "Int64ul",
|
||||||
|
"u32": "Int32ul",
|
||||||
|
"i32": "Int32ul",
|
||||||
|
"StakeAuthorize": "Int32ul",
|
||||||
|
"u8": "Byte",
|
||||||
|
"AuthorityType": "Byte",
|
||||||
|
"pubkey": "PublicKey",
|
||||||
|
"authority": "PublicKey",
|
||||||
|
"string": "String",
|
||||||
|
"memo": "Memo",
|
||||||
|
}
|
||||||
|
INSTRUCTION_TYPES = {
|
||||||
|
0: "Pass",
|
||||||
|
1: "Byte",
|
||||||
|
4: "Int32ul",
|
||||||
|
}
|
||||||
|
def upper_snake_case(name):
|
||||||
|
return "_".join(name.split(" ")).upper()
|
||||||
|
def camelcase(name):
|
||||||
|
return "".join([word.capitalize() for word in name.split(" ")])
|
||||||
|
def instruction_id(instruction):
|
||||||
|
return "INS_" + upper_snake_case(instruction.name)
|
||||||
|
def instruction_struct_name(program, instruction):
|
||||||
|
return camelcase(program.name) + "_" + camelcase(instruction.name) + "_Instruction"
|
||||||
|
def instruction_subcon(program, instruction):
|
||||||
|
if instruction.id is None:
|
||||||
|
return "Pass"
|
||||||
|
instruction_id_type = INSTRUCTION_TYPES[program.instruction_id_length]
|
||||||
|
return f"Const({instruction.id}, {instruction_id_type})"
|
||||||
|
%>\
|
||||||
|
from enum import Enum
|
||||||
|
from construct import (
|
||||||
|
Byte,
|
||||||
|
Const,
|
||||||
|
GreedyBytes,
|
||||||
|
GreedyRange,
|
||||||
|
Int32ul,
|
||||||
|
Int64ul,
|
||||||
|
Optional,
|
||||||
|
Pass,
|
||||||
|
Select,
|
||||||
|
Struct,
|
||||||
|
)
|
||||||
|
from .custom_constructs import (
|
||||||
|
CompactArray,
|
||||||
|
CompactStruct,
|
||||||
|
HexStringAdapter,
|
||||||
|
Memo,
|
||||||
|
OptionalParameter,
|
||||||
|
PublicKey,
|
||||||
|
String,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Program(Enum):
|
||||||
|
% for program in programs.programs:
|
||||||
|
${upper_snake_case(program.name)} = "${program.id}"
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% for program in programs.programs:
|
||||||
|
|
||||||
|
${"#"} ${program.name} begin
|
||||||
|
|
||||||
|
class ${camelcase(program.name)}Instruction(Enum):
|
||||||
|
% for instruction in program.instructions:
|
||||||
|
${upper_snake_case(instruction.name)} = ${instruction.id}
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% for instruction in program.instructions:
|
||||||
|
${camelcase(program.name)}_${camelcase(instruction.name)} = Struct(
|
||||||
|
"program_index" / Byte,
|
||||||
|
"accounts" / CompactStruct(
|
||||||
|
% for reference in instruction.references:
|
||||||
|
% if reference.optional:
|
||||||
|
"${reference.name}" / Optional(Byte),
|
||||||
|
% else:
|
||||||
|
"${reference.name}" / Byte,
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
% if instruction.is_multisig:
|
||||||
|
"multisig_signers" / Optional(GreedyRange(Byte))
|
||||||
|
% endif
|
||||||
|
),
|
||||||
|
"data" / CompactStruct(
|
||||||
|
"instruction_id" / ${instruction_subcon(program, instruction)},
|
||||||
|
% for parameter in instruction.parameters:
|
||||||
|
% if parameter["optional"]:
|
||||||
|
"${parameter["name"]}" / OptionalParameter(${CONSTRUCT_TYPES.get(parameter.type)}),
|
||||||
|
% else:
|
||||||
|
"${parameter["name"]}" / ${CONSTRUCT_TYPES.get(parameter.type, "Int64ul")},
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
${camelcase(program.name)}_Instruction = Select(
|
||||||
|
%for instruction in program.instructions:
|
||||||
|
${camelcase(program.name)}_${camelcase(instruction.name)},
|
||||||
|
%endfor
|
||||||
|
)
|
||||||
|
|
||||||
|
${"#"} ${program.name} end
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
PROGRAMS = {
|
||||||
|
% for program in programs.programs:
|
||||||
|
"${program.id}": ${camelcase(program.name)}_Instruction,
|
||||||
|
%endfor
|
||||||
|
}
|
||||||
|
|
||||||
|
UnknownInstruction = Struct(
|
||||||
|
"program_index" / Byte,
|
||||||
|
"accounts" / CompactArray(Byte),
|
||||||
|
"data" / HexStringAdapter(GreedyBytes),
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user