-
Notifications
You must be signed in to change notification settings - Fork 809
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* adding the synapse strategy * checksummed addresses * adding multichain functionality * reducing the number of calls to a single chain * Update synapse strategy to handle network-specific requests --------- Co-authored-by: Chaitanya <[email protected]>
- Loading branch information
1 parent
f0f7a59
commit 9e4e036
Showing
5 changed files
with
273 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
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,64 @@ | ||
# Synapse Strategy | ||
|
||
This strategy calculates voting power by combining two components: | ||
1. SYN token balance | ||
2. Locked SYN tokens in the staking contract | ||
|
||
## Overview | ||
|
||
The strategy sums up: | ||
- The regular SYN token balance (`balanceOf`) | ||
- The locked amount in the staking contract (`lockedAmountOf`) | ||
|
||
## Parameters | ||
|
||
Here is an example of parameters: | ||
|
||
```json | ||
{ | ||
"symbol": "SYN", | ||
"tokenAddress": "0x0f2D719407FdBeFF09D87557AbB7232601FD9F29", | ||
"stakingAddress": "0x00000010cd90b3688d249d84c616de3a0343e60f", | ||
"decimals": 18 | ||
} | ||
``` | ||
|
||
### Parameter Details | ||
|
||
- `symbol`: Token symbol (default: "SYN") | ||
- `tokenAddress`: The SYN token contract address for the specific network | ||
- `stakingAddress`: The staking contract address (default: 0x00000010cd90b3688d249d84c616de3a0343e60f) | ||
- `decimals`: Token decimals (default: 18) | ||
|
||
## Networks & Addresses | ||
|
||
The strategy works across multiple networks. Here are the SYN token addresses for each supported chain: | ||
|
||
- Ethereum: `0x0f2D719407FdBeFF09D87557AbB7232601FD9F29` | ||
- Arbitrum: `0x080f6aed32fc474dd5717105dba5ea57268f46eb` | ||
- Aurora: `0xd80d8688b02B3FD3afb81cDb124F188BB5aD0445` | ||
- Avalanche: `0x1f1E7c893855525b303f99bDF5c3c05Be09ca251` | ||
- Base: `0x432036208d2717394d2614d6697c46DF3Ed69540` | ||
- Blast: `0x9592f08387134e218327E6E8423400eb845EdE0E` | ||
- Boba: `0xb554A55358fF0382Fb21F0a478C3546d1106Be8c` | ||
- BSC: `0xa4080f1778e69467e905b8d6f72f6e441f9e9484` | ||
- Canto: `0x555982d2E211745b96736665e19D9308B615F78e` | ||
- Cronos: `0xFD0F80899983b8D46152aa1717D76cba71a31616` | ||
- DFK Chain: `0xB6b5C854a8f71939556d4f3a2e5829F7FcC1bf2A` | ||
- Fantom: `0xE55e19Fb4F2D85af758950957714292DAC1e25B2` | ||
- Harmony: `0xE55e19Fb4F2D85af758950957714292DAC1e25B2` | ||
- Metis: `0x67c10c397dd0ba417329543c1a40eb48aaa7cd00` | ||
- Moonbeam: `0xF44938b0125A6662f9536281aD2CD6c499F22004` | ||
- Moonriver: `0xd80d8688b02B3FD3afb81cDb124F188BB5aD0445` | ||
- Optimism: `0x5A5fFf6F753d7C11A56A52FE47a177a87e431655` | ||
- Polygon: `0xf8f9efc0db77d8881500bb06ff5d6abc3070e695` | ||
|
||
Note: Staking functionality is only available on Ethereum, Arbitrum, Avalanche, Optimism, BSC, Polygon, and Base networks. | ||
|
||
## Example | ||
|
||
If a user has: | ||
- 100 SYN tokens in their wallet | ||
- 50 SYN tokens locked in staking | ||
|
||
Their total voting power would be 150 SYN tokens. |
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,19 @@ | ||
[ | ||
{ | ||
"name": "Example Query", | ||
"strategy": { | ||
"name": "synapse", | ||
"params": { | ||
"symbol": "SYN", | ||
"decimals": 18 | ||
} | ||
}, | ||
"network": "1", | ||
"addresses": [ | ||
"0xBdfbc9f2A873E07599CafA9BC18F80D4e07D7832", | ||
"0x20D84F5e6533b48cdC8E557eD50d7825eBA77766", | ||
"0xb73AcB429Ba868984c0236bdf940D4FE1E643F27" | ||
], | ||
"snapshot": 21622022 | ||
} | ||
] |
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,164 @@ | ||
import { formatUnits } from '@ethersproject/units'; | ||
import { BigNumber } from '@ethersproject/bignumber'; | ||
import { getAddress } from '@ethersproject/address'; | ||
import { Multicaller } from '../../utils'; | ||
|
||
export const author = 'defi-moses'; | ||
export const version = '0.2.0'; | ||
|
||
const SUPPORTED_CHAINS = { | ||
'1': { | ||
tokenAddress: '0x0f2D719407FdBeFF09D87557AbB7232601FD9F29', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'42161': { | ||
// Arbitrum | ||
tokenAddress: '0x080f6aed32fc474dd5717105dba5ea57268f46eb', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'43114': { | ||
// Avalanche | ||
tokenAddress: '0x1f1E7c893855525b303f99bDF5c3c05Be09ca251', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'10': { | ||
// Optimism | ||
tokenAddress: '0x5A5fFf6F753d7C11A56A52FE47a177a87e431655', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'56': { | ||
// BSC | ||
tokenAddress: '0xa4080f1778e69467e905b8d6f72f6e441f9e9484', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'137': { | ||
// Polygon | ||
tokenAddress: '0xf8f9efc0db77d8881500bb06ff5d6abc3070e695', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
}, | ||
'8453': { | ||
// Base | ||
tokenAddress: '0x432036208d2717394d2614d6697c46DF3Ed69540', | ||
stakingAddress: '0x00000010cd90b3688d249d84c616de3a0343e60f' | ||
} | ||
}; | ||
|
||
const tokenAbi = [ | ||
'function balanceOf(address) view returns (uint256)', | ||
'function decimals() view returns (uint8)' | ||
]; | ||
|
||
const stakingAbi = [ | ||
'function lockedAmountOf(address account) view returns (uint256)', | ||
'function balanceOf(address account) view returns (uint256)' // Backup method | ||
]; | ||
|
||
interface MulticallResult { | ||
[key: string]: { | ||
[address: string]: BigNumber; | ||
}; | ||
} | ||
|
||
async function getChainBalance( | ||
network: string, | ||
provider, | ||
addresses: string[], | ||
options, | ||
snapshot | ||
): Promise<Record<string, number>> { | ||
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; | ||
const chainConfig = SUPPORTED_CHAINS[network]; | ||
if (!chainConfig) { | ||
throw new Error(`Network ${network} not supported`); | ||
} | ||
|
||
try { | ||
const multi = new Multicaller(network, provider, tokenAbi, { blockTag }); | ||
const checksumAddresses = addresses.map(getAddress); | ||
|
||
checksumAddresses.forEach((address) => { | ||
multi.call(`token.${address}`, chainConfig.tokenAddress, 'balanceOf', [ | ||
address | ||
]); | ||
}); | ||
|
||
const result = (await multi.execute()) as MulticallResult; | ||
const stakingMulti = new Multicaller(network, provider, stakingAbi, { | ||
blockTag | ||
}); | ||
let stakingResult: MulticallResult = { staking: {} }; | ||
|
||
try { | ||
checksumAddresses.forEach((address) => { | ||
stakingMulti.call( | ||
`staking.${address}`, | ||
chainConfig.stakingAddress, | ||
'lockedAmountOf', | ||
[address] | ||
); | ||
}); | ||
stakingResult = await stakingMulti.execute(); | ||
} catch (error) { | ||
const balanceMulti = new Multicaller(network, provider, stakingAbi, { | ||
blockTag | ||
}); | ||
checksumAddresses.forEach((address) => { | ||
balanceMulti.call( | ||
`staking.${address}`, | ||
chainConfig.stakingAddress, | ||
'balanceOf', | ||
[address] | ||
); | ||
}); | ||
|
||
try { | ||
stakingResult = await balanceMulti.execute(); | ||
} catch (error) { | ||
console.warn(`Failed to fetch staking balances for network ${network}`); | ||
} | ||
} | ||
|
||
return Object.fromEntries( | ||
checksumAddresses.map((address) => { | ||
const tokenBalance = result.token?.[address] || BigNumber.from(0); | ||
const stakedBalance = | ||
stakingResult.staking?.[address] || BigNumber.from(0); | ||
|
||
const formattedTokenBalance = parseFloat( | ||
formatUnits(tokenBalance, options.decimals) | ||
); | ||
const formattedStakedBalance = parseFloat( | ||
formatUnits(stakedBalance, options.decimals) | ||
); | ||
|
||
return [address, formattedTokenBalance + formattedStakedBalance]; | ||
}) | ||
); | ||
} catch (error) { | ||
throw new Error(`Error fetching balances for network ${network}: ${error}`); | ||
} | ||
} | ||
|
||
export async function strategy( | ||
space, | ||
network, | ||
provider, | ||
addresses, | ||
options, | ||
snapshot | ||
): Promise<Record<string, number>> { | ||
// Check if the selected network is supported | ||
if (!SUPPORTED_CHAINS[network]) { | ||
throw new Error(`Network ${network} not supported`); | ||
} | ||
|
||
const result = await getChainBalance( | ||
network, | ||
provider, | ||
addresses, | ||
options, | ||
snapshot | ||
); | ||
|
||
return result; | ||
} |
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,23 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"$ref": "#/definitions/Strategy", | ||
"definitions": { | ||
"Strategy": { | ||
"title": "Strategy", | ||
"type": "object", | ||
"properties": { | ||
"symbol": { | ||
"type": ["string", "null"], | ||
"title": "Symbol", | ||
"default": "SYN" | ||
}, | ||
"decimals": { | ||
"type": "number", | ||
"title": "Decimals", | ||
"default": 18 | ||
} | ||
}, | ||
"required": ["decimals"] | ||
} | ||
} | ||
} |