Skip to content

Commit

Permalink
Merge pull request #343 from consensusnetworks/feature/simulation
Browse files Browse the repository at this point in the history
Add pre-audit contracts with dev simulation
  • Loading branch information
shanejearley authored Jun 14, 2023
2 parents 5a0317d + f9908e7 commit ac0aaa0
Show file tree
Hide file tree
Showing 170 changed files with 25,091 additions and 20,710 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jobs:
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
base: develop
branch: master
reviewers: robosupport
token: ${{ github.token }}
Expand Down
19 changes: 7 additions & 12 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@
[submodule "scripts/ledger/resources/speculos"]
path = scripts/ledger/resources/speculos
url = https://github.com/LedgerHQ/speculos.git
[submodule "contracts/ethereum/scripts/resources/ssv-network"]
path = contracts/ethereum/scripts/resources/ssv-network
url = https://github.com/bloxapp/ssv-network.git
[submodule "contracts/ethereum/scripts/resources/ssv-contracts"]
path = contracts/ethereum/scripts/resources/ssv-contracts
url = https://github.com/bloxapp/ssv-contracts.git
[submodule "contracts/ethereum/scripts/resources/consensus-specs"]
path = contracts/ethereum/scripts/resources/consensus-specs
url = https://github.com/ethereum/consensus-specs.git
[submodule "scripts/trezor/resources/trezor-user-env"]
path = scripts/trezor/resources/trezor-user-env
url = https://github.com/trezor/trezor-user-env.git
[submodule "services/keys/scripts/resources/dkg"]
path = services/keys/scripts/resources/dkg
url = https://github.com/RockX-SG/frost-dkg-demo.git
[submodule "services/validators/scripts/resources/rockx-dkg-cli"]
path = services/oracle/scripts/resources/rockx-dkg-cli
url = https://github.com/RockX-SG/rockx-dkg-cli.git
[submodule "contracts/ethereum/scripts/resources/ssv-network"]
path = contracts/ethereum/scripts/resources/ssv-network
url = https://github.com/bloxapp/ssv-network.git
branch = contract-v3
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ Get started contributing to Casimir's codebase.

Make sure your development environment has these prerequisites.

1. [Node.js (v18.x)](https://nodejs.org/en/download/)we use [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.
1. [AWS CLI (v2.x)](https://aws.amazon.com/cli/)create an [AWS profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) named `consensus-networks-dev`.

2. [Docker (v4.x)](https://docs.docker.com/engine/install/) - make sure your Docker runs on startup.

3. [AWS CLI (v2.x)](https://aws.amazon.com/cli/) – create an [AWS profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) named `consensus-networks-dev`.
3. [Git (v2.x)](https://git-scm.com/downloads) – we use [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to manage shared code.

4. [Go (v1.18.x)](https://golang.org/doc/install) – we use [Go modules](https://blog.golang.org/using-go-modules) to manage Go dependencies.

5. [Node.js (v18.x)](https://nodejs.org/en/download/) – we use [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.

> 🚩 You also need to make sure to have at least one SSH authentication key on your GitHub account (for the git cloning of submodules in various scripts). See [Adding a new SSH key to your GitHub account](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account).
Expand All @@ -46,7 +50,7 @@ git checkout -b feature/stake-button develop
npm install
```

> 🚩 'All workspace dependencies' includes `package.json` dependencies listed in the project root and any workspace subdirectories. See [Scripts and dependencies](#-scripts-and-dependencies).
> 🚩 'All workspace dependencies' includes `package.json` dependencies listed in the project root and any workspace subdirectories. See [Scripts and dependencies](#scripts-and-dependencies).
### Serve

Expand Down
2 changes: 1 addition & 1 deletion apps/landing/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { fileURLToPath } from 'url'
import * as path from 'path'

export default defineConfig({
server: { port: 3000 },
server: { port: 3001 },
plugins: [
vue({ include: [/\.vue$/] })
],
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/components/Wallet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@

<script setup lang="ts">
import { ref, watchEffect, onMounted } from 'vue'
import useSSV from '@/composables/ssv'
import useContracts from '@/composables/contracts'
// import useUsers from '@/composables/users'
import useWallet from '@/composables/wallet'
Expand Down Expand Up @@ -185,7 +185,7 @@ const {
switchNetwork
} = useWallet()
const { deposit, getPools, withdraw } = useSSV()
const { deposit, getPools, withdraw } = useContracts()
watchEffect(() => {
if (selectedProvider.value === 'MetaMask') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
import { ethers } from 'ethers'
import { CasimirManager } from '@casimir/ethereum/build/artifacts/types'
import { abi } from '@casimir/ethereum/build/artifacts/src/CasimirManager.sol/CasimirManager.json'
import { CasimirManager, CasimirViews } from '@casimir/ethereum/build/artifacts/types'
import CasimirManagerJson from '@casimir/ethereum/build/artifacts/src/v1/CasimirManager.sol/CasimirManager.json'
import CasimirViewsJson from '@casimir/ethereum/build/artifacts/src/v1/CasimirManager.sol/CasimirManager.json'
import useEnvironment from './environment'
import useUsers from './users'
import useEthers from './ethers'
import useLedger from './ledger'
import useTrezor from './trezor'
import useWalletConnect from './walletConnect'
import { Account, Pool, ProviderString } from '@casimir/types'
import { ReadyOrStakeString } from '../interfaces'
import { ReadyOrStakeString } from '@/interfaces/ReadyOrStakeString'

/** Manager contract */
let casimirManager: CasimirManager
const managerAddress = import.meta.env.PUBLIC_MANAGER_ADDRESS
const manager: CasimirManager = new ethers.Contract(managerAddress, CasimirManagerJson.abi) as CasimirManager

export default function useSSV() {
/** Views contract */
const viewsAddress = import.meta.env.PUBLIC_VIEWS_ADDRESS
const views: CasimirViews = new ethers.Contract(viewsAddress, CasimirViewsJson.abi) as CasimirViews

export default function useContracts() {
const { ethereumURL } = useEnvironment()
const { ethersProviderList, getEthersBrowserSigner } = useEthers()
const { getEthersLedgerSigner } = useLedger()
const { getEthersTrezorSigner } = useTrezor()
const { isWalletConnectSigner, getEthersWalletConnectSigner } = useWalletConnect()

if (!casimirManager) {
casimirManager = (() => {
const address = import.meta.env.PUBLIC_CASIMIR_MANAGER
if (!address) console.log(
`
The PUBLIC_CASIMIR_MANAGER environment variable is empty.\n
If you are on mainnet or testnet, the contract does not exist yet.\n
If you are on the local network, check your terminal logs for a contract address or errors.
`
)
return new ethers.Contract(address, abi) as CasimirManager
})()
}

async function deposit({ amount, walletProvider }: { amount: string, walletProvider: ProviderString }) {
const signerCreators = {
'Browser': getEthersBrowserSigner,
Expand All @@ -45,41 +37,34 @@ export default function useSSV() {
const signerCreator = signerCreators[signerType as keyof typeof signerCreators]
let signer = signerCreator(walletProvider)
if (isWalletConnectSigner(signer)) signer = await signer
const casimirManagerSigner = casimirManager.connect(signer as ethers.Signer)
const fees = await casimirManagerSigner.getFees()
const { LINK, SSV } = fees
const feesTotalPercent = LINK + SSV
const depositAmount = parseFloat(amount) * ((100 + feesTotalPercent) / 100)
const managerSigner = manager.connect(signer as ethers.Signer)
const fees = await managerSigner.feePercent()
const depositAmount = parseFloat(amount) * ((100 + fees) / 100)
const value = ethers.utils.parseEther(depositAmount.toString())
const result = await casimirManagerSigner.deposit({ value, type: 0 })
const result = await managerSigner.depositStake({ value, type: 0 })
return await result.wait()
}

async function getDepositFees() {
const provider = new ethers.providers.JsonRpcProvider(ethereumURL)
const casimirManagerProvider = casimirManager.connect(provider)
const fees = await casimirManagerProvider.getFees()
const { LINK, SSV } = fees
const feesTotalPercent = LINK + SSV
const feesRounded = Math.round(feesTotalPercent * 100) / 100
const fees = await manager.connect(provider).feePercent()
const feesRounded = Math.round(fees * 100) / 100
return feesRounded
}

async function getPools(address: string, readyOrStake: ReadyOrStakeString): Promise<Pool[]> {
const { user } = useUsers()
const provider = new ethers.providers.JsonRpcProvider(ethereumURL)
const casimirManagerProvider = casimirManager.connect(provider)

const userStake = await casimirManagerProvider.getUserStake(address) // to get user's stake balance
const poolStake = await casimirManagerProvider.getStake() // to get total stake balance
const poolIds = readyOrStake === 'ready' ? await casimirManagerProvider.getReadyPoolIds() : await casimirManagerProvider.getStakedPoolIds() // to get ready (open) pool IDs OR to get staked (active) pool IDs
const provider = new ethers.providers.JsonRpcProvider(ethereumURL)
const userStake = await manager.connect(provider).getUserStake(address) // to get user's stake balance
const poolStake = await manager.connect(provider).getTotalStake() // to get total stake balance
const poolIds = readyOrStake === 'ready' ? await manager.connect(provider).getReadyPoolIds() : await manager.connect(provider).getStakedPoolIds() // to get ready (open) pool IDs OR to get staked (active) pool IDs

console.log('userStake :>> ', ethers.utils.formatEther(userStake))
console.log('poolStake :>> ', ethers.utils.formatEther(poolStake))
console.log('poolIds :>> ', poolIds)

return await Promise.all(poolIds.map(async (poolId: number) => {
const { deposits, operatorIds, validatorPublicKey } = await casimirManagerProvider.getPool(poolId)
const { publicKey, operatorIds } = await views.connect(provider).getPoolDetails(poolId)

// TODO: Decide when/how to get rewards/userRewards
let pool: Pool = {
Expand All @@ -90,27 +75,27 @@ export default function useSSV() {
userStake: ethers.utils.formatEther(userStake)
}

if (validatorPublicKey) {
if (publicKey) {
// 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()
// const { status } = data
const validator = {
publicKey: validatorPublicKey,
publicKey,
status: 'Active',
effectiveness: '0%',
apr: '0%', // See issue #205 https://github.com/consensusnetworks/casimir/issues/205#issuecomment-1338142532
url: `https://prater.beaconcha.in/validator/${validatorPublicKey}`
url: `https://prater.beaconcha.in/validator/${publicKey}`
}


// TODO: Replace with less hardcoded network call?
const operators = await Promise.all(operatorIds.map(async (operatorId: number) => {
const operators = await Promise.all(operatorIds.map(async (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,
id: operatorId.toNumber(),
'24HourPerformance': performance['24h'],
'30DayPerformance': performance['30d'],
url: `https://explorer.ssv.network/operators/${operatorId}`
Expand Down Expand Up @@ -147,11 +132,11 @@ export default function useSSV() {
const signerCreator = signerCreators[signerType as keyof typeof signerCreators]
let signer = signerCreator(walletProvider)
if (isWalletConnectSigner(signer)) signer = await signer
const casimirManagerSigner = casimirManager.connect(signer as ethers.Signer)
const managerSigner = manager.connect(signer as ethers.Signer)
const value = ethers.utils.parseEther(amount)
const result = await casimirManagerSigner.withdraw(value)
const result = await managerSigner.requestWithdrawal(value)
return await result.wait()
}

return { casimirManager, deposit, getDepositFees, getPools, withdraw }
return { manager, deposit, getDepositFees, getPools, withdraw }
}
18 changes: 9 additions & 9 deletions apps/web/src/composables/ethers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export default function useEthers() {
method: 'wallet_addEthereumChain',
params: [network]
})
} catch(err){
console.log(`Error occurred while adding network ${network.chainName}, Message: ${err.message} Code: ${err.code}`)
} catch(error: any) {
console.log(`Error occurred while adding network ${network.chainName}, Message: ${error.message} Code: ${error.code}`)
}
}

Expand Down Expand Up @@ -53,13 +53,13 @@ export default function useEthers() {
const feeInWei = ethers.utils.formatEther(fee)
const feeInEth = (parseInt(feeInWei) / 10**18).toFixed(8).toString()
return {
gasEstimate,
gasLimit: gasEstimate.toString(),
fee: feeInEth
}
} catch (err) {
console.error('There was an error in estimateGasFee :>> ', err)
return {
gasEstimate: '0',
gasLimit: '0',
fee: '0'
}
}
Expand All @@ -75,12 +75,12 @@ export default function useEthers() {
try {
const provider = new ethers.providers.JsonRpcProvider(rpcUrl)
const gasPrice = await provider.getGasPrice()
const gasLimit = await provider.estimateGas(unsignedTransaction as ethers.utils.Deferrable<ethers.providers.TransactionRequest>)
const fee = gasPrice.mul(gasLimit)
const gasEstimate = await provider.estimateGas(unsignedTransaction as ethers.utils.Deferrable<ethers.providers.TransactionRequest>)
const fee = gasPrice.mul(gasEstimate)
const feeInWei = ethers.utils.formatEther(fee)
const feeInEth = (parseInt(feeInWei) / 10**18).toFixed(8).toString()
return {
gasLimit,
gasLimit: gasEstimate.toString(),
fee: feeInEth
}
} catch (err) {
Expand Down Expand Up @@ -192,13 +192,13 @@ export default function useEthers() {
value: weiAmount
}
const ethFees = await estimateEIP1559GasFee(ethereumURL, tx)
const { fee, gasEstimate } = ethFees
const { fee, gasLimit } = ethFees
const requiredBalance = parseInt(value) + parseInt(fee)
const balance = await getEthersBalance(from)
if (parseInt(balance) < requiredBalance) {
throw new Error('Insufficient balance')
}
console.log(`Sending ${value} ETH to ${to} with estimated ${fee} ETH in fees using ~${gasEstimate} in gas.`)
console.log(`Sending ${value} ETH to ${to} with estimated ${fee} ETH in fees using ~${gasLimit.toString()} in gas.`)
return await signer.sendTransaction(tx)
}

Expand Down
7 changes: 3 additions & 4 deletions apps/web/src/composables/trezor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import useAuth from '@/composables/auth'
import useEthers from '@/composables/ethers'
import useEnvironment from '@/composables/environment'
import { ethers } from 'ethers'
import { } from '@/interfaces/index'
import { LoginCredentials, MessageRequest, TransactionRequest } from '@casimir/types'

const { createSiweMessage, signInWithEthereum } = useAuth()
Expand Down Expand Up @@ -84,9 +83,9 @@ export default function useTrezor() {
signedMessage
})
return await loginResponse.json()
} catch (err) {
console.log(err)
throw new Error(err)
} catch (error: any) {
console.log(error)
throw new Error(error)
}
}

Expand Down
24 changes: 1 addition & 23 deletions apps/web/src/composables/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { onMounted, ref } from 'vue'
import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, Account, ExistingUserCheck } from '@casimir/types'
import { ethers } from 'ethers'
import useEnvironment from '@/composables/environment'
import useSSV from '@/composables/ssv'
import useContracts from '@/composables/contracts'
import useWallet from '@/composables/wallet'
import * as Session from 'supertokens-web-js/recipe/session'

Expand All @@ -11,7 +11,6 @@ const { usersBaseURL, ethereumURL } = useEnvironment()
// 0xd557a5745d4560B24D36A68b52351ffF9c86A212
const session = ref<boolean>(false)
const user = ref<UserWithAccounts>()
const { casimirManager, getPools } = useSSV()

export default function useUsers () {

Expand Down Expand Up @@ -134,27 +133,6 @@ export default function useUsers () {
user.value = newUser
}

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

const validatorInitFilter = {
address: casimirManager.address,
topics: [
// ethers.utils.id('ManagerDistribution(address,uint256,uint256,uint256)'), // TODO: Make sure to query for past events on page load (Fetch and then subscribe),
ethers.utils.id('PoolStaked(uint32)'),
]
}
casimirManager.connect(provider).on(validatorInitFilter, async () => {
console.log('ValidatorInit event... updating pools')
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()
})
}

async function updatePrimaryAddress(updatedAddress: string) {
const userId = user?.value?.id
const requestOptions = {
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/composables/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import useUsers from '@/composables/users'
import useWalletConnect from '@/composables/walletConnect'
import { Account, CryptoAddress, Currency, ExistingUserCheck, LoginCredentials, MessageRequest, ProviderString, TransactionRequest } from '@casimir/types'
import * as Session from 'supertokens-web-js/recipe/session'
import router from './router'

// Test ethereum send from address : 0xd557a5745d4560B24D36A68b52351ffF9c86A212
// Test ethereum send to address : 0xD4e5faa8aD7d499Aa03BDDE2a3116E66bc8F8203
Expand Down Expand Up @@ -301,8 +300,9 @@ export default function useWallet() {
} else {
return await connectWallet() // sign up or add account
}
} catch (err) {
console.error('selectAddress error: ', err)
} catch (error: any) {
console.error('selectAddress error: ', error)
throw new Error(error)
}
}

Expand Down Expand Up @@ -332,7 +332,7 @@ export default function useWallet() {
const trezorAddresses = await getTrezorAddress[currency]() as CryptoAddress[]
setUserAddresses(trezorAddresses)
}
} catch (error) {
} catch (error: any) {
console.error('There was an error in selectProvider :>> ', error)
if (error.name === 'TransportStatusError') alert('Please enter your PIN and open the Ethereum application on your device.')
}
Expand Down
Loading

0 comments on commit ac0aaa0

Please sign in to comment.