-
Notifications
You must be signed in to change notification settings - Fork 550
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Symmetry x Realms Integration (#2418)
Co-authored-by: bob <[email protected]> Co-authored-by: 0xbridges <[email protected]>
- Loading branch information
1 parent
4372c36
commit 2a5d38c
Showing
13 changed files
with
1,485 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
import { Connection } from "@solana/web3.js" | ||
import { BasketsSDK } from "@symmetry-hq/baskets-sdk" | ||
import BufferLayout from 'buffer-layout' | ||
|
||
const targetCompositionLayout = BufferLayout.seq( | ||
BufferLayout.u8(), | ||
15, | ||
'targetComposition' | ||
); | ||
const targetWeightsLayout = BufferLayout.seq( | ||
BufferLayout.u32(), | ||
15, | ||
'targetWeights' | ||
); | ||
const rebalanceAndLpLayout = BufferLayout.seq( | ||
BufferLayout.u8(), | ||
2, | ||
'rebalanceAndLp' | ||
); | ||
|
||
export const SYMMETRY_V2_INSTRUCTIONS = { | ||
"2KehYt3KsEQR53jYcxjbQp2d2kCp4AkuQW68atufRwSr": { | ||
78: { | ||
name: 'Symmetry: Withdraw from Basket', | ||
accounts: [ | ||
{ name: 'Withdrawer' }, | ||
{ name: 'Basket Address' }, | ||
{ name: 'Symmetry PDA' }, | ||
{ name: 'Withdraw Temporary State Account' }, | ||
{ name: 'Withdrawer Basket Token Account' }, | ||
{ name: 'Basket Token Mint' }, | ||
{ name: 'System Program' }, | ||
{ name: 'Token Program' }, | ||
{ name: 'Rent Program' }, | ||
{ name: 'Account' }, | ||
], | ||
getDataUI: async (connection: Connection, data: Uint8Array) => { | ||
|
||
//@ts-ignore | ||
const { amount, rebalance } = BufferLayout.struct([ | ||
BufferLayout.nu64('amount'), | ||
BufferLayout.nu64('rebalance') | ||
]).decode(Buffer.from(data), 8) | ||
|
||
return ( | ||
<> | ||
<p>Withdraw Amount: {amount / 10**6}</p> | ||
<p>Rebalance to USDC: {rebalance === 2 ? 'Yes' : 'No - Withdraw Assets Directly'}</p> | ||
</> | ||
) | ||
}, | ||
}, | ||
251: { | ||
name: 'Symmetry: Deposit into Basket', | ||
accounts: [ | ||
{ name: 'Depositor' }, | ||
{ name: 'Basket Address' }, | ||
{ name: 'Basket Token Mint' }, | ||
{ name: 'Symmetry Token List' }, | ||
{ name: 'Symmetry PDA' }, | ||
{ name: 'USDC PDA Account' }, | ||
{ name: 'Depositor USDC Account' }, | ||
{ name: 'Manager USDC Account' }, | ||
{ name: 'Symmetry Fee Account' }, | ||
{ name: 'Host Platform USDC Account' }, | ||
{ name: 'Depositor Basket Token Account' }, | ||
{ name: 'Temporary State Account for Deposit' }, | ||
{ name: 'System Program' }, | ||
{ name: 'Token Program' }, | ||
{ name: 'Rent' }, | ||
{ name: 'Associated Token Program' }, | ||
{ name: 'Account' }, | ||
], | ||
getDataUI: async (connection: Connection, data: Uint8Array) => { | ||
|
||
//@ts-ignore | ||
const { amount, rebalance } = BufferLayout.struct([ | ||
BufferLayout.nu64('amount') | ||
]).decode(Buffer.from(data), 8) | ||
|
||
return ( | ||
<> | ||
<p>USDC Deposit Amount: {amount / 10**6}</p> | ||
</> | ||
) | ||
}, | ||
}, | ||
38: { | ||
name: 'Symmetry: Edit Basket', | ||
accounts: [ | ||
{ name: 'Basket Manager' }, | ||
{ name: 'Basket Address' }, | ||
{ name: 'Symmetry Token List' }, | ||
{ name: 'Manager Fee Receiver Address' }, | ||
], | ||
getDataUI: async (connection: Connection, data: Uint8Array) => { | ||
|
||
//@ts-ignore | ||
const { managerFee, rebalanceInterval, rebalanceThreshold, rebalanceSlippage, lpOffsetThreshold, rebalanceAndLp, numOfTokens, targetComposition, targetWeights } = BufferLayout.struct([ | ||
BufferLayout.u16('managerFee'), | ||
BufferLayout.nu64('rebalanceInterval'), | ||
BufferLayout.u16('rebalanceThreshold'), | ||
BufferLayout.u16('rebalanceSlippage'), | ||
BufferLayout.u16('lpOffsetThreshold'), | ||
rebalanceAndLpLayout, | ||
BufferLayout.u8('numOfTokens'), | ||
targetCompositionLayout, | ||
targetWeightsLayout, | ||
]).decode(Buffer.from(data), 8) | ||
|
||
const basketsSdk = await BasketsSDK.init(connection); | ||
const tokenData = basketsSdk.getTokenListData(); | ||
let usdcIncluded = false; | ||
let totalWeight = 0; targetWeights.map(w => totalWeight += w); | ||
|
||
let composition = targetComposition.map((tokenId, i) => { | ||
let token = tokenData.filter(x => x.id == tokenId)[0] | ||
if(token.id === 0) { | ||
if(!usdcIncluded) { | ||
usdcIncluded = true; | ||
return { | ||
...token, | ||
weight: targetWeights[i] / totalWeight * 100 | ||
} | ||
} | ||
} else { | ||
return { | ||
...token, | ||
weight: targetWeights[i] / totalWeight * 100 | ||
} | ||
} | ||
}).filter(x => x != null) | ||
|
||
return ( | ||
<> | ||
<p>Manager Fee: {managerFee / 100}%</p> | ||
<p>Rebalance Check Interval: {rebalanceInterval / 60} minutes</p> | ||
<p>Rebalance Trigger Threshold: {rebalanceThreshold / 100}%</p> | ||
<p>Maximum Slippage Allowed During Rebalancing: {rebalanceSlippage / 100}%</p> | ||
<p>Liquidity Provision Threshold: {lpOffsetThreshold / 100}%</p> | ||
<p>Rebalancing Enabled: {rebalanceAndLp[0] === 0 ? "Yes" : "No"}</p> | ||
<p>Liquidity Provision Enabled: {rebalanceAndLp[1] === 0 ? "No" : "Yes"}</p> | ||
<p>Basket Composition Size: {numOfTokens} Tokens</p> | ||
<div className="text-sm"> | ||
Basket Composition: | ||
{ | ||
composition.map((compItem, i) => { | ||
return <div className="flex items-center"> | ||
<p className="text-sm">{compItem.weight}% {compItem.symbol} <a className="text-blue" target="_blank" href={"https://solscan.io/token/"+compItem.tokenMint}>({compItem.tokenMint.slice(0,6)}...)</a></p> | ||
</div> | ||
}) | ||
} | ||
</div> | ||
</> | ||
) | ||
}, | ||
}, | ||
47: { | ||
name: 'Symmetry: Create Basket', | ||
accounts: [ | ||
{ name: 'Manager' }, | ||
{ name: 'Token List' }, | ||
{ name: 'Basket Address' }, | ||
{ name: 'Symmetry PDA' }, | ||
{ name: 'Basket Token Mint' }, | ||
{ name: 'Symmetry Fee Collector' }, | ||
{ name: 'Metadata Account' }, | ||
{ name: 'Metadata Program' }, | ||
{ name: 'System Program' }, | ||
{ name: 'Token Program' }, | ||
{ name: 'Rent' }, | ||
{ name: 'Host Platform' }, | ||
{ name: 'Fee Collector Address' }, | ||
{ name: 'Account' }, | ||
], | ||
getDataUI: async (connection: Connection, data: Uint8Array) => { | ||
//@ts-ignore | ||
const { managerFee, hostFee, basketType,rebalanceInterval, rebalanceThreshold, rebalanceSlippage, lpOffsetThreshold, rebalanceAndLp, numOfTokens, targetComposition, targetWeights, } = BufferLayout.struct([ | ||
BufferLayout.u16('managerFee'), | ||
BufferLayout.u16('hostFee'), | ||
BufferLayout.u8('basketType'), | ||
BufferLayout.nu64('rebalanceInterval'), | ||
BufferLayout.u16('rebalanceThreshold'), | ||
BufferLayout.u16('rebalanceSlippage'), | ||
BufferLayout.u16('lpOffsetThreshold'), | ||
rebalanceAndLpLayout, | ||
BufferLayout.u8('numOfTokens'), | ||
targetCompositionLayout, | ||
targetWeightsLayout, | ||
]).decode(Buffer.from(data), 8) | ||
|
||
|
||
let basketsSdk = await BasketsSDK.init(connection); | ||
let tokenData = basketsSdk.getTokenListData(); | ||
let usdcIncluded = false; | ||
let totalWeight = 0; targetWeights.map(w => totalWeight += w); | ||
|
||
let composition = targetComposition.map((tokenId, i) => { | ||
let token = tokenData.filter(x => x.id == tokenId)[0] | ||
if(token.id === 0) { | ||
if(!usdcIncluded) { | ||
usdcIncluded = true; | ||
return { | ||
...token, | ||
weight: targetWeights[i] / totalWeight * 100 | ||
} | ||
} | ||
} else | ||
return { | ||
...token, | ||
weight: targetWeights[i] / totalWeight * 100 | ||
} | ||
}).filter(x => x != null) | ||
|
||
return ( | ||
<> | ||
<p>Manager Fee: {managerFee / 100}%</p> | ||
<p>Host Platform Fee: {hostFee / 100}%</p> | ||
<p>Basket Type: {basketType === 0 ? "Bundle" : basketType === 1 ? "Portfolio" : "Private"}</p> | ||
<p>Rebalance Check Interval: {rebalanceInterval / 60} minutes</p> | ||
<p>Rebalance Trigger Threshold: {rebalanceThreshold / 100}%</p> | ||
<p>Maximum Slippage Allowed During Rebalancing: {rebalanceSlippage / 100}%</p> | ||
<p>Liquidity Provision Threshold: {lpOffsetThreshold / 100}%</p> | ||
<p>Rebalancing Enabled: {rebalanceAndLp[0] === 0 ? "Yes" : "No"}</p> | ||
<p>Liquidity Provision Enabled: {rebalanceAndLp[1] === 0 ? "No" : "Yes"}</p> | ||
<p>Basket Composition Size: {numOfTokens} Tokens</p> | ||
<div className="text-sm"> | ||
Basket Composition: | ||
{ | ||
composition.map((compItem, i) => { | ||
return <div className="flex items-center"> | ||
<p className="text-sm">{compItem.weight}% {compItem.symbol} <a className="text-blue" target="_blank" href={"https://solscan.io/token/"+compItem.tokenMint}>({compItem.tokenMint.slice(0,6)}...)</a></p> | ||
</div> | ||
}) | ||
} | ||
</div> | ||
</> | ||
) | ||
}, | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
pages/dao/[symbol]/proposal/components/instructions/Symmetry/AddTokenToBasketModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import Modal from "@components/Modal" | ||
import Input from "@components/inputs/Input" | ||
import { useEffect, useState } from "react" | ||
|
||
|
||
const AddTokenToBasketModal = ({ | ||
open, | ||
onClose, | ||
supportedTokens, | ||
onSelect | ||
}:{ | ||
open: boolean, | ||
onClose: any, | ||
supportedTokens: any, | ||
onSelect: any | ||
}) => { | ||
const [allTokens, setAllTokens] = useState(supportedTokens); | ||
const [searchValue, setSearchValue] = useState(''); | ||
|
||
useEffect(() => { | ||
if(searchValue.length > 0){ | ||
const filteredTokens = supportedTokens.filter((token: any) => { | ||
return token.name.toLowerCase().includes(searchValue.toLowerCase()) || token.symbol.toLowerCase().includes(searchValue.toLowerCase()) | ||
}) | ||
setAllTokens(filteredTokens) | ||
} else { | ||
setAllTokens(supportedTokens) | ||
} | ||
|
||
}, [searchValue, supportedTokens]) | ||
return <> | ||
{ | ||
open && | ||
<Modal | ||
isOpen={open} | ||
onClose={() => onClose()} | ||
> | ||
<h2 className="text-fgd-1 mb-8 text-center">Select a Token</h2> | ||
<input className="w-full p-2 text-lg rounded-md bg-bkg-1 text-fgd-1 text-center" placeholder="Search for tokens" value={searchValue} onChange={(e) => setSearchValue(e.target.value)} type="text" /> | ||
<div className='flex flex-col max-h-64 mt-2 overflow-scroll gap-2'> | ||
{ | ||
allTokens.map((token, i) => { | ||
return ( | ||
<div onClick={() => onSelect(token)} key={i} className='flex w-full gap-2 items-center justify-between bg-bkg-1 hover:bg-bkg-3 cursor-pointer p-2 rounded-md'> | ||
<div className="flex flex-col"> | ||
<p className='text-xs text-fgd-3'> | ||
{ | ||
token.name | ||
} | ||
</p> | ||
<p className='text-sm font-bold'> | ||
{ | ||
token.symbol | ||
} | ||
</p> | ||
</div> | ||
<a rel="noreferrer" href={`https://solscan.io/token/${token.tokenMint}`} target="_blank" className="text-xs text-blue-500 underline"> | ||
{ | ||
token.tokenMint.slice(0, 6) + '...' + token.tokenMint.slice(-6) | ||
} | ||
</a> | ||
</div> | ||
) | ||
}) | ||
} | ||
</div> | ||
</Modal> | ||
} | ||
</> | ||
|
||
} | ||
|
||
export default AddTokenToBasketModal; |
Oops, something went wrong.