|
|
@@ -0,0 +1,324 @@
|
|
|
+
|
|
|
+.equ NUM_ACCOUNTS, 0x0000
|
|
|
+
|
|
|
+.equ OWNER_HEADER, 0x0008
|
|
|
+.equ OWNER_KEY, 0x0010
|
|
|
+.equ OWNER_OWNER, 0x0030
|
|
|
+.equ OWNER_LAMPORTS, 0x0050
|
|
|
+.equ OWNER_DATA_LEN, 0x0058
|
|
|
+.equ OWNER_DATA, 0x0060
|
|
|
+.equ OWNER_RENT_EPOCH, 0x2860
|
|
|
+
|
|
|
+.equ COUNTER_HEADER, 0x2868
|
|
|
+.equ COUNTER_KEY, 0x2870
|
|
|
+.equ COUNTER_OWNER, 0x2890
|
|
|
+.equ COUNTER_LAMPORTS, 0x28b0
|
|
|
+.equ COUNTER_DATA_LEN, 0x28b8
|
|
|
+.equ COUNTER_DATA, 0x28c0
|
|
|
+.equ COUNTER_RENT_EPOCH, 0x50c0
|
|
|
+
|
|
|
+.equ SYSTEM_PROGRAM_HEADER, 0x50c8
|
|
|
+.equ SYSTEM_PROGRAM_KEY, 0x50d0
|
|
|
+.equ SYSTEM_PROGRAM_OWNER, 0x50f0
|
|
|
+.equ SYSTEM_PROGRAM_LAMPORTS, 0x5110
|
|
|
+.equ SYSTEM_PROGRAM_DATA_LEN, 0x5118
|
|
|
+.equ SYSTEM_PROGRAM_DATA, 0x5120
|
|
|
+.equ SYSTEM_PROGRAM_RENT_EPOCH, 0x7930
|
|
|
+
|
|
|
+.equ INSTRUCTION_DATA_LEN, 0x7938
|
|
|
+.equ INSTRUCTION_DATA, 0x7940
|
|
|
+.equ PROGRAM_ID, 0x7942
|
|
|
+
|
|
|
+.equ COUNTER_SEED, 0x7265746e756f63
|
|
|
+.equ COUNTER_DATA_SIZE, 0x9 # 9 (u8 bump + u64 counter)
|
|
|
+
|
|
|
+.equ ACCOUNT_STORAGE_OVERHEAD, 0x80 # 128
|
|
|
+
|
|
|
+
|
|
|
+# NOTE: We are using a DEFAULT_RENT_EXEMPTION_THRESHOLD value of 2 to avoid floating-point math.
|
|
|
+# Check here for more details: https://github.com/solana-foundation/solana-improvement-documents/pull/194
|
|
|
+.equ DEFAULT_RENT_EXEMPTION_THRESHOLD, 0x2
|
|
|
+
|
|
|
+
|
|
|
+.globl entrypoint
|
|
|
+
|
|
|
+
|
|
|
+entrypoint:
|
|
|
+ ldxdw r3, [r1 + COUNTER_DATA_LEN]
|
|
|
+ mov64 r6, r1
|
|
|
+ jeq r3, 0, check_instruction
|
|
|
+ add64 r6, 16 # COUNTER_DATA_SIZE + round up to 8
|
|
|
+
|
|
|
+check_instruction:
|
|
|
+ ldxdw r4, [r6 + INSTRUCTION_DATA_LEN]
|
|
|
+ jne r4, 2, error_invalid_instruction
|
|
|
+
|
|
|
+ ##########################
|
|
|
+ ## Prepare seeds ##
|
|
|
+ ##########################
|
|
|
+
|
|
|
+ mov64 r9, r10
|
|
|
+ sub64 r9, 8
|
|
|
+ lddw r2, COUNTER_SEED
|
|
|
+ stxdw [r9 + 0], r2
|
|
|
+
|
|
|
+ mov64 r8, r9
|
|
|
+ sub64 r8, 8
|
|
|
+ ldxb r2, [r6 + INSTRUCTION_DATA + 1]
|
|
|
+ stxdw [r8 + 0], r2
|
|
|
+
|
|
|
+ mov64 r5, r8
|
|
|
+ sub64 r5, 48
|
|
|
+
|
|
|
+ # First seed ("counter")
|
|
|
+ mov64 r2, r5
|
|
|
+ stxdw [r2 + 0], r9
|
|
|
+ lddw r3, 7
|
|
|
+ stxdw [r2 + 8], r3
|
|
|
+
|
|
|
+ # Second seed (owner key)
|
|
|
+ add64 r2, 16
|
|
|
+ mov64 r4, r1
|
|
|
+ add64 r4, OWNER_KEY
|
|
|
+ stxdw [r2 + 0], r4
|
|
|
+ lddw r3, 32
|
|
|
+ stxdw [r2 + 8], r3
|
|
|
+
|
|
|
+ # bump
|
|
|
+ add64 r2, 16
|
|
|
+ stxdw [r2 + 0], r8
|
|
|
+ lddw r3, 1
|
|
|
+ stxdw [r2 + 8], r3
|
|
|
+
|
|
|
+ ##########################
|
|
|
+ ## Validate PDA ##
|
|
|
+ ##########################
|
|
|
+
|
|
|
+ mov64 r7, r1
|
|
|
+ mov64 r1, r5
|
|
|
+ lddw r2, 3
|
|
|
+ mov64 r3, r6
|
|
|
+ add64 r3, PROGRAM_ID
|
|
|
+ mov64 r4, r5
|
|
|
+ sub64 r4, 32
|
|
|
+ call sol_create_program_address
|
|
|
+
|
|
|
+ mov64 r1, r4
|
|
|
+ mov64 r2, r7
|
|
|
+ add64 r2, COUNTER_KEY
|
|
|
+ lddw r3, 32
|
|
|
+ mov64 r4, r5
|
|
|
+ sub64 r4, 4
|
|
|
+ call sol_memcmp_
|
|
|
+
|
|
|
+ ldxw r1, [r4 + 0]
|
|
|
+ jne r1, 0x0, error_invalid_pda
|
|
|
+
|
|
|
+ # Branch based on instruction type.
|
|
|
+ mov64 r1, r7
|
|
|
+ ldxb r4, [r6 + INSTRUCTION_DATA + 0]
|
|
|
+ jeq r4, 0x0, initialize
|
|
|
+ jeq r4, 0x1, increment
|
|
|
+ ja error_invalid_instruction
|
|
|
+
|
|
|
+
|
|
|
+initialize:
|
|
|
+
|
|
|
+ ##########################
|
|
|
+ ## Set up account metas ##
|
|
|
+ ##########################
|
|
|
+
|
|
|
+ mov64 r9, r5
|
|
|
+ sub64 r9, 32
|
|
|
+
|
|
|
+ # Owner
|
|
|
+ mov64 r2, r9
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, OWNER_KEY
|
|
|
+ stxdw [r2 + 0], r3 # pubkey
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 2]
|
|
|
+ stxb [r2 + 8], r3 # is_writable
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 1]
|
|
|
+ stxb [r2 + 9], r3 # is_signer
|
|
|
+
|
|
|
+ # Counter
|
|
|
+ add64 r2, 16
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, COUNTER_KEY
|
|
|
+ stxdw [r2 + 0], r3 # pubkey
|
|
|
+ ldxb r3, [r1 + COUNTER_HEADER + 2]
|
|
|
+ stxb [r2 + 8], r3 # is_writable
|
|
|
+ lddw r3, 1
|
|
|
+ stxb [r2 + 9], r3 # is_signer
|
|
|
+
|
|
|
+ #############################
|
|
|
+ ## Set up instruction data ##
|
|
|
+ #############################
|
|
|
+
|
|
|
+ mov64 r7, r1
|
|
|
+ mov64 r6, r9
|
|
|
+ sub64 r6, 48
|
|
|
+
|
|
|
+ # Find the minimum balance for rent exemption
|
|
|
+ mov64 r1, r6
|
|
|
+ call sol_get_rent_sysvar
|
|
|
+ ldxdw r3, [r1 + 0] # lamports_per_byte_year
|
|
|
+ lddw r4, ACCOUNT_STORAGE_OVERHEAD
|
|
|
+ add64 r4, COUNTER_DATA_SIZE
|
|
|
+ mul64 r4, r3
|
|
|
+ mul64 r4, DEFAULT_RENT_EXEMPTION_THRESHOLD
|
|
|
+
|
|
|
+ mov64 r8, r6
|
|
|
+ sub64 r8, 56
|
|
|
+
|
|
|
+ # Build instruction to create an account
|
|
|
+ mov64 r2, r8
|
|
|
+ lddw r3, 0 # Instruction discriminator (0 = CreateAccount)
|
|
|
+ stxw [r2 + 0], r3
|
|
|
+ stxdw [r2 + 4], r4 # Lamports for rent exemption
|
|
|
+ lddw r3, COUNTER_DATA_SIZE
|
|
|
+ stxdw [r2 + 12], r3 # Account space
|
|
|
+
|
|
|
+ mov64 r1, r2 # Owner (32 byte program ID)
|
|
|
+ add64 r1, 20
|
|
|
+ mov64 r2, r7
|
|
|
+ add64 r2, PROGRAM_ID
|
|
|
+ lddw r3, 32
|
|
|
+ call sol_memcpy_
|
|
|
+
|
|
|
+
|
|
|
+ ############################
|
|
|
+ ## Set up the instruction ##
|
|
|
+ ############################
|
|
|
+
|
|
|
+ mov64 r1, r7
|
|
|
+ mov64 r7, r8
|
|
|
+ sub64 r7, 40
|
|
|
+
|
|
|
+ mov64 r2, r7
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, SYSTEM_PROGRAM_KEY
|
|
|
+ stxdw [r2 + 0], r3 # program_id
|
|
|
+ mov64 r3, r9
|
|
|
+ stxdw [r2 + 8], r3 # accounts
|
|
|
+ lddw r3, 2
|
|
|
+ stxdw [r2 + 16], r3 # account_len
|
|
|
+ mov64 r3, r8
|
|
|
+ stxdw [r2 + 24], r3 # data
|
|
|
+ lddw r3, 52
|
|
|
+ stxdw [r2 + 32], r3 # data_len
|
|
|
+
|
|
|
+ ##########################
|
|
|
+ ## Set up account infos ##
|
|
|
+ ##########################
|
|
|
+
|
|
|
+ mov64 r6, r7
|
|
|
+ sub64 r6, 112
|
|
|
+
|
|
|
+ # Owner
|
|
|
+ mov64 r2, r6
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, OWNER_KEY
|
|
|
+ stxdw [r2 + 0], r3 # key
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, OWNER_LAMPORTS
|
|
|
+ stxdw [r2 + 8], r3 # lamports
|
|
|
+ ldxdw r3, [r1 + OWNER_DATA_LEN]
|
|
|
+ stxdw [r2 + 16], r3 # data_len
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, OWNER_DATA
|
|
|
+ stxdw [r2 + 24], r3 # data
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, OWNER_OWNER
|
|
|
+ stxdw [r2 + 32], r3 # owner
|
|
|
+ ldxdw r3, [r1 + OWNER_RENT_EPOCH]
|
|
|
+ stxdw [r2 + 40], r3 # rent_epoch
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 1]
|
|
|
+ stxb [r2 + 48], r3 # is_signer
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 2]
|
|
|
+ stxb [r2 + 49], r3 # is_writable
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 3]
|
|
|
+ stxb [r2 + 50], r3 # is_executable
|
|
|
+
|
|
|
+ # Counter
|
|
|
+ add64 r2, 56
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, COUNTER_KEY
|
|
|
+ stxdw [r2 + 0], r3
|
|
|
+ mov64 r3, r1 # key
|
|
|
+ add64 r3, COUNTER_LAMPORTS
|
|
|
+ stxdw [r2 + 8], r3 # lamports
|
|
|
+ ldxdw r3, [r1 + COUNTER_DATA_LEN]
|
|
|
+ stxdw [r2 + 16], r3 # data_len
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, COUNTER_DATA
|
|
|
+ stxdw [r2 + 24], r3 # data
|
|
|
+ mov64 r3, r1
|
|
|
+ add64 r3, COUNTER_OWNER
|
|
|
+ stxdw [r2 + 32], r3 # owner
|
|
|
+ ldxdw r3, [r1 + COUNTER_RENT_EPOCH]
|
|
|
+ stxdw [r2 + 40], r3 # rent_epoch
|
|
|
+ ldxb r3, [r1 + COUNTER_HEADER + 1]
|
|
|
+ stxb [r2 + 48], r3 # is_signer
|
|
|
+ ldxb r3, [r1 + COUNTER_HEADER + 2]
|
|
|
+ stxb [r2 + 49], r3 # is_writable
|
|
|
+ ldxb r3, [r1 + COUNTER_HEADER + 3]
|
|
|
+ stxb [r2 + 50], r3 # is_executable
|
|
|
+
|
|
|
+ ##########################
|
|
|
+ ## Set up signer seeds ##
|
|
|
+ ##########################
|
|
|
+
|
|
|
+ mov64 r9, r6
|
|
|
+ sub64 r9, 16
|
|
|
+
|
|
|
+ mov64 r2, r9
|
|
|
+ stxdw [r2 + 0], r5
|
|
|
+ lddw r3, 3
|
|
|
+ stxdw [r2 + 8], r3
|
|
|
+
|
|
|
+
|
|
|
+ ####################
|
|
|
+ ## Invoke the CPI ##
|
|
|
+ ####################
|
|
|
+
|
|
|
+ mov64 r8, r1
|
|
|
+ mov64 r1, r7 # Instruction
|
|
|
+ mov64 r2, r6 # Account infos
|
|
|
+ lddw r3, 2 # Number of account infos
|
|
|
+ mov64 r4, r9 # Seeds
|
|
|
+ lddw r5, 1 # Seeds count
|
|
|
+ call sol_invoke_signed_c
|
|
|
+
|
|
|
+ # Write data to the newly created account
|
|
|
+ ldxb r2, [r8 + INSTRUCTION_DATA + 1]
|
|
|
+ stxb [r8 + COUNTER_DATA], r2 # Bump
|
|
|
+ lddw r2, 0
|
|
|
+ stxdw [r8 + COUNTER_DATA + 1], r2 # Initial counter value (0)
|
|
|
+
|
|
|
+ exit
|
|
|
+
|
|
|
+increment:
|
|
|
+
|
|
|
+ # Check if owner is the signer
|
|
|
+ ldxb r3, [r1 + OWNER_HEADER + 1]
|
|
|
+ jeq r3, 0, error_invalid_signature
|
|
|
+
|
|
|
+ # Increment count by 1
|
|
|
+ ldxdw r2, [r1 + COUNTER_DATA + 1]
|
|
|
+ add64 r2, 1
|
|
|
+ stxdw [r1 + COUNTER_DATA + 1], r2
|
|
|
+
|
|
|
+ exit
|
|
|
+
|
|
|
+error_invalid_instruction:
|
|
|
+ lddw r0, 0xa
|
|
|
+ exit
|
|
|
+
|
|
|
+error_invalid_pda:
|
|
|
+ lddw r0, 0xb
|
|
|
+ exit
|
|
|
+
|
|
|
+error_invalid_signature:
|
|
|
+ lddw r0, 0xc
|
|
|
+ exit
|