diff --git a/apps/web/src/composables/operators.ts b/apps/web/src/composables/operators.ts index 24d6d3895..aa7803311 100644 --- a/apps/web/src/composables/operators.ts +++ b/apps/web/src/composables/operators.ts @@ -15,9 +15,9 @@ let defaultManager: CasimirManager let defaultRegistry: CasimirRegistry let defaultViews: CasimirViews -// let eigenManager: CasimirManager -// let eigenRegistry: CasimirRegistry -// let eigenViews: CasimirViews +let eigenManager: CasimirManager +let eigenRegistry: CasimirRegistry +let eigenViews: CasimirViews const { getContracts } = useContracts() const { ethereumUrl, ssvNetworkAddress, ssvViewsAddress, usersUrl } = useEnvironment() @@ -35,8 +35,10 @@ export default function useOperators() { const loadingRegisteredOperators = ref(false) const loadingRegisteredOperatorsError = ref(false) - const nonregisteredOperators = ref([]) - const registeredOperators = ref([]) + const nonregisteredDefaultOperators = ref([]) + const nonregisteredEigenOperators = ref([]) + const registeredDefaultOperators = ref([]) + const registeredEigenOperators = ref([]) async function addOperator({ address, nodeUrl }: { address: string, nodeUrl: string }) { try { @@ -73,12 +75,32 @@ export default function useOperators() { ssvOperators.push(...userOperators) } + const defaultCasimirOperators = await _getRegisteredOperators(ssvOperators, 'default') + const eigenCasimirOperators = await _getRegisteredOperators(ssvOperators, 'eigen') + + const nonregDefaultOperators = ssvOperators.filter((operator: any) => { + const idRegistered = defaultCasimirOperators.find((registeredOperator: any) => registeredOperator.id === operator.id) + return !idRegistered + }) + const nonregEigenOperators = ssvOperators.filter((operator: any) => { + const idRegistered = eigenCasimirOperators.find((registeredOperator: any) => registeredOperator.id === operator.id) + return !idRegistered + }) + + nonregisteredDefaultOperators.value = nonregDefaultOperators as Array + nonregisteredEigenOperators.value = nonregEigenOperators as Array + registeredDefaultOperators.value = defaultCasimirOperators as Array + registeredEigenOperators.value = eigenCasimirOperators as Array + } + + async function _getRegisteredOperators(ssvOperators: Operator[], type: 'default' | 'eigen'): Promise { const casimirOperators: RegisteredOperator[] = [] + const registry = type === 'default' ? defaultRegistry : eigenRegistry for (const operator of ssvOperators) { - const { active, collateral, poolCount, resharing } = await (defaultRegistry as CasimirRegistry).getOperator(operator.id) + const { active, collateral, poolCount, resharing } = await (registry as CasimirRegistry).getOperator(operator.id) const registered = active || collateral.gt(0) || poolCount.gt(0) || resharing if (registered) { - const pools = await _getPools(operator.id) + const pools = await _getPools(operator.id, type) // TODO: Replace these Public Nodes URLs once we have this working again const operatorStore = { '208': 'https://nodes.casimir.co/eth/goerli/dkg/1', @@ -102,26 +124,26 @@ export default function useOperators() { }) } } - - const nonregOperators = ssvOperators.filter((operator: any) => { - const idRegistered = casimirOperators.find((registeredOperator: any) => registeredOperator.id === operator.id) - return !idRegistered - }) - - nonregisteredOperators.value = nonregOperators as Array - registeredOperators.value = casimirOperators as Array + return casimirOperators } - async function _getPools(operatorId: number): Promise { + async function _getPools(operatorId: number, type: 'default' | 'eigen'): Promise { const pools: PoolConfig[] = [] - const poolIds = [ + const defaultPoolIds = [ ...await (defaultManager as CasimirManager).getPendingPoolIds(), ...await (defaultManager as CasimirManager).getStakedPoolIds() ] + const eigenPoolIds = [ + ...await (eigenManager as CasimirManager).getPendingPoolIds(), + ...await (eigenManager as CasimirManager).getStakedPoolIds() + ] + + const poolIds = type === 'default' ? defaultPoolIds : eigenPoolIds + const views = type === 'default' ? defaultViews : eigenViews for (const poolId of poolIds) { - const poolConfig = await (defaultViews as CasimirViews).getPoolConfig(poolId) + const poolConfig = await (views as CasimirViews).getPoolConfig(poolId) const pool = { ...poolConfig, operatorIds: poolConfig.operatorIds.map(id => id.toNumber()), @@ -138,9 +160,13 @@ export default function useOperators() { try { /* Get Manager, Views, and Registry */ const { defaultManager: managerContract, defaultRegistry: registryContract, defaultViews: viewsContract } = await getContracts() + const { eigenManager: eigenManagerContract, eigenRegistry: eigenRegistryContract, eigenViews: eigenViewsContract } = await getContracts() defaultManager = managerContract defaultRegistry = registryContract defaultViews = viewsContract + eigenManager = eigenManagerContract + eigenRegistry = eigenRegistryContract + eigenViews = eigenViewsContract loadingInitializeOperators.value = true listenForContractEvents() @@ -155,7 +181,9 @@ export default function useOperators() { function listenForContractEvents() { try { - (defaultRegistry as CasimirRegistry).on('OperatorRegistered', () => getUserOperators()) + (defaultRegistry as CasimirRegistry).on('OperatorRegistered', () => getUserOperators()); + (eigenRegistry as CasimirRegistry).on('OperatorRegistered', () => getUserOperators()) + // (registry as CasimirRegistry).on('OperatorDeregistered', getUserOperators) // (registry as CasimirRegistry).on('DeregistrationRequested', getUserOperators) } catch (err) { @@ -192,8 +220,10 @@ export default function useOperators() { } return { - nonregisteredOperators: readonly(nonregisteredOperators), - registeredOperators: readonly(registeredOperators), + nonregisteredDefaultOperators: readonly(nonregisteredDefaultOperators), + nonregisteredEigenOperators: readonly(nonregisteredEigenOperators), + registeredDefaultOperators: readonly(registeredDefaultOperators), + registeredEigenOperators: readonly(registeredEigenOperators), loadingAddOperator: readonly(loadingAddOperator), loadingAddOperatorError: readonly(loadingAddOperatorError), loadingInitializeOperators: readonly(loadingInitializeOperators), diff --git a/apps/web/src/pages/operators/Operator.vue b/apps/web/src/pages/operators/Operator.vue index 51840fce4..30bae1553 100644 --- a/apps/web/src/pages/operators/Operator.vue +++ b/apps/web/src/pages/operators/Operator.vue @@ -13,7 +13,16 @@ const { loadingSessionLogin } = useAuth() // const { detectActiveWalletAddress } = useEthers() const { exportFile } = useFiles() const { convertString } = useFormat() -const {initializeOperatorComposable, nonregisteredOperators, registeredOperators, registerOperatorWithCasimir, loadingInitializeOperators, loadingAddOperator } = useOperators() +const { + initializeOperatorComposable, + registerOperatorWithCasimir, + nonregisteredDefaultOperators, + nonregisteredEigenOperators, + registeredDefaultOperators, + registeredEigenOperators, + loadingInitializeOperators, + loadingAddOperator +} = useOperators() const { user } = useUser() // Form inputs @@ -24,6 +33,28 @@ const onSelectWalletBlur = () => { openSelectWalletOptions.value = false }, 200) } + +const operatorType = ref<'default' | 'eigen'>('default') +const eigenIsShining = ref(true) // Determines if the shine effect is active +const eigenIsToggled = ref(false) // Determines the toggle state +const toggleBackgroundColor = ref('#eee') // Initial color + +function toggleEigenLayerSupport() { + eigenIsToggled.value = !eigenIsToggled.value + toggleBackgroundColor.value = eigenIsToggled.value ? 'green' : '#eee' + operatorType.value = eigenIsToggled.value ? 'eigen' : 'default' + + console.log('nonregisteredDefaultOperators.value :>> ', nonregisteredDefaultOperators.value) + console.log('registeredDefaultOperators.value :>> ', registeredDefaultOperators.value) + + console.log('nonregisteredEigenOperators.value :>> ', nonregisteredEigenOperators.value) + console.log('registeredEigenOperators.value :>> ', registeredEigenOperators.value) + + console.log('operatorType.value :>> ', operatorType.value) + // Update stakeType + // stakeType.value = eigenIsToggled.value ? 'eigen' : 'default' +} + const selectedOperatorID = ref() const openSelectOperatorID = ref(false) const onSelectOperatorIDBlur = () => { @@ -121,13 +152,34 @@ watch(selectedWallet, async () =>{ if (selectedWallet.value.address === '') { availableOperatorIDs.value = [] - } else if(nonregisteredOperators.value && nonregisteredOperators.value.length > 0) { - availableOperatorIDs.value = [...nonregisteredOperators.value].filter((operator: any) => operator.ownerAddress === selectedWallet.value.address).map((operator: any) => operator.id)} + } else if(operatorType.value === 'default') { + if (nonregisteredDefaultOperators.value && nonregisteredDefaultOperators.value.length > 0) { + availableOperatorIDs.value = [...nonregisteredDefaultOperators.value].filter((operator: any) => operator.ownerAddress === selectedWallet.value.address).map((operator: any) => operator.id) + } else if (nonregisteredEigenOperators.value && nonregisteredEigenOperators.value.length > 0) { + availableOperatorIDs.value = [...nonregisteredEigenOperators.value].filter((operator: any) => operator.ownerAddress === selectedWallet.value.address).map((operator: any) => operator.id) + } else { + availableOperatorIDs.value = [] + } + } +}) + +watch(registeredDefaultOperators, () => { + openAddOperatorModal.value = false + tableData.value = [...registeredDefaultOperators.value].map((operator: any) => { + return { + id: operator.id, + walletAddress: operator.ownerAddress, + collateral: operator.collateral + ' ETH', + poolCount: operator.poolCount, + nodeURL: operator.url + } + }) + filterData() }) -watch(registeredOperators, () => { +watch(registeredEigenOperators, () => { openAddOperatorModal.value = false - tableData.value = [...registeredOperators.value].map((operator: any) => { + tableData.value = [...registeredEigenOperators.value].map((operator: any) => { return { id: operator.id, walletAddress: operator.ownerAddress, @@ -406,6 +458,29 @@ watch([loadingSessionLogin || loadingInitializeOperators], () =>{ Select your SSV owner address +
+ + Enable EigenLayer Support + +
+
+
+
+
Operator ID @@ -913,4 +988,90 @@ watch([loadingSessionLogin || loadingInitializeOperators], () =>{ letter-spacing: -0.03em; color: #FFFFFF; } + +/* Eigen Button */ +.toggle_container { + display: flex; + align-items: center; + justify-content: flex-start; + padding-left: 10px; /* space from the left edge */ + position: relative; + height: 44px; /* adjust as needed if required */ + background-color: rgb(26 12 109); + overflow: hidden; + text-align: center; + color: #fff; /* or any suitable color for better visibility */ + font-size: 14px; /* adjust based on preference */ + border-radius: 8px; + transition: background-color 0.3s; /* This will animate the color change */ +} + +.toggle_container:disabled { + background-color: rgba(26, 12, 109, 0.5); /* This makes the purple color lighter (grayed out) */ + /* cursor: not-allowed; This changes the cursor to indicate the button is not clickable */ +} + +.shine-effect { + content: ''; + position: absolute; + top: -50%; + left: -150%; + width: 200%; + height: 200%; + background: rgba(255, 255, 255, 0.5); + transform: rotate(30deg); + pointer-events: none; + animation: shine 2.5s infinite; +} + +@keyframes shine { + 0% { + left: -150%; + } + 50% { + left: 150%; + } + 100% { + left: 150%; + } +} + +/* Eigen Button */ +.toggle-button { + position: absolute; + top: 50%; + right: 10px; /* space from the right edge */ + transform: translateY(-50%); + width: 50px; + height: 25px; + background-color: #eee; + border-radius: 15px; + cursor: pointer; + overflow: hidden; +} + +.card_container .toggle_container.toggle-on .toggle-button { + background-color: green !important; +} + +.toggle-circle { + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 30px; + height: 30px; + background-color: #fff; + border-radius: 50%; + transition: left 0.3s; +} + +.toggle-on .toggle-circle { + left: calc(100% - 30px); +} + +.eigen-logo { + height: 20px; + margin-right: 10px; +} @/composables/files@/composables/user \ No newline at end of file diff --git a/apps/web/src/pages/overview/components/Staking.vue b/apps/web/src/pages/overview/components/Staking.vue index b771c10c1..4665c0e0c 100644 --- a/apps/web/src/pages/overview/components/Staking.vue +++ b/apps/web/src/pages/overview/components/Staking.vue @@ -452,26 +452,26 @@ const handleDeposit = async () => { @@ -671,7 +671,7 @@ const handleDeposit = async () => { } /* Eigen Button */ -.toggle-container { +.toggle_container { display: flex; align-items: center; justify-content: flex-start; @@ -688,12 +688,12 @@ const handleDeposit = async () => { transition: background-color 0.3s; /* This will animate the color change */ } -.toggle-container:disabled { +.toggle_container:disabled { background-color: rgba(26, 12, 109, 0.5); /* This makes the purple color lighter (grayed out) */ /* cursor: not-allowed; This changes the cursor to indicate the button is not clickable */ } -.shine-effect { +.shine_effect { content: ''; position: absolute; top: -50%; @@ -718,7 +718,7 @@ const handleDeposit = async () => { } } -.toggle-button { +.toggle_button { position: absolute; top: 50%; right: 10px; /* space from the right edge */ @@ -731,11 +731,11 @@ const handleDeposit = async () => { overflow: hidden; } -.card_container .toggle-container.toggle-on .toggle-button { +.card_container .toggle_container.toggle-on .toggle_button { background-color: green !important; } -.toggle-circle { +.toggle_circle { position: absolute; top: 50%; left: 0; @@ -747,11 +747,11 @@ const handleDeposit = async () => { transition: left 0.3s; } -.toggle-on .toggle-circle { +.toggle-on .toggle_circle { left: calc(100% - 30px); } -.eigen-logo { +.eigen_logo { height: 20px; margin-right: 10px; }