Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/algorithms/ENTRYPOINT.tex
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
\INPUT $r_1$ = input
\COMMENT{Pointer to instruction data.}
\INPUT $r_2$ = insn
\COMMENT{Pointer to stack frame.}
\INPUT $r_{10}$ = frame
\PROCEDURE{ENTRYPOINT}{input, insn}
\STATE n\_accounts = input.n\_accounts
\STATE insn\_len = insn.length
\STATE insn\_disc = insn.discriminant
\IF{insn\_disc == \texttt{Discriminant::RegisterMarket}}
\RETURN \CALL{REGISTER-MARKET}{input, insn, n\_accounts, insn\_len}
\RETURN \CALL{REGISTER-MARKET}{input, insn, n\_accounts, insn\_len, frame}
\ENDIF
\RETURN \texttt{ErrorCode::InvalidDiscriminant}
\ENDPROCEDURE
Expand Down
44 changes: 44 additions & 0 deletions docs/algorithms/INIT-VAULT.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
\begin{algorithm}
\caption{INIT-VAULT}
\begin{algorithmic}
\COMMENT{Pointer to vault account.}
\INPUT $r_1$ = acct
\COMMENT{Pointer to REGISTER-MARKET stack frame.}
\INPUT $r_2$ = frame
\REQUIRE frame.vault\_index $\in$ \{
\texttt{register\_misc.VAULT\_INDEX\_BASE},
\texttt{register\_misc.VAULT\_INDEX\_QUOTE}
\}
\REQUIRE frame.token\_program\_is\_2022 $\in$ \{
\texttt{true},
\texttt{false}
\}
\COMMENT{Pointer to owning token program address.}
\REQUIRE frame.token\_program\_id
\COMMENT{Pointer to input buffer.}
\REQUIRE frame.input
\REQUIRE frame.pda\_seeds[0].len = \texttt{Address.size}
\FUNCTION{INIT-VAULT}{acct, frame}
\STATE \CALL{Store}{frame}
\STATE \CALL{Store}{acct}
\COMMENT{Derive vault PDA.}
\STATE frame.pda\_seeds[0].addr = \&input.market.address
\STATE frame.pda\_seeds[1].addr = \&frame.vault\_index
\STATE frame.pda\_seeds[1].len = \texttt{u8.size}
\STATE syscall.seeds = \&frame.pda\_seeds
\STATE syscall.seeds\_len = \texttt{register\_misc.TRY\_FIND\_VAULT\_PDA\_SEEDS\_LEN}
\STATE syscall.program\_id = frame.token\_program\_id
\STATE syscall.program\_address = \&frame.pda
\STATE syscall.bump\_seed = \&frame.bump
\STATE \CALL{sol-try-find-program-address}{}
\COMMENT{Verify vault address matches derived PDA.}
\IF{acct.address $\neq$ frame.pda}
\IF{frame.vault\_index == \texttt{register\_misc.VAULT\_INDEX\_BASE}}
\RETURN \texttt{ErrorCode::InvalidBaseVaultPubkey}
\ELSE
\RETURN \texttt{ErrorCode::InvalidQuoteVaultPubkey}
\ENDIF
\ENDIF
\ENDFUNCTION
\end{algorithmic}
\end{algorithm}
67 changes: 30 additions & 37 deletions docs/algorithms/REGISTER-MARKET.tex
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
\INPUT $r_3$ = n\_accounts
\COMMENT{Instruction data length.}
\INPUT $r_4$ = insn\_len
\COMMENT{Pointer to stack frame.}
\INPUT $r_{10}$ = frame
\REQUIRE insn.discriminant == \texttt{Discriminant::RegisterMarket}
\PROCEDURE{REGISTER-MARKET}{input, insn, n\_accounts, insn\_len}
\PROCEDURE{REGISTER-MARKET}{input, insn, n\_accounts, insn\_len, frame}
\COMMENT{Check number of accounts and instruction data length.}
\IF{n\_accounts $<$ \texttt{RegisterMarketAccounts.LEN}}
\RETURN \texttt{ErrorCode::InvalidNumberOfAccounts}
Expand All @@ -32,7 +34,7 @@
\IF{input.base\_mint.duplicate $\neq$ \texttt{account.NON\_DUP\_MARKER}}
\RETURN \texttt{ErrorCode::BaseMintIsDuplicate}
\ENDIF
\STATE frame.pda\_seeds[0].addr = input.base\_mint.pubkey
\STATE frame.pda\_seeds[0].addr = input.base\_mint.address
\STATE frame.pda\_seeds[0].len = \texttt{Address.size}
\COMMENT{Increment input buffer by base mint padded data length for quote offsets.}
\STATE input\_shifted = input + input.base\_mint.padded\_data\_len
Expand All @@ -41,7 +43,7 @@
\IF{input\_shifted.quote\_mint.duplicate $\neq$ \texttt{account.NON\_DUP\_MARKER}}
\RETURN \texttt{ErrorCode::QuoteMintIsDuplicate}
\ENDIF
\STATE frame.pda\_seeds[1].addr = input\_shifted.quote\_mint.pubkey
\STATE frame.pda\_seeds[1].addr = input\_shifted.quote\_mint.address
\STATE frame.pda\_seeds[1].len = \texttt{Address.size}
\COMMENT{Advance to System Program account.}
\STATE quote\_mint\_padded\_data\_len = input\_shifted.quote\_mint.padded\_data\_len
Expand All @@ -55,9 +57,9 @@
\STATE syscall.program\_address = \&frame.pda
\STATE syscall.bump\_seed = \&frame.bump
\STATE \CALL{sol-try-find-program-address}{}
\COMMENT{Verify derived market PDA matches market account pubkey.}
\COMMENT{Verify derived market PDA matches market account address.}
\STATE input = frame.input
\IF{input.market.pubkey $\neq$ frame.market\_pda}
\IF{input.market.address $\neq$ frame.market\_pda}
\RETURN \texttt{ErrorCode::InvalidMarketPubkey}
\ENDIF
\COMMENT{Populate bump signer seed from derived bump.}
Expand All @@ -69,7 +71,7 @@
\IF{acct.duplicate $\neq$ \texttt{account.NON\_DUP\_MARKER}}
\RETURN \texttt{ErrorCode::SystemProgramIsDuplicate}
\ENDIF
\IF{acct.pubkey $\neq$ frame.system\_program\_pubkey}
\IF{acct.address $\neq$ frame.system\_program\_pubkey}
\RETURN \texttt{ErrorCode::InvalidSystemProgramPubkey}
\ENDIF
\COMMENT{Populate CPI program ID field.}
Expand All @@ -81,7 +83,7 @@
\IF{acct.duplicate $\neq$ \texttt{account.NON\_DUP\_MARKER}}
\RETURN \texttt{ErrorCode::RentSysvarIsDuplicate}
\ENDIF
\IF{acct.pubkey $\neq$ \texttt{pubkey.RENT}}
\IF{acct.address $\neq$ \texttt{pubkey.RENT}}
\RETURN \texttt{ErrorCode::InvalidRentSysvarPubkey}
\ENDIF
\COMMENT{Prepare CreateAccount instruction lamports, space fields.}
Expand Down Expand Up @@ -137,51 +139,46 @@
\RETURN \texttt{ErrorCode::BaseTokenProgramIsDuplicate}
\ENDIF
\COMMENT{Verify base token program owns the base mint.}
\IF{acct.pubkey $\neq$ input.base\_mint.owner}
\IF{acct.address $\neq$ input.base\_mint.owner}
\RETURN \texttt{ErrorCode::BaseTokenProgramNotBaseMintOwner}
\ENDIF
\COMMENT{Verify base token program is Token Program or Token 2022.}
\IF{acct.pubkey $\neq$ \texttt{pubkey.TOKEN\_PROGRAM}}
\IF{acct.pubkey $\neq$ \texttt{pubkey.TOKEN\_2022\_PROGRAM}}
\IF{acct.address $\neq$ \texttt{pubkey.TOKEN\_PROGRAM}}
\IF{acct.address $\neq$ \texttt{pubkey.TOKEN\_2022\_PROGRAM}}
\RETURN \texttt{ErrorCode::BaseTokenProgramNotTokenProgram}
\ENDIF
\STATE frame.token\_program\_is\_2022 = \texttt{true}
\ENDIF
\COMMENT{Derive base vault PDA from base token program.}
\STATE frame.pda\_seeds[0].addr = \&input.market.address
\STATE frame.vault\_index = \texttt{register\_misc.VAULT\_INDEX\_BASE}
\STATE frame.pda\_seeds[1].addr = \&frame.vault\_index
\STATE frame.pda\_seeds[1].len = \texttt{u8.size}
\STATE syscall.seeds = \&frame.pda\_seeds
\STATE syscall.seeds\_len = \texttt{register\_misc.TRY\_FIND\_VAULT\_PDA\_SEEDS\_LEN}
\STATE syscall.program\_id = \&acct.address
\STATE syscall.program\_address = \&frame.pda
\STATE syscall.bump\_seed = \&frame.bump
\STATE \CALL{sol-try-find-program-address}{}
\STATE frame.token\_program\_id = \&acct.address
\COMMENT{Advance to base vault account.}
\STATE base\_token\_program\_padded\_data\_len = acct.padded\_data\_len
\STATE acct += base\_token\_program\_padded\_data\_len + \texttt{EmptyAccount.size}
\COMMENT{Verify base vault address matches derived PDA.}
\IF{acct.pubkey $\neq$ frame.pda}
\RETURN \texttt{ErrorCode::InvalidBaseVaultPubkey}
\COMMENT{Initialize base vault account.}
\STATE frame.vault\_index = \texttt{register\_misc.VAULT\_INDEX\_BASE}
\STATE result = \CALL{INIT-VAULT}{acct, frame}
\IF{result $\neq$ \texttt{entrypoint.RETURN\_SUCCESS}}
\RETURN result
\ENDIF
\COMMENT{Advance to quote token program account.}
\STATE base\_vault\_padded\_data\_len = acct.padded\_data\_len
\STATE acct += base\_vault\_padded\_data\_len + \texttt{EmptyAccount.size}
\COMMENT{Check quote token program account.}
\IF{acct.duplicate == \texttt{account.NON\_DUP\_MARKER}}
\COMMENT{Non-duplicate; verify quote token program owns the quote mint.}
\IF{acct.pubkey $\neq$ input\_shifted.quote\_mint.owner}
\IF{acct.address $\neq$ input\_shifted.quote\_mint.owner}
\RETURN \texttt{ErrorCode::NonDupQuoteTokenProgramNotQuoteMintOwner}
\ENDIF
\COMMENT{Verify quote token program is Token Program or Token 2022.}
\IF{acct.pubkey $\neq$ \texttt{pubkey.TOKEN\_PROGRAM}}
\IF{acct.pubkey $\neq$ \texttt{pubkey.TOKEN\_2022\_PROGRAM}}
\IF{acct.address $\neq$ \texttt{pubkey.TOKEN\_PROGRAM}}
\IF{acct.address $\neq$ \texttt{pubkey.TOKEN\_2022\_PROGRAM}}
\RETURN \texttt{ErrorCode::QuoteTokenProgramNotTokenProgram}
\ENDIF
\STATE frame.token\_program\_is\_2022 = \texttt{true}
\ELSE
\STATE frame.token\_program\_is\_2022 = \texttt{false}
\ENDIF
\COMMENT{Update syscall program ID from non-duplicate quote token program.}
\STATE syscall.program\_id = \&acct.address
\COMMENT{Advance past non-duplicate quote token program account.}
\STATE frame.token\_program\_id = \&acct.address
\COMMENT{Advance to quote vault account.}
\STATE quote\_token\_program\_padded\_data\_len = acct.padded\_data\_len
\STATE acct += quote\_token\_program\_padded\_data\_len + \texttt{EmptyAccount.size}
\ELSE
Expand All @@ -193,16 +190,12 @@
\IF{input.base\_mint.owner $\neq$ input\_shifted.quote\_mint.owner}
\RETURN \texttt{ErrorCode::DupQuoteTokenProgramNotQuoteMintOwner}
\ENDIF
\COMMENT{Advance past duplicate quote token program account.}
\COMMENT{Advance to quote vault account.}
\STATE acct += \texttt{u64.size}
\ENDIF
\COMMENT{Derive quote vault PDA.}
\COMMENT{Initialize quote vault account.}
\STATE frame.vault\_index = \texttt{register\_misc.VAULT\_INDEX\_QUOTE}
\STATE \CALL{sol-try-find-program-address}{}
\COMMENT{Verify quote vault address matches derived PDA.}
\IF{acct.pubkey $\neq$ frame.pda}
\RETURN \texttt{ErrorCode::InvalidQuoteVaultPubkey}
\ENDIF
\STATE \CALL{INIT-VAULT}{acct, frame}
\ENDPROCEDURE
\end{algorithmic}
\end{algorithm}
1 change: 1 addition & 0 deletions docs/src/program/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ program/src/dropset/
│ ├── memory.s # Memory layout constants
│ └── pubkey.s # Pubkey chunk offsets and known addresses
└── market/
├── init_vault.s # InitVault function
└── register.s # RegisterMarket handler
```

Expand Down
4 changes: 4 additions & 0 deletions docs/src/program/markets.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ The instruction requires the following accounts:

<Algorithm tex="REGISTER-MARKET" asm="market/register"/>

## Vault initialization

<Algorithm tex="INIT-VAULT" asm="market/init_vault"/>

[input buffer]: inputs#input-buffer
2 changes: 2 additions & 0 deletions interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ constant_group! {
INSN_LEN = offset!(-size_of::<u64>()),
/// Offset from instruction data to discriminant, in input buffer.
INSN_DISC = offset!(0),
/// Successful return code.
RETURN_SUCCESS = immediate!(0),
}
}

Expand Down
12 changes: 12 additions & 0 deletions interface/src/market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ signer_seeds! {
#[frame]
/// Stack frame for REGISTER-MARKET.
pub struct RegisterMarketFrame {
/// Saved acct pointer across INIT-VAULT syscall.
pub acct: u64,
/// Pointer to owning token program address.
pub token_program_id: u64,
/// Saved input buffer pointer.
pub input: u64,
/// Saved input_shifted pointer.
Expand All @@ -169,6 +173,8 @@ pub struct RegisterMarketFrame {
pub bump: u8,
/// Vault index for PDA derivation.
pub vault_index: u8,
/// Whether the current token program is Token 2022.
pub token_program_is_2022: u8,
}
// endregion: frame_example

Expand All @@ -177,6 +183,10 @@ constant_group! {
#[inject("market/register")]
#[frame(RegisterMarketFrame)]
frame {
/// Saved acct pointer across INIT-VAULT syscall.
ACCT = offset!(acct),
/// Pointer to owning token program address.
TOKEN_PROGRAM_ID = offset!(token_program_id),
/// Saved input buffer pointer.
INPUT = offset!(input),
/// Saved input_shifted pointer.
Expand Down Expand Up @@ -207,6 +217,8 @@ constant_group! {
BUMP = offset!(bump),
/// Vault index for PDA derivation.
VAULT_INDEX = unaligned_offset!(vault_index),
/// Whether the current token program is Token 2022.
TOKEN_PROGRAM_IS_2022 = unaligned_offset!(token_program_is_2022),
/// From pda_seeds to sol_instruction.
PDA_SEEDS_TO_SOL_INSN = relative_offset!(pda_seeds, sol_instruction),
/// From pda to signers_seeds.
Expand Down
4 changes: 4 additions & 0 deletions interface/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ constant_group! {
LEN_MAX_PAD = immediate!(7),
/// And mask for data length alignment.
LEN_AND_MASK = immediate!(-8),
/// Boolean false value.
BOOL_FALSE = immediate!(0),
/// Boolean true value.
BOOL_TRUE = immediate!(1),
}
}

Expand Down
4 changes: 0 additions & 4 deletions program/src/dropset/common/error.s
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,3 @@ e_quote_token_program_not_token_program:
e_invalid_base_vault_pubkey:
mov32 r0, E_INVALID_BASE_VAULT_PUBKEY
exit

e_invalid_quote_vault_pubkey:
mov32 r0, E_INVALID_QUOTE_VAULT_PUBKEY
exit
2 changes: 2 additions & 0 deletions program/src/dropset/common/memory.s
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
# Maximum possible data length padding for a runtime account.
.equ DATA_LEN_MAX_PAD, 7
.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment.
.equ DATA_BOOL_FALSE, 0 # Boolean false value.
.equ DATA_BOOL_TRUE, 1 # Boolean true value.
# -------------------------------------------------------------------------

# Input buffer constants for static header.
Expand Down
1 change: 1 addition & 0 deletions program/src/dropset/dropset.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
.include "common/pubkey.s"
.include "entrypoint.s"
.include "market/register.s"
.include "market/init_vault.s"
1 change: 1 addition & 0 deletions program/src/dropset/entrypoint.s
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.equ INSN_LEN_OFF, -8
# Offset from instruction data to discriminant, in input buffer.
.equ INSN_DISC_OFF, 0
.equ RETURN_SUCCESS, 0 # Successful return code.

entrypoint:
# n_accounts = input.n_accounts
Expand Down
53 changes: 53 additions & 0 deletions program/src/dropset/market/init_vault.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
init_vault:
# Store(frame)
mov64 r6, r2
# Store(acct)
mov64 r7, r1
# frame.pda_seeds[0].addr = &input.market.address
ldxdw r8, [r6 + RM_FM_INPUT_OFF]
add64 r8, IB_MARKET_PUBKEY_OFF
stxdw [r6 + RM_FM_PDA_SEEDS_IDX_0_ADDR_OFF], r8
# frame.pda_seeds[1].addr = &frame.vault_index
mov64 r8, r6
add64 r8, RM_FM_VAULT_INDEX_UOFF
stxdw [r6 + RM_FM_PDA_SEEDS_IDX_1_ADDR_OFF], r8
# frame.pda_seeds[1].len = u8.size
mov64 r8, SIZE_OF_U8
stxdw [r6 + RM_FM_PDA_SEEDS_IDX_1_LEN_OFF], r8
# syscall.seeds = &frame.pda_seeds
mov64 r1, r6
add64 r1, RM_FM_PDA_SEEDS_OFF
# syscall.seeds_len = register_misc.TRY_FIND_VAULT_PDA_SEEDS_LEN
mov64 r2, RM_MISC_TRY_FIND_VAULT_PDA_SEEDS_LEN
# syscall.program_id = frame.token_program_id
ldxdw r3, [r6 + RM_FM_TOKEN_PROGRAM_ID_OFF]
# syscall.program_address = &frame.pda
mov64 r4, r6
add64 r4, RM_FM_PDA_OFF
# syscall.bump_seed = &frame.bump
mov64 r5, r6
add64 r5, RM_FM_BUMP_OFF
call sol_try_find_program_address
# if acct.address != frame.pda
ldxdw r1, [r7 + ACCT_ADDRESS_CHUNK_0_OFF]
ldxdw r2, [r6 + RM_FM_PDA_CHUNK_0_OFF]
jne r1, r2, init_vault_invalid_pda
ldxdw r1, [r7 + ACCT_ADDRESS_CHUNK_1_OFF]
ldxdw r2, [r6 + RM_FM_PDA_CHUNK_1_OFF]
jne r1, r2, init_vault_invalid_pda
ldxdw r1, [r7 + ACCT_ADDRESS_CHUNK_2_OFF]
ldxdw r2, [r6 + RM_FM_PDA_CHUNK_2_OFF]
jne r1, r2, init_vault_invalid_pda
ldxdw r1, [r7 + ACCT_ADDRESS_CHUNK_3_OFF]
ldxdw r2, [r6 + RM_FM_PDA_CHUNK_3_OFF]
jne r1, r2, init_vault_invalid_pda
exit
init_vault_invalid_pda:
# if frame.vault_index == register_misc.VAULT_INDEX_BASE
# return ErrorCode::InvalidBaseVaultPubkey
# else
# return ErrorCode::InvalidQuoteVaultPubkey
ldxb r1, [r6 + RM_FM_VAULT_INDEX_UOFF]
jeq r1, RM_MISC_VAULT_INDEX_BASE, e_invalid_base_vault_pubkey
mov32 r0, E_INVALID_QUOTE_VAULT_PUBKEY
exit
Loading
Loading