@ref-finance/ref-sdk
v1.4.2
Published
This SDK is designed to assist developers when interacting with the main functions of the protocol. Main functions that can be defined as:
Downloads
1,606
Readme
Ref SDK
This SDK is designed to assist developers when interacting with the main functions of the protocol. Main functions that can be defined as:
- Trade: Swap tokens with our Automated Market Maker (AMM).
- Pool: Add/Remove liquidity and earn revenue from swap fee (Coming soon)
- Farm: Stale LP tokens into farms and earn liquidity incentives (Coming soon)
- Boost Farm: Stake LOVE tokens to get boosted liquidity incentives (Coming soon)
- Stake: Stake REF tokens to earn fees generated by the protocol (Coming soon)
- Vote: Lock REF<>NEAR LP tokens to get veTokens and participate in the governance of the protocol and the allocation of liquidity incentives (Coming soon)
Install
yarn: yarn add @ref-finance/ref-sdk
npm: npm install @ref-finance/ref-sdk
Initialization
Ref SDK identifies env variable NEAR_ENV or REACT_APP_REF_SDK_ENV to get global configuration.
export function getConfig(
env: string | undefined = ENV ||
process.env.NEAR_ENV ||
process.env.REACT_APP_REF_SDK_ENV
) {
ENV = env;
switch (env) {
case 'mainnet':
return {
networkId: 'mainnet',
nodeUrl: 'https://rpc.mainnet.near.org',
walletUrl: 'https://wallet.near.org',
WRAP_NEAR_CONTRACT_ID: 'wrap.near',
REF_FI_CONTRACT_ID: 'v2.ref-finance.near',
REF_TOKEN_ID: 'token.v2.ref-finance.near',
indexerUrl: 'https://indexer.ref.finance',
explorerUrl: 'https://testnet.nearblocks.io',
REF_DCL_SWAP_CONTRACT_ID: 'dclv2.ref-labs.near',
};
case 'testnet':
return {
networkId: 'testnet',
nodeUrl: 'https://rpc.testnet.near.org',
walletUrl: 'https://wallet.testnet.near.org',
indexerUrl: 'https://testnet-indexer.ref-finance.com',
WRAP_NEAR_CONTRACT_ID: 'wrap.testnet',
REF_FI_CONTRACT_ID: 'ref-finance-101.testnet',
REF_TOKEN_ID: 'ref.fakes.testnet',
explorerUrl: 'https://testnet.nearblocks.io',
REF_DCL_SWAP_CONTRACT_ID: 'dclv2.ref-dev.testnet',
};
default:
return {
networkId: 'mainnet',
nodeUrl: 'https://rpc.mainnet.near.org',
walletUrl: 'https://wallet.near.org',
REF_FI_CONTRACT_ID: 'v2.ref-finance.near',
WRAP_NEAR_CONTRACT_ID: 'wrap.near',
REF_TOKEN_ID: 'token.v2.ref-finance.near',
indexerUrl: 'https://indexer.ref.finance',
explorerUrl: 'https://nearblocks.io',
REF_DCL_SWAP_CONTRACT_ID: 'dclv2.ref-labs.near',
};
}
}
Also, the SDK provides init_env
to switch application environment. there is an optional parameter indexerUrl that you can use to replace the one in the SDK with your own deployed indexer service. We'd better call it at the entrance of the application, then the entire application environment switch takes effect. If you're not sure where to call, you can call in more than one place.
Example
init_env('testnet');
init_env('mainnet');
init_env('testnet', 'https://xx-xx.xx-xxx.com');
init_env('mainnet', 'https://xx-xx.xx-xxx.com');
Ref V1 Swap
Tokens
ftGetTokenMetadata
Get token metadata.
Parameters
id: string;
Example
const WrapNear = await ftGetTokenMetadata('wrap.testnet');
Response
{
decimals: 24;
icon: null;
id: 'wrap.testnet';
name: 'Wrapped NEAR fungible token';
reference: null;
reference_hash: null;
spec: 'ft-1.0.0';
symbol: 'wNEAR';
}
ftGetTokensMetadata
Get tokens metadata and set token id as index.
Will fetch token matadata if the token not included in the allTokens.
Parameters
(tokenIds: string[], allTokens: Record<string, TokenMetadata>)
Example
const tokensMetadata = await ftGetTokensMetadata([
'ref.fakes.testnet',
'wrap.testnet',
],{});
Response
{
"ref.fakes.testnet":{
decimals: 18
icon: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='16 24 248 248' style='background: %23000'%3E%3Cpath d='M164,164v52h52Zm-45-45,20.4,20.4,20.6-20.6V81H119Zm0,18.39V216h41V137.19l-20.6,20.6ZM166.5,81H164v33.81l26.16-26.17A40.29,40.29,0,0,0,166.5,81ZM72,153.19V216h43V133.4l-11.6-11.61Zm0-18.38,31.4-31.4L115,115V81H72ZM207,121.5h0a40.29,40.29,0,0,0-7.64-23.66L164,133.19V162h2.5A40.5,40.5,0,0,0,207,121.5Z' fill='%23fff'/%3E%3Cpath d='M189 72l27 27V72h-27z' fill='%2300c08b'/%3E%3C/svg%3E%0A"
id: "ref.fakes.testnet"
name: "Ref Finance Token"
reference: null
reference_hash: null
spec: "ft-1.0.0"
symbol: "REF"
},
"wrap.testnet":{
decimals: 24
icon: null
id: "wrap.testnet"
name: "Wrapped NEAR fungible token"
reference: null
reference_hash: null
spec: "ft-1.0.0"
symbol: "wNEAR"
}
}
Pools
fetchAllPools
Fetch all existing pools, including vanilla/simple pools, stable pools and rated pools (designed for yield-bearing tokens).
Parameters
perPage?:number
Example
const { ratedPools, unRatedPools, simplePools } = await fetchAllPools();
const { ratedPools, unRatedPools, simplePools } = await fetchAllPools(200);
Response
{
ratedPools:[{
fee: 5,
id: 568,
pool_kind: "RATED_SWAP",
shareSupply: "80676034815429711745720012070",
supplies:{
"meta-v2.pool.testnet": "1298314415249170366960739764"
"wrap.testnet": "80182803630538035347294614770"
},
token0_ref_price: undefined,
tokenIds: ["meta-v2.pool.testnet", "wrap.testnet"],
tvl: undefined
},...]
unRatedPools:[...],
simplePools:[...],
}
getStablePools
We define unRatedPools
and ratedPools
as stablePool
. You can use this function to get details of stable pools.
Parameters
stablePools: Pool[]
Example
const stablePools: Pool[] = unRatedPools.concat(ratedPools);
const stablePoolsDetail: StablePool[] = await getStablePools(stablePools);
Response
[
{
amounts: ['1298314415249170366960739764', '80182803630538035347294614770'],
amp: 240,
c_amounts:["1298314415249170366960739764","80182803630538035347294614770"],
decimals:[24,24],
id: 568,
pool_kind: "RATED_SWAP",
rates:["1972101024157559347385372","1000000000000000000000000"],
shares_total_supply: "80676034815429711745720012070",
token_account_ids:["meta-v2.pool.testnet","wrap.testnet"],
total_fee:5
},
...
]
getPoolByIds
Input pool id array to get according pools detail
Parameters
ids: number[]
Example
const pools = await getPoolByIds([1, 2, 20])
Response
[
{
"id": 1,
"tokenIds": [
"nusdt.ft-fin.testnet",
"nusdc.ft-fin.testnet"
],
"supplies": {
"nusdt.ft-fin.testnet": "194177",
"nusdc.ft-fin.testnet": "54127"
},
"fee": 20,
"shareSupply": "1004672374319452764166320",
"pool_kind": "SIMPLE_POOL"
},
{
"id": 2,
"tokenIds": [
"wrap.testnet",
"rft.tokenfactory.testnet"
],
"supplies": {
"wrap.testnet": "511569006838329327251856820",
"rft.tokenfactory.testnet": "860281941972"
},
"fee": 20,
"shareSupply": "935312501418615016412773941",
"pool_kind": "SIMPLE_POOL"
},
{
"id": 20,
"tokenIds": [
"usdc.fakes.testnet",
"nusdc.ft-fin.testnet"
],
"supplies": {
"usdc.fakes.testnet": "129199395436",
"nusdc.ft-fin.testnet": "26747"
},
"fee": 20,
"shareSupply": "7084500646929369809446253",
"pool_kind": "SIMPLE_POOL"
}
]
Swap
estimateSwap
Get token output amount and corresponding route.
As there is a memory limitation on Ledger, note that we set enableSmartRouting
option for developers.
This function integrates a smart routing algorithm, designed to deliver the best output token amount.
Parameters
interface SwapParams {
tokenIn: TokenMetadata;
tokenOut: TokenMetadata;
amountIn: string;
simplePools: Pool[];
options?: SwapOptions;
}
interface SwapOptions {
enableSmartRouting?: boolean;
stablePools?: Pool[];
stablePoolsDetail?: StablePool[];
}
Example (enableSmartRouting == false)
// enableSmartRouting as FALSE, swap from Ref to wNear, with amount 1
const tokenIn = await ftGetTokenMetadata('ref.fakes.testnet');
const tokenOut = await ftGetTokenMetadata('wrap.testnet');
const swapTodos: EstimateSwapView[] = await estimateSwap({
tokenIn,
tokenOut,
amountIn: '1',
simplePools,
});
Response (enableSmartRouting == false)
// enableSmartRouting as FALSE, swap from Ref to wNear, with amount 1
[
{
estimate: '0.7338604246699393',
inputToken: 'ref.fakes.testnet',
outputToken: 'wrap.testnet',
pool: {
fee: 30,
id: 38,
partialAmountIn: '1000000000000000000',
pool_kind: 'SIMPLE_POOL',
shareSupply: '1000587315520795219676332',
supplies: {
'ref.fakes.testnet': '7789776060978885018',
'wrap.testnet': '6467670222256390319335181',
},
token0_ref_price: undefined,
tokenIds: (2)[('ref.fakes.testnet', 'wrap.testnet')],
tvl: undefined,
},
},
];
Example (enableSmartRouting == true)
// enableSmartRouting as TRUE, swap from Ref to wNear, with amount 1
const tokenIn = await ftGetTokenMetadata('ref.fakes.testnet');
const tokenOut = await ftGetTokenMetadata('wrap.testnet');
const options: SwapOptions = {
enableSmartRouting: true,
stablePools,
stablePoolsDetail,
};
const swapTodos: EstimateSwapView[] = await estimateSwap({
tokenIn,
tokenOut,
amountIn: '1',
simplePools,
options,
});
Response (enableSmartRouting == true)
// enableSmartRouting as true, swap from Ref to wNear, with amount 1
[
{
estimate: "0.000225321544275095902371355566972009167",
inputToken: "ref.fakes.testnet",
outputToken: "nusdt.ft-fin.testnet",
pool:{
id: 341,
partialAmountIn: "836859596261755688",
tokenIds: ["ref.fakes.testnet","nusdt.ft-fin.testnet"],
...
},
...
},{
estimate: "0.5203255327171591155634413370660973429264",
inputToken: "nusdt.ft-fin.testnet",
outputToken: "wrap.testnet",
pool:{
id: 1625,
tokenIds: ["nusdt.ft-fin.testnet","wrap.testnet"],
...
},
...
},{
estimate: "5.3206339674140066489000963525772735539612",
inputToken: "ref.fakes.testnet",
outputToken: "usdn.testnet",
pool:{
id: 376,
tokenIds: ["usdn.testnet","ref.fakes.testnet"],
partialAmountIn: "163140403738244312",
...
},
...
},{
estimate: "0.2036473132202839680683206178037243543302",
inputToken: "usdn.testnet",
outputToken: "wrap.testnet",
pool:{
id: 385,
tokenIds: ["usdn.testnet","wrap.testnet"],
...
},
...
}
]
getExpectedOutputFromSwapTodos
Get token output amount from swapTodos.
Parameters
(swapTodos: EstimateSwapView[], outputToken: string)
Example
const swapTodos: EstimateSwapView[] = await estimateSwap({
tokenIn,
tokenOut,
amountIn: '1',
simplePools,
options,
});
const amountOut:string = getExpectedOutputFromSwapTodos(swapTodos, tokenOut.id);
Response
"0.723972845937443"
getPoolEstimate
Get token output amount from one single pool. Method can be used for simple and stable pools.
Parameters
{
tokenIn: TokenMetadata;
tokenOut: TokenMetadata;
amountIn: string;
pool: Pool;
// please input stablePoolDetail if you want estimate output on stable pool or the pool will be recognized as simple pool
stablePoolDetail?: StablePool;
}
Example (on simple pool)
// estimate on simple Pool
const estimate = await getPoolEstimate({
tokenIn,
tokenOut,
amountIn: '1',
pool,
});
Response (on simple pool)
// estimate on simple pool, swap from Ref to wNear, with amount 1
{
estimate: "0.7338604246699393",
inputToken: "ref.fakes.testnet",
outputToken: "wrap.testnet",
pool:{
fee: 30,
id: 38,
partialAmountIn: "1000000000000000000",
pool_kind: "SIMPLE_POOL",
shareSupply: "1000587315520795219676332",
supplies: {"ref.fakes.testnet": '7789776060978885018', "wrap.testnet": '6467670222256390319335181'},
token0_ref_price: undefined,
tokenIds: (2) ['ref.fakes.testnet', 'wrap.testnet'],
tvl: undefined
}
}
Example (on stable pool)
// estimate on stable pool
const estimate = await getPoolEstimate({
tokenIn,
tokenOut,
amountIn: '1',
pool: stablePool,
stablePoolDetail: stablePoolDetail,
});
Response (on stable pool)
// estimate on stable pool, swap from stNear to wNear, with amount 1
{
estimate: "2.4898866773442284",
inputToken: "meta-v2.pool.testnet",
noFeeAmountOut: "2.491132243465961",
outputToken: "wrap.testnet",
pool:{
amounts:["1298314415249170366960739764","80182803630538035347294614770"],
amp: 240,
c_amounts:["1298314415249170366960739764","80182803630538035347294614770"],
decimals:[24,24],
id: 568,
pool_kind: "RATED_SWAP",
rates:["1972204647926836788049038","1000000000000000000000000"],
shares_total_supply: "80676034815429711745720012070",
token_account_ids:["meta-v2.pool.testnet", "wrap.testnet"],
total_fee: 5,
}
}
Transactions
instantSwap
Set up transactions through swap routes. Please ensure that the AccountId has an active balance storage in the token-in contract, otherwise the transaction will fail and the user will lose the token input amount.
Parameters
{
tokenIn: TokenMetadata;
tokenOut: TokenMetadata;
amountIn: string;
slippageTolerance: number;
swapTodos: EstimateSwapView[];
AccountId: string;
referralId?: string;
}
Example
const transactionsRef: Transaction[] = await instantSwap({
tokenIn,
tokenOut,
amountIn: '1',
swapTodos,
slippageTolerance = 0.01,
AccountId: 'your-account-id.testnet',
referralId: 'ref-fee.testnet'
});
Response
[
{
functionCalls: [
{
amount: '0.000000000000000000000001',
args: {
amount: '1000000000000000000',
msg:
'{"force":0,"referral_id":"ref-fee.testnet" ,"actions":[{"pool_id":38,"token_in":"ref.fakes.testnet","token_out":"wrap.testnet","amount_in":"1000000000000000000","min_amount_out":"730191122546589600000000"}]}',
receiver_id: 'ref-finance-101.testnet',
},
gas: '180000000000000',
methodName: 'ft_transfer_call',
},
],
receiverId: 'ref.fakes.testnet',
},
];
getSignedTransactionsByMemoryKey (Node)
In the local env, developers can add credentials by near login
.
This function utilizes credentials stored in the local env to sign transactions.
Parameters
{
transactionsRef: Transaction[];
AccountId: string;
keyPath: string;
}
Example
const signedTransactions:nearTransactions.SignedTransaction[] = await getSignedTransactionsByMemoryKey({
transactionsRef;
AccountId: "your-account-id.testnet",
keyPath: "/.near-credentials/testnet/your-account-id.testnet.json"
})
Response
[
SignedTransaction {
transaction: Transaction {
signerId: 'your-account-id.testnet',
publicKey: [PublicKey],
nonce: 91940092000042,
receiverId: 'ref.fakes.testnet',
actions: [Array],
blockHash: <Buffer 45 e5 fd 36 87 3b 10 59 81 d9 a7 b5 20 c7 29 33 f7 27 48 59 06 90 ca 8a 17 03 5c 25 f2 76 ab 7c>
},
signature: Signature { keyType: 0, data: [Uint8Array] }
}
]
sendTransactionsByMemoryKey (Node)
This function utilizes credentials stored in the local env to send transactions.
Parameters
{
signedTransactions: nearTransactions.SignedTransaction[];
}
Example
sendTransactionsByMemoryKey({
signedTransactions,
});
Response
[
{
receipts_outcome: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object]
],
status: { SuccessValue: 'xxxxxx' },
transaction: {
actions: [Array],
hash: 'xxxxxxxx',
nonce: 91940092000042,
public_key: 'ed25519:xxxxxxxx',
receiver_id: 'ref.fakes.testnet',
signature: 'ed25519:xxxxxxxxxxxxx',
signer_id: 'your-account-id.testnet'
},
transaction_outcome: {
block_hash: '3QXEF941UvsHzXrMhwbchk7wmy3qmPNs3w9gkfvW84QK',
id: 'xxxxxxxx',
outcome: [Object],
proof: []
}
}
]
Ref Swap Widget
Description
The Ref Swap Widget is a useful tool, allowing any third party service to access Ref's liquidity. Users of ecosystem dapps have the ability to swap via the Widget, without the need to go to Ref app, thus improving the user experience.
Here are some use cases:
- Swapping stablecoins for your project's token
- Swapping tokens to lend, farm or stake
- Swapping one token for a specific token, which can be used to buy a NFT in the associated marketplace
Using the Ref Swap Widget, with a few customizations, developers can integrate the Swap funtion directly into their dapps. Both mobile and/or website version are available.
For the default theme, developers can chose between the light mode and dark mode.
More themes can be selected: Click here to check them on figma.
To integrate the Ref Swap Widget, please follow this guide.
Getting started
A QuickStart of Ref Swap component.
Props
export interface SwapWidgetProps {
theme?: Theme;
defaultTokenList?: string[];
onSwap: (transactionsRef: Transaction[]) => void;
onDisConnect: () => void;
width: string;
height?: string;
enableSmartRouting?: boolean;
className?: string;
darkMode?: boolean;
connection: {
AccountId: string;
isSignedIn: boolean;
};
defaultTokenIn?: string;
defaultTokenOut?: string;
referralId?:string;
transactionState: {
state: SwapState;
setState: (state: SwapState) => void;
tx?: string;
detail?: string;
};
minNearAmountLeftForGasFees?: number;
onConnect: () => void;
}
- theme: widget theme for customization.
- defaultTokenList: default tokens with ref whitelist into token list in the widget.
- onSwap: Swap button triggers this function.
- width: width of widget component.
- height: height of widget component.
- enableSmartRouting: option to choose if enable smart routing in swap routes estimation.
- className: extra className added to widget component.
- darkMode: if true, will automatically set theme to default dark mode.
- connection: connection to wallets, input { AccountId:"", isSignedIn:false } if wallet not connected.
- defaultTokenIn: default token-in.
- defaultTokenOut: default token-out.
- referralId: You can get referral fee from every swap routed by your app. But make sure that your referral_id is in Ref's referral list. For the details, please check https://gov.ref.finance/t/contract-upgrade-1-7-0-referral-fee/823 .
- transactionState: entry to input transaction states after you send transactions.
- state: denote if last transaction is failed or successfull.
- setState: used to change setState to interact with pop-up.
- tx: will add link to near explorer according to this tx.
- detail: you could input some tips to show on sucess pop-up.
- minNearAmountLeftForGasFees: minimun near value reserved for tx gas fees.
- onDisConnect: Disconnect button triggers this function.
- onConnect: Connect to Near Wallet button triggers this function.
Usage
Theme
export interface Theme {
container: string; // container background
buttonBg: string; // button background
primary: string; // primary theme color
secondary: string; // secondary theme color
borderRadius: string; // border radius
fontFamily: string; // font family
hover: string; // hovering color
active: string; // active color
secondaryBg: string; // secondary background color
borderColor: string; // border color
iconDefault: string; // default icon color
iconHover: string; // icon hovering color
refIcon?: string; // ref icon color, default to be black
}
export const defaultTheme: Theme = {
container: '#FFFFFF',
buttonBg: '#00C6A2',
primary: '#000000',
secondary: '#7E8A93',
borderRadius: '4px',
fontFamily: 'sans-serif',
hover: 'rgba(126, 138, 147, 0.2)',
active: 'rgba(126, 138, 147, 0.2)',
secondaryBg: '#F7F7F7',
borderColor: 'rgba(126, 138, 147, 0.2)',
iconDefault: '#7E8A93',
iconHover: '#B7C9D6',
};
export const defaultDarkModeTheme: Theme = {
container: '#26343E',
buttonBg: '#00C6A2',
primary: '#FFFFFF',
secondary: '#7E8A93',
borderRadius: '4px',
fontFamily: 'sans-serif',
hover: 'rgba(126, 138, 147, 0.2)',
active: 'rgba(126, 138, 147, 0.2)',
secondaryBg: 'rgba(0, 0, 0, 0.2)',
borderColor: 'rgba(126, 138, 147, 0.2)',
iconDefault: '#7E8A93',
iconHover: '#B7C9D6',
refIcon: 'white',
};
Component
// an example of combining SwapWidget with wallet-selector
import * as React from 'react';
import { SwapWidget } from '@ref-finance/ref-sdk';
// please check on wallet-selector example about how to set WalletSelectorContext
import { useWalletSelector } from './WalletSelectorContext';
import { WalletSelectorTransactions, NotLoginError } from '@ref-finance/ref-sdk';
export const Widget = ()=>{
const { modal, selector, accountId } = useWalletSelector();
const [swapState, setSwapState] = React.useState<SwapState>(
null
);
const [tx, setTx] = React.useState<string | undefined>(undefined);
React.useEffect(() => {
const errorCode = new URLSearchParams(window.location.search).get(
'errorCode'
);
const transactions = new URLSearchParams(window.location.search).get(
'transactionHashes'
);
const lastTX = transactions?.split(',').pop();
setTx(lastTX);
setSwapState(!!errorCode ? 'fail' : !!lastTX ? 'success' : null);
window.history.replaceState(
{},
'',
window.location.origin + window.location.pathname
);
}, []);
const onSwap = async (transactionsRef: Transaction[]) => {
const wallet = await selector.wallet();
if (!accountId) throw NotLoginError;
wallet.signAndSendTransactions(
WalletSelectorTransactions(transactionsRef, accountId)
);
};
const onConnect = () => {
modal.show();
};
const onDisConnect = async () => {
const wallet = await selector.wallet();
return await wallet.signOut();
};
return (
<SwapWidget
onSwap={onSwap}
onDisConnect={onDisConnect}
width={'400px'}
connection={{
AccountId: accountId || '',
isSignedIn: !!accountId,
}}
transactionState={{
state: swapState,
setState: setSwapState,
tx,
detail: '(success details show here)',
}}
enableSmartRouting={true}
onConnect={onConnect}
defaultTokenIn={'wrap.testnet'}
defaultTokenOut={'ref.fakes.testnet'}
/>
);
}
Integrating Ref Swap function using the SDK
The SDK provides more flexibility/options.
The default Swap version can serve as a reference. Click here to check on figma.
For more details about the SDK, please refer to [here].
SDK integration tips:
- You can use 'ftGetTokensMetadata' function to get all available tokens, and list them in the token selector to allow users to select their trading pair. If you do not need all available tokens, you can limit the list at the frontend level, thus only displaying specific tokens such as REF, NEAR, and USDT, for example.
- Please pay attention to the user's 'tokenIn' balance. If the balance is zero, you should DISABLE the swap button.
- You can let the user set the slippage, or you can pre set a default number.
- For a better user experience, before the execution of the swap, you can show more details about the swap (ex: fee, rate, route, etc.), allowing users to take better data-driven decisions.
- You can redirect the user to the NEAR Explorer, once the transaction is confirmed.
Ref V2(DCL) Swap
An overview of Ref V2
The launch of concentrated liquidity AMM is an achievement for Ref Finance. In collaboration with Izumi Finance and Arctic, Ref is glad to introduce discretized concentrated liquidity and limit order two new key features to the NEAR ecosystem. Using REF SDK, developers can dig more opportunities and implement various trading strategies.Before introducing SDK details, let's have an overview of V2 exciting features.
Discretized concentrated liquidity
Discretized concentrated liquidity can improve as much as 4000x higher capital efficiency for liquidity providers(LPs).
When adding liquidity, LPs are can allocate their capital to a certain price range thus providing greater amounts of liquidity at this range. The fees earned are decided by the volumes swapped in the price range. Logically, if you want to earn more, you should set the price range most desired by the market.
Here are the advantages of using Ref V2 concentrated liquidity for LPS.
- Efficient swap fee earnings and less impermanent loss by setting a price range
- Improved fee structure: only LPs (and the protocol itself) can benefit from swap fees, which means an LP can also benefit from a transaction between a taker and market makers as long the transaction closes at the price within the range set by him/her. This is quite different from Uniswap V3 by giving more benefits to LPS.
- Versatile strategies for different pairs: according to correlations of trading pairs, market demand and fee tiers, versatile strategies can be designed to make a profit and hedge against risk.
Enhanced limit order
Izumi's algorithm of constant sum formula on small price range fragment enables an enhanced limit order function that is different than Uniswap V3. The following remarkable improvements are noticeable.
- No price restrictions when placing a limit order: Users can place limit buy orders at a price higher than current price or sell orders lower than current price. Ref V2 would auto match with best price first, similar to CLOBs (central limit order books) seen on centralized exchanges.
- No need to keep an eye on order progress: As a kind of one-way liquidity, users can claim their order earning at any time without any concern that the earned token would be reverted.
- CEX order-book style user experience.
Enhanced limit order will give more convenience for strategy trading like grid trading, arbitrage, day trading, etc.
Decreased swap slippage
With much thicker liquidity around the current price point, swap slippage has a notable decrease.
As mentioned above, we've compared our development features of this model in comparison to Uniswaps model, from Ethereum to NEAR, but far less costly. Ref V2 provides a more capital efficient, user-friendly experience with dynamic pricing, reduced fees, and cross-chain integrations.
The combination of concentrated liquidity, enhanced limit order and decreased swap slippage offers a good tool kit for trading in NEAR ecosystem. Enjoy it.
DCL pool
getDCLPoolId
Get DCL pool id by tokenA, tokenB and fee.
Note: the fee should be in one of [100, 400, 2000, 10000], which means we charge [0.01%, 0.04%, 0.2%, 1%] separately.
Parameters
(tokenA:string, tokenB:string, fee:number)
Example
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const pool_id = getDCLPoolId(tokenA, tokenB, fee)
Response
"usdt.fakes.testnet|wrap.testnet|2000"
listDCLPools
List all DCL pools
Parameters
None
Example
const allDCLPools = await listDCLPools()
Response
[
{
pool_id: 'usdt.fakes.testnet|wrap.testnet|100',
token_x: 'usdt.fakes.testnet',
token_y: 'wrap.testnet',
fee: 100,
point_delta: 1,
current_point: 391459,
liquidity: '0',
liquidity_x: '0',
max_liquidity_per_point: '212676346402870037870835460372692',
volume_x_in: '0',
volume_y_in: '0',
volume_x_out: '0',
volume_y_out: '0',
total_liquidity: '0',
total_order_x: '1000000000000',
total_order_y: '0',
total_x: '1000000000000',
total_y: '0',
state: 'Running'
},
...
]
getDCLPool
Get DCL pool by pool id
Parameters
(pool_id: string)
Example
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const pool_id = getDCLPoolId(tokenA, tokenB, fee)
const pool = await getDCLPool(pool_id)
Response
{
pool_id: 'usdt.fakes.testnet|wrap.testnet|2000',
token_x: 'usdt.fakes.testnet',
token_y: 'wrap.testnet',
fee: 2000,
point_delta: 40,
current_point: 380120,
liquidity: '1110725876876975',
liquidity_x: '1110725876876975',
max_liquidity_per_point: '8506846501860915063707772491481918',
volume_x_in: '8754783773',
volume_y_in: '109748224827667685031216606',
volume_x_out: '1220525924',
volume_y_out: '1301582127053053120024924721',
total_liquidity: '9961756656973511',
total_order_x: '101475486843',
total_order_y: '31907047396923536842194449',
total_x: '125636676594',
total_y: '131645349254303605341104269',
state: 'Running'
}
DCL Swap
quote
quote output amount by pool_ids, input_amount, input_token, output_token
Parameters
{
pool_ids: string[];
input_token: TokenMetadata;
output_token: TokenMetadata;
input_amount: string;
tag?: string;
}
Example
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 10000
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await quote({
pool_ids,
input_amount,
input_token: tokenAMetadata,
output_token: tokenBMetadata,
});
Response
{ amount: '203807761645099642566723', tag: null }
quote_by_output
quote in put amount by output amount to price by pool_ids, input_amount, input_token, output_token
Parameters
{
pool_ids: string[];
input_token: TokenMetadata;
output_token: TokenMetadata;
input_amount: string;
tag?: string;
}
Example
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 10000
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await quote_by_output({
pool_ids,
output_amount: "0.1",
input_token: tokenAMetadata,
output_token: tokenBMetadata,
});
Response
{ amount: '490370', tag: null }
DCLSwap
This function integrates Swap, SwapByOutput and LimitOrderWithSwap apis.
- Swap: swap from tokenA to get tokenB.
- SwapByOutput: Swap to get specific tokenB and comsume tokenA.
- LimitOrderWithSwap: compare the calculated price based on parameters with price in the pool, if calculated price is lower than the pool price, go to Swap, the left will generate an limit order higher than the pool price, and if no amount is left, no order generated; if the calculated price is higher than the pool price, will directly generate an limit order.
Parameters
interface SwapInfo {
tokenA: TokenMetadata;
tokenB: TokenMetadata;
amountA: string;
}
interface DCLSwapProps {
swapInfo: SwapInfo;
Swap?: {
pool_ids: string[];
min_output_amount: string;
};
SwapByOutput?: {
pool_ids: string[];
output_amount: string;
};
LimitOrderWithSwap?: {
pool_id: string;
output_amount: string;
};
SwapByStopPoint?: {
pool_id: string;
stop_point: number;
skip_unwrap_near: boolean;
};
AccountId: string;
}
Example (Swap)
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await DCLSwap({
swapInfo: {
amountA: input_amount,
tokenA: tokenAMetadata,
tokenB: tokenBMetadata,
},
Swap: {
min_output_amount: "0",
pool_ids,
},
AccountId,
});
Response (Swap)
[
{
receiverId: "usdt.fakes.testnet",
functionCalls: [
{
methodName: "ft_transfer_call",
args: {
receiver_id: "dcl.ref-dev.testnet",
amount: "1000000",
msg: '{"Swap":{"pool_ids":["usdt.fakes.testnet|wrap.testnet|2000"],"output_token":"wrap.testnet","min_output_amount":"0"}}',
},
gas: "180000000000000",
amount: "0.000000000000000000000001",
},
],
},
];
Example (SwapByOutput)
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const res = await DCLSwap({
swapInfo: {
amountA: input_amount,
tokenA: tokenAMetadata,
tokenB: tokenBMetadata,
},
SwapByOutput: {
pool_ids,
output_amount: "4.89454792",
},
AccountId,
});
Response (SwapByOutput)
[
{
receiverId: "usdt.fakes.testnet",
functionCalls: [
{
methodName: "ft_transfer_call",
args: {
receiver_id: "dcl.ref-dev.testnet",
amount: "900000",
msg: '{"SwapByOutput":{"pool_ids":["usdt.fakes.testnet|wrap.testnet|2000"],"output_token":"wrap.testnet","output_amount":"4894547920000000000000000"}}',
},
gas: "180000000000000",
amount: "0.000000000000000000000001",
},
],
},
];
Example (LimitOrderWithSwap)
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await DCLSwap({
swapInfo: {
amountA: input_amount,
tokenA: tokenAMetadata,
tokenB: tokenBMetadata,
},
LimitOrderWithSwap: {
pool_id,
output_amount: "3217.929",
},
AccountId,
});
Response (LimitOrderWithSwap)
[
{
receiverId: "usdt.fakes.testnet",
functionCalls: [
{
methodName: "ft_transfer_call",
args: {
receiver_id: "dcl.ref-dev.testnet",
amount: "1000000",
msg: '{"LimitOrderWithSwap":{"pool_id":"usdt.fakes.testnet|wrap.testnet|2000","buy_token":"wrap.testnet","point":495240}}',
},
gas: "180000000000000",
amount: "0.000000000000000000000001",
},
],
},
];
Example (SwapByStopPoint)
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const fee = 2000
const pool_ids = [getDCLPoolId(tokenA, tokenB, fee)];
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await DCLSwap({
swapInfo: {
amountA: input_amount,
tokenA: tokenAMetadata,
tokenB: tokenBMetadata,
},
SwapByStopPoint: {
pool_id: pool_id,
stop_point: 405920,
},
AccountId,
});
Response (SwapByStopPoint)
[
{
receiverId: "usdt.fakes.testnet",
functionCalls: [
{
methodName: "ft_transfer_call",
args: {
receiver_id: "dcl.ref-dev.testnet",
amount: "1000000",
msg: '{"SwapByStopPoint":{"pool_id":"usdt.fakes.testnet|wrap.testnet|2000","stop_point":495240}}',
},
gas: "180000000000000",
amount: "0.000000000000000000000001",
},
],
},
];
DCLSwapByInputOnBestPool
This function helps to swap on best price pool of at most 4 candidate pools based on tokenA, tokenB, amountA (input amount) and slippageTolerance.
Parameters
{
tokenA: TokenMetadata;
tokenB: TokenMetadata;
amountA: string;
slippageTolerance: number;
AccountId: string;
}
Example
const tokenA = "usdt.fakes.testnet";
const tokenB = "wrap.testnet";
const tokenAMetadata = await ftGetTokenMetadata(tokenA)
const tokenBMetadata = await ftGetTokenMetadata(tokenB)
const res = await DCLSwapByInputOnBestPool({
tokenA:tokenAMetadata,
tokenB:tokenBMetadata,
amountA: "1",
slippageTolerance: 0.1,
AccountId,
});
Response
[
{
receiverId: "usdt.fakes.testnet",
functionCalls: [
{
methodName: "ft_transfer_call",
args: {
receiver_id: "dcl.ref-dev.testnet",
amount: "1000000",
msg: '{"Swap":{"pool_ids":["usdt.fakes.testnet|wrap.testnet|10000"],"output_token":"wrap.testnet","min_output_amount":"203606350172806050000000"}}',
},
gas: "180000000000000",
amount: "0.000000000000000000000001",
},
],
},
];
Order
UserOrderInfo (interface)
interface UserOrderInfo {
order_id: string;
owner_id: string;
pool_id: string;
point: number;
sell_token: string;
created_at: string; // timestamp when this order created
original_amount: string; // original amount of sell_token
remain_amount: string; // remain amount to be swapped, 0 means a history order
cancel_amount: string; // amount after cancel an active order
original_deposit_amount: string; // the input amount of LimitOrderWithSwap through ft_transfer_call, maybe partially into instant Swap
swap_earn_amount: string; // earn token amount through swap before actual place order
buy_token: string;
unclaimed_amount: string;
bought_amount: string; // accumalated amount you get
}
list_active_orders
Get your active orders
Parameters
(AccountId: string)
Example
const res = await list_active_orders(AccountId)
Response
[
{
order_id: "usdt.fakes.testnet|wrap.testnet|10000#93",
owner_id: "your-account-id.testnet",
pool_id: "usdt.fakes.testnet|wrap.testnet|10000",
point: 398600,
sell_token: "wrap.testnet",
buy_token: "usdt.fakes.testnet",
original_deposit_amount: "1000000000000000000000000",
swap_earn_amount: "0",
original_amount: "1000000000000000000000000",
cancel_amount: "0",
created_at: "1667292669983952215",
remain_amount: "1000000000000000000000000",
bought_amount: "0",
unclaimed_amount: "0",
},
];
list_history_orders
Get your history orders
Parameters
(AccountId: string)
Example
const res = await list_history_orders(AccountId)
Response
[
{
order_id: "usdc.fakes.testnet|wrap.testnet|2000#47",
owner_id: "juaner.testnet",
pool_id: "usdc.fakes.testnet|wrap.testnet|2000",
point: 399120,
sell_token: "wrap.testnet",
buy_token: "usdc.fakes.testnet",
original_deposit_amount: "1000000000000000000000000",
swap_earn_amount: "0",
original_amount: "1000000000000000000000000",
cancel_amount: "1000000000000000000000000",
created_at: "1665928620632469264",
remain_amount: "0",
bought_amount: "0",
unclaimed_amount: null,
},
];
cancel_order
cancel an active order
Parameters
(order_id: string)
Example
const res = await cancel_order("usdt.fakes.testnet|wrap.testnet|10000#93")
Response
[
{
receiverId: "dcl.ref-dev.testnet",
functionCalls: [
{
methodName: "cancel_order",
args: {
order_id: "usdt.fakes.testnet|wrap.testnet|10000#93",
amount: "1000000000000000000000000",
},
gas: "180000000000000",
},
],
},
];
claim_order
Claim your unclaimed_amount in the order.
Parameters
(order_id: string)
Example
const res = await claim_order("usdt.fakes.testnet|wrap.testnet|10000#93")
Response
[
{
receiverId: "dcl.ref-dev.testnet",
functionCalls: [
{
methodName: "cancel_order",
args: {
order_id: "usdt.fakes.testnet|wrap.testnet|10000#93",
amount: "0",
},
gas: "180000000000000",
},
],
},
];
get_order
Get order information by order_id
Parameters
(order_id: string)
Example
const res = await get_order("usdt.fakes.testnet|wrap.testnet|10000#93")
Response
{
order_id: 'usdt.fakes.testnet|wrap.testnet|10000#93',
owner_id: 'juaner.testnet',
pool_id: 'usdt.fakes.testnet|wrap.testnet|10000',
point: 398600,
sell_token: 'wrap.testnet',
buy_token: 'usdt.fakes.testnet',
original_deposit_amount: '1000000000000000000000000',
swap_earn_amount: '0',
original_amount: '1000000000000000000000000',
cancel_amount: '0',
created_at: '1667292669983952215',
remain_amount: '1000000000000000000000000',
bought_amount: '0',
unclaimed_amount: '0'
}
Asset
list_user_assets
Get user assets.
Parameters
(AccountId: string)
Example
const res = await list_user_assets("your-account-id.testnet")
Response
{
'meta-v2.pool.testnet': '1000000000000000000000000',
'ref.fakes.testnet': '54795238623455655224444',
'usdc.fakes.testnet': '204436562555',
'eth.fakes.testnet': '112348196732799990900',
'usdt.fakes.testnet': '164044235810',
'wrap.testnet': '1004944616890200800000000'
}
Utils
priceToPoint
Get point based on input price
Parameters
{
tokenA: TokenMetadata;
tokenB: TokenMetadata;
amountA: string;
amountB: string;
fee: number;
}
Example
const tokenA = await ftGetTokenMetadata("usdt.fakes.testnet");
const tokenB = await ftGetTokenMetadata("wrap.testnet");
const amountA = "0.9";
const amountB = "4.89454792";
const fee = 400;
const res = priceToPoint({
tokenA,
tokenB,
amountA,
amountB,
fee,
});
Response
431416
pointToPrice
Get price from tokenA to tokenB based on point
Parameters
{
tokenA: TokenMetadata;
tokenB: TokenMetadata;
point: number;
}
Example
const tokenA = await ftGetTokenMetadata("usdt.fakes.testnet");
const tokenB = await ftGetTokenMetadata("wrap.testnet");
const res = pointToPrice({
tokenA,
tokenB,
point: 431416,
});
Response
5.43528191708623