diff --git a/docs/algorithms/ENTRYPOINT.tex b/docs/algorithms/ENTRYPOINT.tex
index 5c20040..a097be3 100644
--- a/docs/algorithms/ENTRYPOINT.tex
+++ b/docs/algorithms/ENTRYPOINT.tex
@@ -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
diff --git a/docs/algorithms/INIT-VAULT.tex b/docs/algorithms/INIT-VAULT.tex
new file mode 100644
index 0000000..a1f3844
--- /dev/null
+++ b/docs/algorithms/INIT-VAULT.tex
@@ -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}
diff --git a/docs/algorithms/REGISTER-MARKET.tex b/docs/algorithms/REGISTER-MARKET.tex
index d257278..c22b373 100644
--- a/docs/algorithms/REGISTER-MARKET.tex
+++ b/docs/algorithms/REGISTER-MARKET.tex
@@ -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}
@@ -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
@@ -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
@@ -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.}
@@ -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.}
@@ -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.}
@@ -137,32 +139,25 @@
\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
@@ -170,18 +165,20 @@
\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
@@ -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}
diff --git a/docs/src/program/layout.md b/docs/src/program/layout.md
index 91063bb..913000d 100644
--- a/docs/src/program/layout.md
+++ b/docs/src/program/layout.md
@@ -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
```
diff --git a/docs/src/program/markets.md b/docs/src/program/markets.md
index dfa3611..60b714a 100644
--- a/docs/src/program/markets.md
+++ b/docs/src/program/markets.md
@@ -22,4 +22,8 @@ The instruction requires the following accounts:
+## Vault initialization
+
+
+
[input buffer]: inputs#input-buffer
diff --git a/interface/src/lib.rs b/interface/src/lib.rs
index c325f17..a135690 100644
--- a/interface/src/lib.rs
+++ b/interface/src/lib.rs
@@ -74,6 +74,8 @@ constant_group! {
INSN_LEN = offset!(-size_of::()),
/// Offset from instruction data to discriminant, in input buffer.
INSN_DISC = offset!(0),
+ /// Successful return code.
+ RETURN_SUCCESS = immediate!(0),
}
}
diff --git a/interface/src/market.rs b/interface/src/market.rs
index 9745500..0af45b0 100644
--- a/interface/src/market.rs
+++ b/interface/src/market.rs
@@ -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.
@@ -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
@@ -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.
@@ -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.
diff --git a/interface/src/memory.rs b/interface/src/memory.rs
index aac1bb3..9c8fb7e 100644
--- a/interface/src/memory.rs
+++ b/interface/src/memory.rs
@@ -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),
}
}
diff --git a/program/src/dropset/common/error.s b/program/src/dropset/common/error.s
index 7951c64..4e78e23 100644
--- a/program/src/dropset/common/error.s
+++ b/program/src/dropset/common/error.s
@@ -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
diff --git a/program/src/dropset/common/memory.s b/program/src/dropset/common/memory.s
index a244370..394483e 100644
--- a/program/src/dropset/common/memory.s
+++ b/program/src/dropset/common/memory.s
@@ -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.
diff --git a/program/src/dropset/dropset.s b/program/src/dropset/dropset.s
index 70d6e2f..5575b3e 100644
--- a/program/src/dropset/dropset.s
+++ b/program/src/dropset/dropset.s
@@ -7,3 +7,4 @@
.include "common/pubkey.s"
.include "entrypoint.s"
.include "market/register.s"
+.include "market/init_vault.s"
diff --git a/program/src/dropset/entrypoint.s b/program/src/dropset/entrypoint.s
index b868306..b9d6f24 100644
--- a/program/src/dropset/entrypoint.s
+++ b/program/src/dropset/entrypoint.s
@@ -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
diff --git a/program/src/dropset/market/init_vault.s b/program/src/dropset/market/init_vault.s
new file mode 100644
index 0000000..d868784
--- /dev/null
+++ b/program/src/dropset/market/init_vault.s
@@ -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
diff --git a/program/src/dropset/market/register.s b/program/src/dropset/market/register.s
index 8f243e6..1334a86 100644
--- a/program/src/dropset/market/register.s
+++ b/program/src/dropset/market/register.s
@@ -24,6 +24,9 @@
# Stack frame for REGISTER-MARKET.
# -------------------------------------------------------------------------
+.equ RM_FM_ACCT_OFF, -480 # Saved acct pointer across INIT-VAULT syscall.
+# Pointer to owning token program address.
+.equ RM_FM_TOKEN_PROGRAM_ID_OFF, -472
.equ RM_FM_INPUT_OFF, -464 # Saved input buffer pointer.
.equ RM_FM_INPUT_SHIFTED_OFF, -456 # Saved input_shifted pointer.
.equ RM_FM_PDA_SEEDS_OFF, -448 # Signer seeds offset.
@@ -139,6 +142,8 @@
.equ RM_FM_SOL_INSN_DATA_LEN_UOFF, -16 # SolInstruction data length.
.equ RM_FM_BUMP_OFF, -8 # Bump seed.
.equ RM_FM_VAULT_INDEX_UOFF, -7 # Vault index for PDA derivation.
+# Whether the current token program is Token 2022.
+.equ RM_FM_TOKEN_PROGRAM_IS_2022_UOFF, -6
# From pda_seeds to sol_instruction.
.equ RM_FM_PDA_SEEDS_TO_SOL_INSN_REL_OFF_IMM, 400
# From pda to signers_seeds.
@@ -483,35 +488,13 @@ register_market_check_base_token_2022:
ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_3_OFF]
lddw r1, PUBKEY_TOKEN_2022_PROGRAM_CHUNK_3
jne r7, r1, e_base_token_program_not_token_program
+ # frame.token_program_is_2022 = true
+ stb [r10 + RM_FM_TOKEN_PROGRAM_IS_2022_UOFF], DATA_BOOL_TRUE
register_market_base_vault:
- # frame.pda_seeds[0].addr = &input.market.address
- mov64 r7, r8
- add64 r7, IB_MARKET_PUBKEY_OFF
- stxdw [r10 + RM_FM_PDA_SEEDS_IDX_0_ADDR_OFF], r7
- # frame.vault_index = register_misc.VAULT_INDEX_BASE
- stb [r10 + RM_FM_VAULT_INDEX_UOFF], RM_MISC_VAULT_INDEX_BASE
- # frame.pda_seeds[1].addr = &frame.vault_index
- mov64 r7, r10
- add64 r7, RM_FM_VAULT_INDEX_UOFF
- stxdw [r10 + RM_FM_PDA_SEEDS_IDX_1_ADDR_OFF], r7
- # frame.pda_seeds[1].len = u8.size
- mov64 r7, SIZE_OF_U8
- stxdw [r10 + RM_FM_PDA_SEEDS_IDX_1_LEN_OFF], r7
- # syscall.seeds = &frame.pda_seeds
- mov64 r1, r10
- 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 = &acct.address
- mov64 r3, r9
- add64 r3, ACCT_ADDRESS_OFF
- # syscall.program_address = &frame.pda
- mov64 r4, r10
- add64 r4, RM_FM_PDA_OFF
- # syscall.bump_seed = &frame.bump
- mov64 r5, r10
- add64 r5, RM_FM_BUMP_OFF
- call sol_try_find_program_address
+ # frame.token_program_id = &acct.address
+ mov64 r7, r9
+ add64 r7, ACCT_ADDRESS_OFF
+ stxdw [r10 + RM_FM_TOKEN_PROGRAM_ID_OFF], r7
# base_token_program_padded_data_len = acct.padded_data_len
ldxdw r7, [r9 + ACCT_DATA_LEN_OFF]
add64 r7, DATA_LEN_MAX_PAD
@@ -519,20 +502,17 @@ register_market_base_vault:
# acct += base_token_program_padded_data_len + EmptyAccount.size
add64 r9, r7
add64 r9, SIZE_OF_EMPTY_ACCOUNT
- # if acct.pubkey != frame.pda
- # return ErrorCode::InvalidBaseVaultPubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_0_OFF]
- ldxdw r2, [r10 + RM_FM_PDA_CHUNK_0_OFF]
- jne r7, r2, e_invalid_base_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_1_OFF]
- ldxdw r2, [r10 + RM_FM_PDA_CHUNK_1_OFF]
- jne r7, r2, e_invalid_base_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_2_OFF]
- ldxdw r2, [r10 + RM_FM_PDA_CHUNK_2_OFF]
- jne r7, r2, e_invalid_base_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_3_OFF]
- ldxdw r2, [r10 + RM_FM_PDA_CHUNK_3_OFF]
- jne r7, r2, e_invalid_base_vault_pubkey
+ # frame.vault_index = register_misc.VAULT_INDEX_BASE
+ stb [r10 + RM_FM_VAULT_INDEX_UOFF], RM_MISC_VAULT_INDEX_BASE
+ # result = INIT-VAULT(acct, frame)
+ mov64 r1, r9
+ mov64 r2, r10
+ call init_vault
+ # if result != entrypoint.RETURN_SUCCESS
+ # return result
+ jeq r0, RETURN_SUCCESS, register_market_quote_token_program
+ exit
+register_market_quote_token_program:
# base_vault_padded_data_len = acct.padded_data_len
ldxdw r7, [r9 + ACCT_DATA_LEN_OFF]
add64 r7, DATA_LEN_MAX_PAD
@@ -571,7 +551,7 @@ register_market_base_vault:
jne r7, r2, register_market_check_quote_token_2022
ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_3_OFF]
lddw r2, PUBKEY_TOKEN_PROGRAM_CHUNK_3
- jeq r7, r2, register_market_advance_quote_non_dup
+ jeq r7, r2, register_market_quote_is_token_program
register_market_check_quote_token_2022:
ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_0_OFF]
lddw r2, PUBKEY_TOKEN_2022_PROGRAM_CHUNK_0
@@ -585,10 +565,17 @@ register_market_check_quote_token_2022:
ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_3_OFF]
lddw r2, PUBKEY_TOKEN_2022_PROGRAM_CHUNK_3
jne r7, r2, e_quote_token_program_not_token_program
+ # frame.token_program_is_2022 = true
+ stb [r10 + RM_FM_TOKEN_PROGRAM_IS_2022_UOFF], DATA_BOOL_TRUE
+ ja register_market_advance_quote_non_dup
+register_market_quote_is_token_program:
+ # frame.token_program_is_2022 = false
+ stb [r10 + RM_FM_TOKEN_PROGRAM_IS_2022_UOFF], DATA_BOOL_FALSE
register_market_advance_quote_non_dup:
- # syscall.program_id = &acct.address
- mov64 r3, r9
- add64 r3, ACCT_ADDRESS_OFF
+ # frame.token_program_id = &acct.address
+ mov64 r7, r9
+ add64 r7, ACCT_ADDRESS_OFF
+ stxdw [r10 + RM_FM_TOKEN_PROGRAM_ID_OFF], r7
# quote_token_program_padded_data_len = acct.padded_data_len
ldxdw r7, [r9 + ACCT_DATA_LEN_OFF]
add64 r7, DATA_LEN_MAX_PAD
@@ -615,29 +602,13 @@ register_market_base_vault_dup:
ldxdw r7, [r8 + RM_MISC_BASE_OWNER_CHUNK_3_OFF]
ldxdw r2, [r6 + RM_MISC_QUOTE_OWNER_CHUNK_3_OFF]
jne r7, r2, e_dup_quote_token_program_not_quote_mint_owner
- # syscall.program_id = &input.base_mint.owner
- mov64 r3, r8
- add64 r3, RM_MISC_BASE_OWNER_OFF
# acct += u64.size
add64 r9, SIZE_OF_U64
register_market_done_token_programs:
# frame.vault_index = register_misc.VAULT_INDEX_QUOTE
stb [r10 + RM_FM_VAULT_INDEX_UOFF], RM_MISC_VAULT_INDEX_QUOTE
- # syscall.seeds_len = register_misc.TRY_FIND_VAULT_PDA_SEEDS_LEN
- mov64 r2, RM_MISC_TRY_FIND_VAULT_PDA_SEEDS_LEN
- call sol_try_find_program_address
- # if acct.pubkey != frame.pda
- # return ErrorCode::InvalidQuoteVaultPubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_0_OFF]
- ldxdw r1, [r10 + RM_FM_PDA_CHUNK_0_OFF]
- jne r7, r1, e_invalid_quote_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_1_OFF]
- ldxdw r1, [r10 + RM_FM_PDA_CHUNK_1_OFF]
- jne r7, r1, e_invalid_quote_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_2_OFF]
- ldxdw r1, [r10 + RM_FM_PDA_CHUNK_2_OFF]
- jne r7, r1, e_invalid_quote_vault_pubkey
- ldxdw r7, [r9 + ACCT_ADDRESS_CHUNK_3_OFF]
- ldxdw r1, [r10 + RM_FM_PDA_CHUNK_3_OFF]
- jne r7, r1, e_invalid_quote_vault_pubkey
+ # INIT-VAULT(acct, frame)
+ mov64 r1, r9
+ mov64 r2, r10
+ call init_vault
exit
diff --git a/tests/tests/cases/register_market.rs b/tests/tests/cases/register_market.rs
index d74e2a5..c0ec192 100644
--- a/tests/tests/cases/register_market.rs
+++ b/tests/tests/cases/register_market.rs
@@ -77,6 +77,8 @@ test_cases! {
InvalidQuoteVaultPubkeyNonDupChunk3,
CreateAccountHappyPathQuoteDup,
CreateAccountHappyPathQuoteNonDup,
+ CreateAccountHappyPathToken2022QuoteDup,
+ CreateAccountHappyPathToken2022QuoteNonDup,
}
}
@@ -1028,6 +1030,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidBaseVaultPubkeyChunk0 => {
let (metas, accounts) = base_vault_mismatch_accounts(setup, CHUNK_0_OFF as usize);
check_custom(
@@ -1039,6 +1042,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidBaseVaultPubkeyChunk1 => {
let (metas, accounts) = base_vault_mismatch_accounts(setup, CHUNK_1_OFF as usize);
check_custom(
@@ -1050,6 +1054,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidBaseVaultPubkeyChunk2 => {
let (metas, accounts) = base_vault_mismatch_accounts(setup, CHUNK_2_OFF as usize);
check_custom(
@@ -1061,6 +1066,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidBaseVaultPubkeyChunk3 => {
let (metas, accounts) = base_vault_mismatch_accounts(setup, CHUNK_3_OFF as usize);
check_custom(
@@ -1072,6 +1078,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyDupChunk0 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_0_OFF as usize, true);
@@ -1084,6 +1091,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyDupChunk1 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_1_OFF as usize, true);
@@ -1096,6 +1104,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyDupChunk2 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_2_OFF as usize, true);
@@ -1108,6 +1117,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyDupChunk3 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_3_OFF as usize, true);
@@ -1120,6 +1130,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyNonDupChunk0 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_0_OFF as usize, false);
@@ -1132,6 +1143,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyNonDupChunk1 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_1_OFF as usize, false);
@@ -1144,6 +1156,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyNonDupChunk2 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_2_OFF as usize, false);
@@ -1156,6 +1169,7 @@ impl TestCase for Case {
)
}
// Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::InvalidQuoteVaultPubkeyNonDupChunk3 => {
let (metas, accounts) =
quote_vault_mismatch_accounts(setup, CHUNK_3_OFF as usize, false);
@@ -1167,7 +1181,8 @@ impl TestCase for Case {
Some(ErrorCode::InvalidQuoteVaultPubkey),
)
}
- // Verifies: REGISTER-MARKET (happy path, quote token program is duplicate)
+ // Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::CreateAccountHappyPathQuoteDup => {
let token_program_id = Pubkey::from(TOKEN_PROGRAM_ID);
let (metas, accounts) =
@@ -1217,7 +1232,8 @@ impl TestCase for Case {
},
}
}
- // Verifies: REGISTER-MARKET (happy path, quote token program is non-duplicate)
+ // Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
Self::CreateAccountHappyPathQuoteNonDup => {
let token_program_id = Pubkey::from(TOKEN_PROGRAM_ID);
let token_2022_id = Pubkey::from(TOKEN_2022_PROGRAM_ID);
@@ -1258,6 +1274,107 @@ impl TestCase for Case {
}
}
+ CaseResult {
+ cu: result.compute_units_consumed,
+ error: if errors.is_empty() {
+ None
+ } else {
+ Some(errors.join("; "))
+ },
+ }
+ }
+ // Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
+ Self::CreateAccountHappyPathToken2022QuoteDup => {
+ let token_2022_id = Pubkey::from(TOKEN_2022_PROGRAM_ID);
+ let (metas, accounts) = happy_path_accounts(setup, token_2022_id, token_2022_id);
+ let instruction = Instruction::new_with_bytes(setup.program_id, insn, metas);
+ let result = setup.mollusk.process_instruction(&instruction, &accounts);
+
+ let mut errors = Vec::new();
+ match &result.program_result {
+ MolluskResult::Success => {
+ let market =
+ &result.resulting_accounts[RegisterMarketAccounts::Market as usize].1;
+
+ if market.owner != setup.program_id {
+ errors.push(format!(
+ "owner: expected {:?}, got {:?}",
+ setup.program_id, market.owner
+ ));
+ }
+ if market.data.len() != MARKET_HEADER_SIZE {
+ errors.push(format!(
+ "data len: expected {}, got {}",
+ MARKET_HEADER_SIZE,
+ market.data.len()
+ ));
+ }
+ let rent = &setup.mollusk.sysvars.rent;
+ if !rent.is_exempt(market.lamports, market.data.len()) {
+ errors.push(format!(
+ "market not rent exempt: {} lamports for {} bytes",
+ market.lamports,
+ market.data.len()
+ ));
+ }
+ }
+ other => {
+ errors.push(format!("expected success, got {:?}", other));
+ }
+ }
+
+ CaseResult {
+ cu: result.compute_units_consumed,
+ error: if errors.is_empty() {
+ None
+ } else {
+ Some(errors.join("; "))
+ },
+ }
+ }
+ // Verifies: REGISTER-MARKET
+ // Verifies: INIT-VAULT
+ Self::CreateAccountHappyPathToken2022QuoteNonDup => {
+ let token_program_id = Pubkey::from(TOKEN_PROGRAM_ID);
+ let token_2022_id = Pubkey::from(TOKEN_2022_PROGRAM_ID);
+ let (metas, accounts) = happy_path_accounts(setup, token_2022_id, token_program_id);
+ let instruction = Instruction::new_with_bytes(setup.program_id, insn, metas);
+ let result = setup.mollusk.process_instruction(&instruction, &accounts);
+
+ let mut errors = Vec::new();
+ match &result.program_result {
+ MolluskResult::Success => {
+ let market =
+ &result.resulting_accounts[RegisterMarketAccounts::Market as usize].1;
+
+ if market.owner != setup.program_id {
+ errors.push(format!(
+ "owner: expected {:?}, got {:?}",
+ setup.program_id, market.owner
+ ));
+ }
+ if market.data.len() != MARKET_HEADER_SIZE {
+ errors.push(format!(
+ "data len: expected {}, got {}",
+ MARKET_HEADER_SIZE,
+ market.data.len()
+ ));
+ }
+ let rent = &setup.mollusk.sysvars.rent;
+ if !rent.is_exempt(market.lamports, market.data.len()) {
+ errors.push(format!(
+ "market not rent exempt: {} lamports for {} bytes",
+ market.lamports,
+ market.data.len()
+ ));
+ }
+ }
+ other => {
+ errors.push(format!("expected success, got {:?}", other));
+ }
+ }
+
CaseResult {
cu: result.compute_units_consumed,
error: if errors.is_empty() {