-
Notifications
You must be signed in to change notification settings - Fork 115
Open
Labels
standardsRelated to standard note scripts or account componentsRelated to standard note scripts or account components
Milestone
Description
Feature description
Pioneers are asking for us to add the SWAPP note script to the Miden-base repository.
This would mean:
- Cleaning up the code
- Updating the script to make it work with the new protocol rules (Error: MissalignedMemory)
- Optimizing the code
These would be the steps for this script to become a standard script like P2ID or SWAP.
This is the current code:
use.std::sys
use.std::math::u64
use.miden::note
use.miden::tx
use.miden::contracts::wallets::basic->wallet
# CONSTANTS
# =================================================================================================
const.PRIVATE_NOTE=2
const.PUBLIC_NOTE=1
# Memory Addresses
const.REQUESTED_ASSET_PTR=1
const.SCRIPT_HASH_PTR=3
const.OFFERED_ASSET_PTR=4
const.FILL_AMOUNT_PTR=5
# Memory Addresses for Price Calculation Procedure
const.AMT_TOKENS_A=64
const.AMT_TOKENS_B=65
const.AMT_TOKENS_B_IN=66
const.RATIO=67
const.FACTOR=0x000186A0 # 1e5
const.MAX_U32=0x0000000100000000
# ERRORS
# =================================================================================================
# SWAPP script expects exactly 10 note inputs
const.ERR_SWAP_WRONG_NUMBER_OF_INPUTS=0x00020055
# SWAPP script requires exactly 1 note asset
const.ERR_SWAP_WRONG_NUMBER_OF_ASSETS=0x00020056
# SWAPP script fill amount should be smaller than requested amount
const.ERR_SWAPP_FILL_AMOUNT_EXCEEDS_REQUESTED_AMOUNT=0x00020057
# SWAPP script fill amount should not be zero
const.ERR_SWAPP_FILL_AMOUNT_IS_ZERO=0x00020058
# HELPERS
# =================================================================================================
#! Returns the amount of tokens_a out given an amount of tokens_b
#!
#! Inputs: [tokens_a, tokens_b, tokens_b_in]
#! Outputs: [tokens_a_out]
#!
proc.calculate_partial_exchange
mem_store.AMT_TOKENS_A
mem_store.AMT_TOKENS_B
mem_store.AMT_TOKENS_B_IN
mem_load.AMT_TOKENS_B mem_load.AMT_TOKENS_A
gt
if.true
mem_load.AMT_TOKENS_B
u32split
push.FACTOR
u32split
exec.u64::wrapping_mul
mem_load.AMT_TOKENS_A
u32split
exec.u64::div
push.MAX_U32 mul add
mem_store.RATIO
mem_load.AMT_TOKENS_B_IN
u32split
push.FACTOR
u32split
exec.u64::wrapping_mul
mem_load.RATIO
u32split
exec.u64::div
push.MAX_U32 mul add
else
mem_load.AMT_TOKENS_A
u32split
push.FACTOR
u32split
exec.u64::wrapping_mul
mem_load.AMT_TOKENS_B
u32split
exec.u64::div
mem_load.AMT_TOKENS_B_IN
u32split
exec.u64::wrapping_mul
push.FACTOR
u32split
exec.u64::div
push.MAX_U32 mul add
end
end
#! Creates a new p2id note using inputs from memory
#!
#! Stack: [ASSET]
#! Output: []
proc.create_p2id_note
# load RECIPIENT
padw mem_loadw.0
# => [RECIPIENT, ASSET]
swapw
# => [ASSET, RECIPIENT]
padw mem_loadw.2 drop drop push.0 push.0
# => [0, 0, execution_hint, tag, ASSET, RECIPIENT]
drop drop swap
# => [tag, execution_hint, ASSET, RECIPIENT]
# we add aux = 0 to the note assuming we don't need it for the second leg of the SWAP
push.0 swap
# => [tag, aux, execution_hint, ASSET, RECIPIENT]
push.PRIVATE_NOTE movdn.2
# => [tag, aux, note_type, execution_hint, ASSET, RECIPIENT]
swapw
# => [ASSET, tag, aux, note_type, execution_hint, RECIPIENT]
# create a note using inputs
padw swapdw padw movdnw.2
# => [tag, aux, note_type, execution_hint, RECIPIENT, PAD(8), ASSET]
call.wallet::create_note
# => [note_idx, PAD(15), ASSET]
swapw dropw movupw.3
# => [ASSET, note_idx, PAD(11)]
# move asset to the note
call.wallet::move_asset_to_note
# => [ASSET, note_idx, PAD(11)]
# clean stack
dropw dropw dropw dropw
# => []
end
#! Creates a new swapp note using inputs from memory
#!
#! Stack: []
#! Output: []
proc.create_swapp_note
# load payback recipient
padw mem_loadw.0
# => [PAYBACK_RECIPIENT]
# load remaining requested asset amount
padw mem_loadw.REQUESTED_ASSET_PTR mem_load.FILL_AMOUNT_PTR dup.4 swap sub swap.4 drop
# => [REQUESTED_ASSET_REMAINING, PAYBACK_RECIPIENT]
# load tag and hint
padw mem_loadw.2
# => [0, swapp_tag, execution_hint, payback_tag, REQUESTED_ASSET_REMAINING, PAYBACK_RECIPIENT]
# load script hash
padw mem_loadw.SCRIPT_HASH_PTR
# => [SCRIPT_HASH, 0, swapp_tag, execution_hint, payback_tag, REQUESTED_ASSET_REMAINING, PAYBACK_RECIPIENT]
# compute inputs hash
mem_storew.83 dropw
mem_storew.82 dropw
mem_storew.81 dropw
mem_storew.80 dropw
push.16.80
# => [inputs_ptr, num_inputs]
exec.note::compute_inputs_hash
# => [INPUTS_HASH]
# compute swapp recipient
padw mem_loadw.SCRIPT_HASH_PTR
push.1.2.3.4 # SERIAL_NUM
# => [SERIAL_NUM, SCRIPT_HASH, INPUT_HASH]
exec.tx::build_recipient_hash
# => [SWAPP_RECIPIENT]
# build swapp note inputs
padw mem_loadw.2 drop movup.2 drop push.0 swap push.PUBLIC_NOTE movdn.2
padw mem_loadw.OFFERED_ASSET_PTR
# => [ASSET, tag, aux, note_type, execution_hint, SWAPP_RECIPIENT]
# create note using inputs
padw swapdw padw movdnw.2
# => [tag, aux, note_type, execution_hint, RECIPIENT, PAD(8), ASSET]
call.wallet::create_note
# => [note_idx, PAD(15), ASSET]
swapw dropw movupw.3
# => [ASSET, note_idx, PAD(11)]
# move asset to the note
call.wallet::move_asset_to_note
# => [ASSET, note_idx, PAD(11)]
# clean stack
dropw dropw dropw dropw
# => []
end
#! Executes a partial swap
#!
#! Stack: []
#! Output: []
proc.partial_swap
# update the requested asset with the fill amount for note creation
padw mem_loadw.REQUESTED_ASSET_PTR mem_load.FILL_AMOUNT_PTR swap.4 drop
# => [REQUESTED_ASSET_FILL]
# create p2id note (payback note)
exec.create_p2id_note
# => []
# get inputs for partial exchange
mem_load.FILL_AMOUNT_PTR
padw mem_loadw.REQUESTED_ASSET_PTR drop drop drop
padw mem_loadw.OFFERED_ASSET_PTR drop drop drop
# => [offered_amount, requested_amount, fill_amount]
# calculate partial exchange
exec.calculate_partial_exchange
# => [final_offered_amount]
# get asset for consumer account
padw mem_loadw.OFFERED_ASSET_PTR
# => [OFFERED_ASSET, final_offered_amount]
# update offered asset (remaining)
dupw dup.8 movup.4 swap sub movdn.3 mem_storew.OFFERED_ASSET_PTR dropw
# => [OFFERED_ASSET, final_offered_amount]
# add assets to consumer account
movup.4 drop call.wallet::receive_asset dropw
# => []
# create swapp note
exec.create_swapp_note
# => []
end
#! Executes a full swap
#!
#! Stack: []
#! Output: []
proc.full_swap
# load the offered asset and add it to the account
mem_loadw.OFFERED_ASSET_PTR call.wallet::receive_asset dropw
# => []
# load requested asset for p2id
mem_loadw.REQUESTED_ASSET_PTR
# => [REQUESTED_ASSET]
# create p2id note
exec.create_p2id_note
# => []
end
begin
# drop the script hash
# dropw
# => [NOTE_ARGS]
# populate memory with note inputs
push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr]
# make sure the number of inputs is 16
eq.16 assert.err=ERR_SWAP_WRONG_NUMBER_OF_INPUTS drop
# => []
# store OFFERED_ASSET into memory
push.OFFERED_ASSET_PTR exec.note::get_assets assert.err=ERR_SWAP_WRONG_NUMBER_OF_ASSETS drop
# => []
# get fill amount from note args
drop drop drop
# => [fill_amount]
# store fill amount in memory
dup mem_store.FILL_AMOUNT_PTR
# => [fill_amount]
# get fill amount and requested amount
padw mem_loadw.REQUESTED_ASSET_PTR drop drop drop
# => [requested_amount, fill_amount]
# throw an error if fill amount is greater than requested amount
dup.1 dup.1 lte assert.err=ERR_SWAPP_FILL_AMOUNT_EXCEEDS_REQUESTED_AMOUNT
# => [requested_amount, fill_amount]
# throw an error if fill amount is zero
dup.1 neq.0 assert.err=ERR_SWAPP_FILL_AMOUNT_IS_ZERO
# => [requested_amount, fill_amount]
# check if fill amount is equal to requested amount
eq
# => [fill_requested_eq]
if.true
# perform a full swap
exec.full_swap
else
# perform a partial swap
exec.partial_swap
end
# clean stack
exec.sys::truncate_stack
# => []
end
Why is this feature needed?
This would be needed to simplify the integration of SWAPP in the codebase of different Pioneers as partial swaps are a norm in DeFi.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
standardsRelated to standard note scripts or account componentsRelated to standard note scripts or account components