Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic balances with mock rewards and distribution #299

Merged
merged 69 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
f817d15
Clean up deposit flow
shanejearley Mar 15, 2023
5620c7f
Add total stake
shanejearley Mar 16, 2023
e5931bb
Add validator, pool, and operator checks to tests
shanejearley Mar 16, 2023
4e79e79
Add rewards (unrevised)
shanejearley Mar 17, 2023
389a68b
Change openDeposits to unstakedDeposits
shanejearley Mar 17, 2023
15fec3d
Add rewards check to tests
shanejearley Mar 17, 2023
feb4451
Add constant time rewards distribution
shanejearley Mar 20, 2023
fee6411
Add auto compound option
shanejearley Mar 22, 2023
ca0d636
Move pool distribution to private internal method
shanejearley Mar 23, 2023
986015d
Add untested compounding balance
shanejearley Mar 23, 2023
8ba9736
Add comment to temporarily optional autoCompound param
shanejearley Mar 23, 2023
cf724dc
Depend mock rewards on validator count
shanejearley Mar 23, 2023
f10327d
Update scripts and tests to handle compound flag
shanejearley Mar 28, 2023
ac06866
Add mock rewards to dev script
shanejearley Mar 28, 2023
a4cde2c
Rename distributionScale to scaleFactor
shanejearley Mar 28, 2023
87bef48
Change ethereum compile command name to build
shanejearley Mar 28, 2023
2a6a6bb
Add uni v3 core back to contract dependencies
shanejearley Mar 28, 2023
1ead65f
Remove leaked vscode setting
shanejearley Mar 28, 2023
baaac1e
Change ethereum node command name
shanejearley Mar 28, 2023
01a170b
Add simulation flag to run fixture with dev
shanejearley Mar 29, 2023
f119dc7
Update compound test and log simulation results
shanejearley Mar 29, 2023
437fa81
Make compound contract default
shanejearley Mar 30, 2023
f90eed8
Update dev options
shanejearley Mar 30, 2023
8c9c2f1
Update npm flags
shanejearley Mar 30, 2023
ceda24b
Merge branch 'develop' into feature/balances
shanejearley Mar 30, 2023
782d83f
Remove ghost common directories
shanejearley Mar 30, 2023
069ee66
Add simulation flag to README
shanejearley Mar 30, 2023
fc253f6
Update tests to check total balances
shanejearley Mar 30, 2023
3464662
Update classic param
shanejearley Mar 30, 2023
6dd6efc
Update dev simulation blocks per reward
shanejearley Mar 30, 2023
35126b1
Merge branch 'develop' into feature/balances
shanejearley Mar 30, 2023
5b13065
Add multiple stakes and withdrawals (classic mode tbd)
shanejearley Mar 31, 2023
9d80775
Change getOpenPoolIds to getReadyPoolIds
shanejearley Mar 31, 2023
1e10127
Add withdraw warning
shanejearley Mar 31, 2023
6a438b8
Add settlement comment
shanejearley Mar 31, 2023
90eba99
Add amount check to withdraw
shanejearley Mar 31, 2023
d9b284a
Add withdraw test
shanejearley Mar 31, 2023
c334eaa
Change revert to require
shanejearley Mar 31, 2023
c7d2af7
Add ready validators requirement to stakePool
shanejearley Mar 31, 2023
a90b984
Remove classic mode
shanejearley Apr 3, 2023
271ab66
Add compounding explanation
shanejearley Apr 4, 2023
1614df2
Fix math block expression
shanejearley Apr 4, 2023
31ce2b1
Remove docs from gitignore
shanejearley Apr 4, 2023
5f7825b
Add initial notes on oracles and withdrawals
shanejearley Apr 4, 2023
af42e95
Add initial dkg notes
shanejearley Apr 4, 2023
2698a71
Fix table
shanejearley Apr 4, 2023
93a4aa2
Add initial notes on fees
shanejearley Apr 4, 2023
96186ce
Update fee notes
shanejearley Apr 4, 2023
20feec5
Change block statements to single line
shanejearley Apr 4, 2023
b651167
Switch variable description order
shanejearley Apr 4, 2023
60107fb
Update userStake0 variable description
shanejearley Apr 4, 2023
055277d
Update oracle explanation
shanejearley Apr 4, 2023
cdc9045
Add staking diagram
shanejearley Apr 4, 2023
fdf09da
Update SSV contracts description
shanejearley Apr 4, 2023
5f9a777
Update fee contract method reference
shanejearley Apr 5, 2023
92171db
Remove section layer in README
shanejearley Apr 5, 2023
07afa60
Clean up calculation steps
shanejearley Apr 5, 2023
6c1b393
Move config note
shanejearley Apr 5, 2023
e5de506
Subgraph chainlink nodes
shanejearley Apr 5, 2023
695e77b
Add contracts to subgraph
shanejearley Apr 5, 2023
10c7ec1
Fix ssv contract relationship
shanejearley Apr 5, 2023
2c2a33e
Change graph node shapes
shanejearley Apr 5, 2023
58b92a2
Update main readme
shanejearley Apr 5, 2023
3d6feb2
Adapt to v1 contract interface and aggregate data
ccali11 Apr 5, 2023
0389d1d
Update front-end User type
ccali11 Apr 5, 2023
72d38ce
Organize wallet methods
ccali11 Apr 5, 2023
d1354c5
Rollback to simple upkeep
shanejearley Apr 5, 2023
d128e7d
Merge pull request #305 from consensusnetworks/enhancement/contracts-…
ccali11 Apr 5, 2023
12fa735
Update ssv composable with Balance(uint256) interface
ccali11 Apr 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ npm run dev
| `--fork` | Which live Ethereum network to fork locally | goerli | --fork=mainnet |
| `--mock` | Whether to mock services | true | --mock=false |
| `--network` | Which live Ethereum network to use | goerli | --network=mainnet |
| `--simulation` | Whether to run contract simulation fixture | false | --simulation |

**Example commands:**

Expand Down Expand Up @@ -106,18 +107,18 @@ npm run dev:landing

### Contracts

Ethereum contracts are configured with a Hardhat development environment in the [contracts/ethereum/hardhat.config.ts](contracts/ethereum/hardhat.config.ts) file.
Ethereum contracts are configured with a Hardhat development environment in the [contracts/ethereum/hardhat.config.ts](contracts/ethereum/hardhat.config.ts) file. Read more about `@casimir/ethereum` staking [here](contracts/ethereum/README.md). Below are some helpful commands for developing on or with the contracts.

Run all contract tests.

```zsh
npm run test:ethereum
```

Compile the contracts in [contracts/ethereum](contracts/ethereum).
Build the contracts in [contracts/ssv](contracts/ssv).

```zsh
npm run task:compile --workspace @casimir/ethereum
npm run build --workspace @casimir/ethereum
```

Deploy a contract, specifically [contracts/ethereum/src/SSVManager.sol](contracts/ethereum/src/SSVManager.sol) with [contracts/ethereum/scripts/ssv.deploy.ts](contracts/ethereum/deploy/ssv.deploy.ts).
Expand Down
37 changes: 20 additions & 17 deletions apps/web/src/components/Wallet.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
<template>
<div>
<div class="flex">
<button @click="getCurrentBalance()">
Get Balance New
</button>
<button @click="getUserBalance(selectedAddress)">
Get Balance Old
<button @click="getUserBalance()">
Get User Balance
</button>
</div>
<div class="network-div w-100 mx-8">
Expand Down Expand Up @@ -43,21 +40,28 @@
</button>
</div>
<div class="staking-container">
<button @click="getUserPools(selectedAddress)">
What do I have staked where?
<button @click="getPools(selectedAddress, 'ready')">
Get ready user pools
</button>
<button @click="getPools(selectedAddress, 'stake')">
Get staked user pools
</button>
<ul>
<!-- <ul>
<li
v-for="(pool, index) in user?.pools"
v-for="(account, index) in user?.accounts"
:key="index"
>
<p>Pool ID: #{{ pool.id }}</p>
<p>Your Stake: {{ pool.userStake }} ETH</p>
<p>Your Rewards: {{ pool.userRewards }} ETH</p>
<p>Total Stake: {{ pool.stake }} ETH</p>
<p>Total Rewards: {{ pool.rewards }} ETH</p>
<ul v-for="(pool, index) in account"
:key="index"
>
<li>Pool ID: #{{ pool?.id }}</li>
<li>Your Stake: {{ pool?.userStake }} ETH</li>
<li>Your Rewards: {{ pool?.userRewards }} ETH</li>
<li>Total Stake: {{ pool?.stake }} ETH</li>
<li>Total Rewards: {{ pool?.rewards }} ETH</li>
</ul>
</li>
</ul>
</ul> -->
<input
v-model="amountToStake"
placeholder="Amount to Stake"
Expand Down Expand Up @@ -214,12 +218,11 @@ const {
sendTransaction,
signMessage,
getUserBalance,
getCurrentBalance,
removeConnectedAccount,
switchNetwork
} = useWallet()

const { deposit, getUserPools } = useSSV()
const { deposit, getPools } = useSSV()

watchEffect(() => {
if (selectedProvider.value === 'MetaMask') {
Expand Down
46 changes: 30 additions & 16 deletions apps/web/src/composables/ssv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import useEthers from './ethers'
import useLedger from './ledger'
import useTrezor from './trezor'
import useWalletConnect from './walletConnect'
import { Pool, ProviderString } from '@casimir/types'
import { Account, Pool, ProviderString } from '@casimir/types'
import { ReadyOrStakeString } from '../interfaces'

/** SSV Manager contract */
let ssvManager: SSVManager
Expand Down Expand Up @@ -64,23 +65,28 @@ export default function useSSV() {
return feesRounded
}

async function getUserPools(userAddress: string): Promise<Pool[]> {
async function getPools(address: string, readyOrStake: ReadyOrStakeString): Promise<Pool[]> {
const { user } = useUsers()
const provider = new ethers.providers.JsonRpcProvider(ethereumURL)
const ssvManagerProvider = ssvManager.connect(provider)
const userPoolsIds = await ssvManagerProvider.getUserPoolIds(userAddress)
return await Promise.all(userPoolsIds.map(async (poolId: number) => {
const { balance, userBalance } = await ssvManagerProvider.getPoolUserDetails(poolId, userAddress)

const userStake = await ssvManagerProvider.getUserStake(address) // to get user's stake balance
const poolStake = await ssvManagerProvider.getStake() // to get total stake balance
const poolIds = readyOrStake === 'ready' ? await ssvManagerProvider.getReadyPoolIds() : await ssvManagerProvider.getStakedPoolIds() // to get ready (open) pool IDs OR to get staked (active) pool IDs

return await Promise.all(poolIds.map(async (poolId: number) => {
const { deposits, operatorIds, validatorPublicKey } = await ssvManagerProvider.getPool(poolId)

// TODO: Decide when/how to get rewards/userRewards
let pool: Pool = {
id: poolId,
rewards: ethers.utils.formatEther(balance.rewards),
stake: ethers.utils.formatEther(balance.stake),
userRewards: ethers.utils.formatEther(userBalance.rewards),
userStake: ethers.utils.formatEther(userBalance.stake)
rewards: ethers.utils.formatEther(poolStake),
stake: ethers.utils.formatEther(poolStake),
userRewards: ethers.utils.formatEther(userStake),
userStake: ethers.utils.formatEther(userStake)
}

const validatorPublicKey = await ssvManagerProvider.getPoolValidatorPublicKey(poolId) // Public key bytes (i.e., 0x..)
if (validatorPublicKey) {

// Validator data from beaconcha.in hardcoded for now
// const response = await fetch(`https://prater.beaconcha.in/api/v1/validator/${validatorPublicKey}`)
// const { data } = await response.json()
Expand All @@ -92,9 +98,12 @@ export default function useSSV() {
apr: '0%', // See issue #205 https://github.com/consensusnetworks/casimir/issues/205#issuecomment-1338142532
url: `https://prater.beaconcha.in/validator/${validatorPublicKey}`
}
const operatorIds = await ssvManagerProvider.getPoolOperatorIds(poolId) // Operator ID uint32[] (i.e., [1, 2, 3, 4])


// TODO: Replace with less hardcoded network call?
const operators = await Promise.all(operatorIds.map(async (operatorId: number) => {
const response = await fetch(`https://api.ssv.network/api/v3/operators/${operatorId}`)
const network = 'prater'
const response = await fetch(`https://api.ssv.network/api/v3/${network}/operators/${operatorId}`)
const { performance } = await response.json()
return {
id: operatorId,
Expand All @@ -111,12 +120,17 @@ export default function useSSV() {
}
}

const { user } = useUsers()
user.value?.pools.push(pool)
if (readyOrStake === 'stake') {
user.value?.accounts.forEach((account: Account) => {
if (account.address === address) {
account.pools ? account.pools.push(pool) : account.pools = [pool]
}
})
}

return pool
}))
}

return { ssvManager, deposit, getDepositFees, getUserPools }
return { ssvManager, deposit, getDepositFees, getPools }
}
153 changes: 77 additions & 76 deletions apps/web/src/composables/users.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { onMounted, ref } from 'vue'
import { AddAccountOptions, ProviderString, RemoveAccountOptions, User } from '@casimir/types'
import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts } from '@casimir/types'
import { ethers } from 'ethers'
import useEnvironment from '@/composables/environment'
import useSSV from '@/composables/ssv'
Expand All @@ -8,73 +8,73 @@ import useWallet from '@/composables/wallet'
const { usersBaseURL, ethereumURL } = useEnvironment()

// 0xd557a5745d4560B24D36A68b52351ffF9c86A212
// const user = ref<User>()
const user = ref(
{
address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(),
accounts: [
{
address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(),
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'MetaMask'
},
{
address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'CoinbaseWallet'
},
{
address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'CoinbaseWallet'
},
{
address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'CoinbaseWallet'
},
{
address: '0x8222Ef172A2117D1C4739E35234E097630D94376'.toLowerCase(),
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'Ledger'
},
{
address: '0x8222Ef172A2117D1C4739E35234E097630D94377'.toLowerCase(), // Fake address
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'Trezor'
},
{
address: '0x8222Ef172A2117D1C4739E35234E097630D94378'.toLowerCase(), // Fake address
currency: 'ETH',
balance: '1000000000000000000',
balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
roi: 0.25,
walletProvider: 'WalletConnect'
},
],
nonce: '1234567890',
pools: []
}
)
const { ssvManager } = useSSV()
const user = ref<UserWithAccounts>()
// const user = ref(
// {
// address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(),
// accounts: [
// {
// address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(),
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'MetaMask'
// },
// {
// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'CoinbaseWallet'
// },
// {
// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'CoinbaseWallet'
// },
// {
// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(),
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'CoinbaseWallet'
// },
// {
// address: '0x8222Ef172A2117D1C4739E35234E097630D94376'.toLowerCase(),
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'Ledger'
// },
// {
// address: '0x8222Ef172A2117D1C4739E35234E097630D94377'.toLowerCase(), // Fake address
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'Trezor'
// },
// {
// address: '0x8222Ef172A2117D1C4739E35234E097630D94378'.toLowerCase(), // Fake address
// currency: 'ETH',
// balance: '1000000000000000000',
// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }],
// roi: 0.25,
// walletProvider: 'WalletConnect'
// },
// ],
// nonce: '1234567890',
// pools: []
// }
// )
const { ssvManager, getPools } = useSSV()

export default function useUsers () {

Expand All @@ -90,39 +90,40 @@ export default function useUsers () {
return user
}

function setUser(newUser?: User) {
function setUser(newUser?: UserWithAccounts) {
user.value = newUser
}

// Todo filter for events for user addresses
function subscribeToUserEvents() {
const { getUserBalance, getUserPools } = useWallet()
const { getUserBalance } = useWallet()
const provider = new ethers.providers.JsonRpcProvider(ethereumURL)

const validatorInitFilter = {
address: ssvManager.address,
topics: [
ethers.utils.id('ValidatorActivated(uint32,uint32[],string)')
ethers.utils.id('PoolStaked(uint32,bytes,uint32[])'),
// ethers.utils.id('ManagerDistribution(uint32,bytes,uint32[])'), // TODO: Make sure to query for past events on page load (Fetch and then subscribe)
]
}
ssvManager.connect(provider).on(validatorInitFilter, async () => {
console.log('ValidatorInit event... updating pools')
user.value.balance = ethers.utils.formatEther(await getUserBalance(user.value.id))
user.value.pools = await getUserPools(user.value.id)
user.value.balance = await getUserBalance()
user.value.pools = await getPools(user.value.id)
user.value.stake = user.value.pools?.reduce((a, c) => a + parseFloat(c.userStake), 0).toString()
user.value.rewards = user.value.pools?.reduce((a, c) => a + parseFloat(c.userRewards), 0).toString()
})
}

// onMounted(async () => {
// const { getUserBalance, getUserPools } = useWallet()
// const { getUserBalance } = useWallet()
// // Just get pools for primary account for demo
// user.value.balance = ethers.utils.formatEther(await getUserBalance(user.value.id))
// user.value.pools = await getUserPools(user.value.id)
// user.value.pools = await getPools(user.value.id)
// subscribeToUserEvents()
// })

async function addAccount(account: AddAccountOptions): Promise<{ error: boolean, message: string, data: User | null }> {
async function addAccount(account: AddAccountOptions): Promise<{ error: boolean, message: string, data: UserWithAccounts | null }> {
const requestOptions = {
method: 'POST',
headers: {
Expand Down
Loading