GrowFi - UDT Swap

Team Background

The GrowFi team is currently developing a DeFi infrastructure, including the fundraising model Growdrop, interest derivatives and DeFi aggregate. Growdrop has already released an Open Beta version(Ethereum). Our goal is to enable DeFi to expand financial inclusion, which has not been possible with centralized financing.

The GrowFi team has been running the Nervos Korean community for the past year, and we have written development research and content on various Nervos and made it known to Korea. Philosophy like Nervos PoW, layer architecture has inspired us a lot and we want to make this philosophy public. So in order to contribute to Nervos decentralized ecosystem, we want to create a financing that anyone can participate in DeFi infrastructure on top of Nervos. Our development proposal is as follows.

Github:https://github.com/bannplayer/Growdrop/tree/master
Github:https://github.com/bannplayer/Nervos

Medium:https://medium.com/growfi

Twitter:https://twitter.com/Grow_drop

Growdrop app: http://dev.growdrop.io/

Mike MU : Blockchain researcher(Create a Blockchain research report 30+ ) , DeFi Korea Co-Organizer, GrowFi Co-Founder, Korea Government Support Blockchain Education Instructor

David Park : ex-Bithumb coin(20+) wallet, sign server development & node operation guide. Samsung Galaxy S S-memo Development.

Jay Lee : ex-Bithumb coin(20+) wallet, sign server development & node operation guide. LG Mobile Developer ex-Bithumb coin.

Brian Noh : Defi Proeject full-stack Developer. (https://github.com/bannplayer/Growdrop/tree/master ). Korea Government Support Blockchain Education Instructor.

Adonis Seo : exchange service Front-end & Back-end development Bithumb Cryptocurreny Deposit/Withdraw development .

Ian Son : Bithumb new exchange system development, Coin/Token Management/Listing system development.

Kidori Park : exchange web solution developer. Korea Government Support Blockchain Education Instructor.

Gami Wang : ​Exchange​ ​Product manager

Project and Nervos Ecosystem Growth

UDT swap
we will be able to trade tokens for Nervos scalability to make it easier for investors and users to enter. This requires a trading site that is easy to list and exchange. This enables users to experience various Nervos environments.​ As the Nervos ecosystem expands in the future, Layer 2 and Dapp will offer tokens a liquidity pool of UDT swap (x * y = k models) to create new business models through fees. The price of the token is also determined by the size of the liquidity pool.

We also focus on the token interface (UDT) of the Nervos network, and we know that the Nervos community is already actively discussing UDT. We will modify this proposal and continue working.

Technical Specification and Implementation
image

We will create an UDTswap lock script and an UDTswap type script, and the UDTswap lock script checks only if there is an UDTswap type script within that transaction.

The UDTswap type script will check for other content.
There are five kinds of transactions.

Create UDTswap
Create a cell to store the liquidity pool related data between UDT and ckb.

Add liquidity pool
Add a liquidity pool to provide users with the ckb or UDT needed for swap.

Liquidity pool providers are provided by quantifying the ratio of liquidity pools to the ckb ratio of liquidity pools.

Liquidity pool removal
Depending on the percentage of the liquidity pool provided to the user, it can be removed from the liquidity pool again to get back ckb and UDTs based on the removed ratio of the liquidity pool.

Swap ckb to UDT (swap UDT to ckb)
Depending on the ratio of ckb to UDT or UDT to ckb provided to the liquid pool, you can either provide ckb and receive a UDT, or provide a UDT to receive a ckb.

The shared state of the figure indicates that the latest liquidity pool related information cell by all users should be used as input.

Also, if the liquidity pool is empty, ckb will have 200ckb, and the remaining ckb is the liquidity pool balance.

Similarly, if the liquidity pool is empty, the UDT will have 1 and all other UDTs are liquidity pool balances.

There is an undefined fee for every transaction, which is a fixed fee to prevent the occupancy of the shared state.

The fee for swap is 0.3%, which is left in the liquidity pool so that liquidity pool providers can earn it on a percentage basis.

Create UDTswap
There is one input and three outputs.

The input is shown below.

Ckb for cell creation.

The output is shown below.

Cell that stores ckb amount of liquidity pool provided as capacity and locks up, stores information about liquidity pool.

Cell where the UDT is actually locked and stored.

Cell to get the remaining change after cell creation.

When you create an UDTswap type script, you create a unique type script using the first input of the transaction as args.

After that, all transactions containing UDTswap type script should check below.

whether the UDTswap lock script is used,

type script is used,

the args of the type script match,

The number of input and output cells in the transaction is
correct

Etc., and further checks according to the other situation

Add liquidity pool
There are five inputs and five outputs.

The inputs are as follows:
Cell that stores liquidity pool information
Cell locking up UDT by liquidity pool information
Cell providing ckb liquidity pool
Cell provides UDT liquidity pool
Cell with the ckb needed to create the cell

The outputs are as follows:
Cell with updated liquidity pool information
Cell to lock up the UDT by updated liquidity pool information
Cell to store liquidity pool ratio information of user
Cell to return the remaining ckb after cell creation
Fixed fee cell to prevent occupancy of shared state

For cell that store liquidity pool information and cell that lock up UDTs as much as liquid pool information, the latest updated output should be used as input each time the user uses.

If you add a liquidity pool through ckb and UDT, you must add it according to the ratio of ckb and UDT of liquidity pool.

After the addition, the user’s liquidity pool percentage information is based on ckb’s previous liquidity pool information and the percentage of ckb users added.

‘ckb reserve’ refers to the amount of ckb that exists in the liquidity pool.

‘UDT reserve’ refers to the amount of UDTs that exist in the liquidity pool.

‘total liquidity’ means quantifying the total proportion of the liquidity pool.

For a UDT you should add :
UDT reserve * ckb amount to add liquidity / ckb reserve + 1

The liquidity pool ratio information for a user is as follows :
total liquidity * ckb amount to add liquidity / ckb reserve

At this time, if the liquidity pool is empty, the first time you add a liquidity pool, you can add as many ckb and UDTs as you want, and this ratio will be used to calculate when you add the liquidity pool later.

In addition, upon initial addition of the liquidity pool, the total liquidity is equal to the ckb amount.

Liquidity pool removal
There are four inputs and six outputs.

The inputs are as follows:
Cell that stores liquidity pool information
Cell locking up UDT by liquidity pool information
Cell storing user’s liquidity pool information
Cell with the ckb needed to create the cell

The outputs are as follows:
Cell with updated liquidity pool information.
Cell to lock up the UDT by updated liquidity pool information.
Cell to get back ckb according to the percentage of liquidity pool removed.
Cell to get back the UDT based on the percentage of liquidity pool removed.
Cell to return the remaining ckb after cell creation.
Fixed fee cell to prevent occupancy of shared state.

For the cell that stores liquid pool information and cell that locks up UDTs as much as liquid pool information, the latest updated output should be used as input each time the user uses.

If you remove the liquidity pool, you will get back the ckb and UDT based on the ratio of the liquidity pool.

For the returned UDT :
removing liquidity * UDT reserve / total liquidity

For the returned ckb :
removing liquidity * ckb reserve / total liquidity

Swap ckb to UDT (similar to swapping UDT to ckb)
There are four inputs and five outputs.

The inputs are as follows:
Cell that stores liquidity pool information
Cell locking up UDT by liquidity pool information
Cell containing ckb provided for swap
Cell with the ckb needed to create the cell

The outputs are as follows:
Cell with updated liquidity pool information
Cell to lock up the UDT by updated liquidity pool information
Cell containing UDT to receive as a result of swap
Cell to return the remaining ckb after cell creation
Fixed fee cell to prevent occupancy of shared state

For cell that stores liquidity pool information and cell that locks up UDTs as much as liquid pool information, the latest updated output should be used as input each time the user uses.

In the above case, ckb is exchanged for UDT. When ckb and UDT are reversed, same calculation will be used.

‘input amount’ means the ckb or UDT amount you want to provide.

The ‘output amount’ is the ckb or UDT amount that you will receive.

‘input reserve’ refers to the amount of liquidity pool provided by the user, such as ckb or UDT.

‘output reserve’ refers to the amount of liquidity pool that you receive, such as ckb or UDT.

The formula is shown below.

Determine input amount based on output amount :
input amount = input reserve * output amount * 1000 / (output reserve-output amount) * 997 + 1

Determine output amount based on input amount :
output amount = input amount * 997 * output reserve / (input reserve * 1000 + input amount * 997)

If any of the above two formulas are correct during transaction verification, they will be treated correctly. If both formulas do not match, the verification will fail.

front-running
If a malicious person first checks a transaction and assumes that the transaction is processed before it is processed, then the user’s transaction will not be processed because it did not use the latest updated output. This prevents front-running.

future work
We may make user’s liquidity as UDT and transmit it. UDT to UDT swap is already available through two transactions, but we may make it possible to use one transaction.

Road map:
We propose a 4 month timeline, with 3 checkpoints.

Checkpoint 1(1 Month):
● UDTSwap code MVP model release

Checkpoint 2(2 Month):
● UX/UI
● Test swap
● Bug Improvements
● Guide Documents

Checkpoint 3 (1 Month):
● Full version UDT Swap
● UDTswap price history API
● UDTswap info

4 Likes

This grant has been approved! Announcement and details here.

UPDATE: Checkpoint 1 Update

First let’s recall the goals of Checkpoint 1:

Checkpoint 1(1 Month):
● UDTSwap code MVP model release

At this checkpoint, we released the MVP model of UDTswap scripts. It also supports 4 features: Create UDTswap, Add liquidity pool, Liquidity pool removal, Swap CKB to UDT / Swap UDT to UDT / Swap UDT to CKB.

UDTswap_udt_based.c

UDTswap type script:

UDTswap_lock_udt_based.c

UDTswap lock script:

UDTswap_liquidity_UDT_udt_based.c

UDTswap liquidity udt type script:

UDTswap_common.h

UDTswap constants header:

UDTswap feature

  • Supports CKB and UDT based pools
  • Supports multiple pools for same CKB and UDT pairs
  • Supports multiple swaps for different pools

UDTswap supports not only CKB but also UDT for basic assets to expand the Nervos and UDT ecosystem in the future. Also, the liquidity pool of most existing swap models only supports a single pool, but UDTswap supports multiple pools. As a result, UDTswap offers more economic opportunities for liquidity providers (LP).

For more information on the MVP code, please refer to our GitHub.
Github:https://github.com/bannplayer/UDTswap

3 Likes

What’s the purpose of using bignum here? UDT standard specifies UDT amount of Uint128. I can see the value due to safe arithmetic, but safe arithmetic can be achieved with a lot less bloat than including entire big num library

Because of calculation. If UDT max amount should be calculated, we should multiply in some case so we just added bignum. And we searched for light library. Thank you for your suggestion.

Technical Specification and Implementation Update

UDTswap cell structure

The indicated cells in the figure above should have the same index as the figure. However, in the case of multiple swaps, the index of the fee cell may change.

The first UDT or the second UDT can be CKB and the method is the same.

The output cells, which will serve as the change for all transactions, can be located at any position as long as the above picture and the following conditions are satisfied.

If two UDTs are specified, there is only one pair. The order is divided from smallest to largest UDT type script hash.

There are 4 types of transactions.

  • Create UDTswap

Create cells to store the liquidity pool related data.

  • Add liquidity pool

By adding a liquidity pool, the user provides the first UDT and the second UDT pair.

Liquidity pool providers are provided with a numerical ratio of the liquidity pool according to the first UDT ratio of the liquidity pool.

  • Liquidity Pool Removal

Depending on the ratio of the digitized liquidity pool provided to the user, it can be removed from the liquidity pool again and the first UDT and the second UDT can be returned according to the removed ratio of the liquidity pool.

  • Swap UDT to UDT

Depending on the ratio of the first UDT to the second UDT provided in the liquidity pool, you can either provide the first UDT and receive the second UDT, or provide the second UDT to receive the first UDT.

The part represented by the shared state in the figure means that the latest updated output should be used as input as information related to the liquidity pool shared by all users.

Also, if the liquidity pool is empty, there will be 300 CKB for CKB, and the remaining CKB is the liquidity pool balance.

Likewise, if the liquidity pool is empty, the UDT will have 1, and the rest of the UDTs will be the liquidity pool balance.

There is a 61 CKB fee for all transactions except creation, which is a fixed fee to prevent occupancy of the shared state.

When swapping, the fee is 0.3%, which is left in the liquidity pool and can be earned by liquidity pool providers at a rate.

Create UDTswap

There are at least 1 input and 3 outputs.

The input is as follows.

  • CKB for cell generation

The output is shown below.

  • Cell to store the numerical value of the ratio of the first UDT liquidity pool provision amount to the second UDT liquidity pool provision amount in data
  • Cell where the first UDT will be locked up and stored
  • Cell where the second UDT is locked up and stored

When creating UDTswap type script, the first input of the transaction is identified as a unique pool using args.

The UDT of an empty pool is 1, or 300CKB for CKB.

The CKB and UDT input cells for pool creation can be located anywhere if the above picture is satisfied.

Add liquidity pool

There are at least 3 inputs and 5 outputs.

The inputs are:

  • Cell that stores liquidity pool information
  • Cell locking the first UDT as much as the liquidity pool information
  • Cell locking up the second UDT as much as the liquidity pool information

The outputs are:

  • Cell with updated liquidity pool information
  • Cell to lock up the first UDT as much as the updated liquidity pool information
  • Cell to lock up the second UDT as much as the updated liquidity pool information
  • Fixed fee cell to prevent occupancy of shared state
  • Cell to store user’s liquidity ratio information

When adding liquidity, you must add it according to the ratio of the first UDT and the second UDT of the liquidity pool.

UDT input cells required to add liquidity can be located anywhere if the above picture is satisfied.

There is no need to have one cell to store the user’s liquidity ratio information after adding liquidity, and it does not matter if there is at least one cell in the fifth output.

The first UDT reserve means the first UDT amount in the liquidity pool.

The second UDT reserve means the second UDT amount in the liquidity pool.

Total liquidity means the total ratio of the liquidity pool.

For the second UDT to be added,

  • Second UDT reserve * First UDT amount to add liquidity / First UDT reserve + 1

The user’s liquidity ratio information is as follows.

  • total liquidity * first UDT amount to add liquidity / first UDT reserve

When the liquidity pool is empty, if you add liquidity for the first time, you can enter as many of the first UDT and the second UDT as the basis, and it is calculated based on the ratio when you add liquidity later. In addition, when liquidity is first added, total liquidity is equal to the first UDT amount.

Liquidity Pool Removal


There are at least 4 inputs and 4 outputs.

The inputs are:

  • Cell that stores liquidity pool information
  • Cell that locks up the first UDT as much as the liquidity pool information
  • Cell locking the second UDT as much as the liquidity pool information
  • Cell that stores user’s liquidity information

The outputs are:

  • Cell with updated liquidity pool information
  • Cell to lock up the first UDT as much as the updated liquidity pool information
  • Cell to lock up the second UDT as much as the updated liquidity pool information
  • Fixed fee cell to prevent occupancy of shared state

When liquidity is removed, it will be returned according to the ratio of the first UDT and the second UDT of the liquidity pool.

It does not need to be one cell that stores the user’s liquidity information, and it does not matter if there is at least one cell in the fourth input.

UDT output cells to be returned after removing liquidity can be located at any position if the above conditions are satisfied.

For the returned UDT, it is as follows, and both the first and second UDTs are the same.

  • removing liquidity * UDT reserve / total liquidity

Swap UDT to UDT

There are at least 3 inputs and 4 outputs.

The inputs are:

  • Cell that stores liquidity pool information
  • Cell that locks up the first UDT as much as the liquidity pool information
  • Cell locking the second UDT as much as the liquidity pool information

The outputs are:

  • Cell with updated liquidity pool information
  • Cell to lock up the first UDT as much as the updated liquidity pool information
  • Cell to lock up the second UDT as much as the updated liquidity pool information
  • Fixed fee cell to prevent occupancy of shared state

Swapping the first UDT with the second UDT and swapping the second UDT with the first UDT work with the same formula.

The UDT cell that the user needs for swap can be input to any location that satisfies the picture above.

The UDT cell that the user will receive after swapping does not matter at any location that satisfies the picture above.

When multiple swaps due to multiple pools are performed in one transaction, the input and output must be present in sequence, in order of three, in order of the storage of the liquidity pool information, the cell that locks up the first UDT, and the cell that locks up the second UDT. The fee cell must exist as the output cell immediately after all the above cells.

All UDT inputs and outputs required for this can be located at any position as long as the above conditions are satisfied.

The input amount means the amount of CKB or UDT to be provided by the user.

The output amount is the amount of CKB or UDT the user will receive.

The input reserve means the amount of liquidity pool provided by the user, which is the same as CKB or UDT.

The output reserve is the amount of liquidity pool that the user will receive equal to CKB or UDT.

The formula is:

  1. When determining the input amount based on the output amount
  • input amount = input reserve * output amount * 1000 / (output reserve-output amount) * 997 + 1
  1. When determining the output amount based on the input amount
  • output amount = input amount * 997 * output reserve / (input reserve * 1000 + input amount * 997)
2 Likes

Thank you for updating this!

2 Likes

Could I say that it is an innovation for not only solving the occupation problem but finding a incentive model for pool providers?

UDTswap has a Protocol Protection Fee (PPF) to solve the occupancy problem. PPF is currently set to a fixed value of 61 CKB. And PPF is not offered as an incentive to pool providers.

UPDATE: Checkpoint 2 Update

First let’s recall the goals of Checkpoint 2:

UDTswap’s UX/UI MVP model, Test case, and documents were released at this checkpoint.

UDTswap UX/UI:

UDTswap’s overall UX/UI has been made familiar to existing swap users, so you can proceed with swap without learning.

Swap:

Send:

Pool(Add):

Pool (Remove):

Pool (Create):

Documents:

In the documentation, you can see the basic introduction of the basic UDTswap, technical specification, script architecture, and User Defined Token Listing form.

Documents:https://docs.udtswap.io/

Test case

We created swap, pool(add/remove/create), multiple pool swap test cases for CKB/UDT pair and UDT/UDT pair to test scripts and functions of UDTswap. If you want to see the contents of this, please refer to GitHub.

Src:

Test:

Prerequisite

  • local testnet (private) node rpc endpoint
  • 1 account for deploying UDTswap scripts
  • 2 accounts for minting test UDT
  • 1 account for testing (all accounts should have enough ckb)

How to test

Compile

  1. sudo docker run --rm -it -v pwd:/code nervos/ckb-riscv-gnu-toolchain:xenial bash
  2. cd /code/UDTswap_scripts
  3. riscv64-unknown-elf-gcc -c bn.c
  4. ar rc libbn.a bn.o
  5. riscv64-unknown-elf-gcc -o UDTswap_udt_based UDTswap_udt_based.c -L ./ -lbn
  • Execute 3. 4. only once
  • Execute 5. with same name for all scripts (test_udt.c, UDTswap_liquidity_UDT_udt_based.c, UDTswap_lock_udt_based.c, UDTswap_udt_based.c)

Deploy

  1. npm install
  2. Change sk to deploying account’s secret key in ‘/src/udtswap_consts.js’
  3. Change nodeUrl to local testnet node rpc endpoint in ‘/src/udtswap_consts.js’
  4. Compile scripts
  5. node deploy_scripts 0 in ‘/test/deploy’
  6. Change udtswap_type_script_code_hash_buf , udtswap_lock_code_hash_buf , udtswap_liquidity_udt_code_hash_buf to 5. outputs
  7. Compile scripts again
  8. node deploy_scripts 1 in ‘/test/deploy’
  9. Change CodeHash, Deps, Type to 5. outputs and 8. outputs

Mint test UDTs

  1. Change UDT1Owner , UDT2Owner , skTesting to 2 accounts secret key minting test UDT, 1 account’s secret key testing
  2. node deploy_scripts 2 in ‘test/deploy’

Test

npm test

We made it easy to test UDTswap thanks to the @harryliu team.

8 Likes

Cool job :grinning:

1 Like

How are you getting along with the work?

1 Like