From 2d47887c3585647616e05954cc60a07e2421cf10 Mon Sep 17 00:00:00 2001 From: gmolki Date: Thu, 29 Aug 2024 16:23:57 +0200 Subject: [PATCH] feat: support base for payg --- .../pages/computing/NewInstancePage/cmp.tsx | 7 ++-- src/domain/connect/base.ts | 32 +++++++++++++------ src/domain/connect/index.ts | 1 + src/domain/executable.ts | 5 +-- src/domain/instance.ts | 2 -- src/helpers/errors.ts | 2 +- src/helpers/schemas/base.ts | 6 +++- .../pages/computing/useNewInstancePage.ts | 16 ++++++---- .../solutions/manage/useManageInstance.ts | 20 ++++++------ src/hooks/pages/useHeader.ts | 6 ++++ 10 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/components/pages/computing/NewInstancePage/cmp.tsx b/src/components/pages/computing/NewInstancePage/cmp.tsx index 34f0efca..a2a9dfa2 100644 --- a/src/components/pages/computing/NewInstancePage/cmp.tsx +++ b/src/components/pages/computing/NewInstancePage/cmp.tsx @@ -39,6 +39,7 @@ import Strong from '@/components/common/Strong' import { useConnection } from '@/hooks/common/useConnection' import CRNList from '../../../common/CRNList' import BackButtonSection from '@/components/common/BackButtonSection' +import { isBlockchainSupported as isBlockchainPAYGCompatible } from '@aleph-sdk/superfluid' export default function NewInstancePage({ mainRef }: PageProps) { const { @@ -206,7 +207,7 @@ export default function NewInstancePage({ mainRef }: PageProps) { You are about to switch your payment method to{' '} Pay-as-you-go, which will also allow you to{' '} manually select your preferred CRN on{' '} - Avalanche. + Avalanche or Base.
Making this change will prompt your wallet to automatically switch @@ -311,7 +312,7 @@ export default function NewInstancePage({ mainRef }: PageProps) { You are about to switch from the automated Holder-tier setup on Ethereum to manually selecting a CRN with the{' '} Pay-as-you-go method on{' '} - Avalanche. + Avalanche or Base.
Making this change will prompt your wallet to automatically switch @@ -384,7 +385,7 @@ export default function NewInstancePage({ mainRef }: PageProps) { if (selectedModal) return if ( - (node && blockchain === BlockchainId.AVAX) || + (node && isBlockchainPAYGCompatible(blockchain)) || (!node && blockchain === BlockchainId.ETH) ) { return modalClose() diff --git a/src/domain/connect/base.ts b/src/domain/connect/base.ts index 0807c710..baa3bdd5 100644 --- a/src/domain/connect/base.ts +++ b/src/domain/connect/base.ts @@ -9,11 +9,12 @@ import { getAccountFromProvider as getSOLAccount, SOLAccount, } from '@aleph-sdk/solana' +import { getAccountFromProvider as getAVAXAccount } from '@aleph-sdk/avalanche' +import { getAccountFromProvider as getBASEAccount } from '@aleph-sdk/base' import { - getAccountFromProvider as getAVAXAccount, - AvalancheAccount, -} from '@aleph-sdk/avalanche' -import { createFromAvalancheAccount } from '@aleph-sdk/superfluid' + createFromEVMAccount, + isAccountSupported as isAccountPAYGCompatible, +} from '@aleph-sdk/superfluid' import { Mutex, getERC20Balance, getSOLBalance, sleep } from '@/helpers/utils' import { MetaMaskInpageProvider } from '@metamask/providers' import type { @@ -21,6 +22,7 @@ import type { CombinedProvider, } from '@web3modal/scaffold-utils/ethers' import Err from '@/helpers/errors' +import { EVMAccount } from '@aleph-sdk/evm' export { BlockchainId } @@ -78,6 +80,15 @@ export const blockchains: Record = { explorerUrl: 'https://snowtrace.io/', rpcUrl: 'https://avalanche.drpc.org', }, + [BlockchainId.BASE]: { + id: BlockchainId.BASE, + name: 'Base', + chainId: 8453, + eip155: true, + currency: 'ETH', + explorerUrl: 'https://basescan.org', + rpcUrl: 'https://mainnet.base.org', + }, [BlockchainId.SOL]: { id: BlockchainId.SOL, name: 'Solana', @@ -90,6 +101,7 @@ export const blockchains: Record = { export const networks: Record = { 1: blockchains.ETH, 43114: blockchains.AVAX, + 8453: blockchains.BASE, 900: blockchains.SOL, } @@ -235,6 +247,9 @@ export abstract class BaseConnectionProviderManager { case BlockchainId.AVAX: return getAVAXAccount(provider as any) + case BlockchainId.BASE: + return getBASEAccount(provider as any) + case BlockchainId.SOL: return getSOLAccount(provider as any) @@ -244,12 +259,11 @@ export abstract class BaseConnectionProviderManager { } async getBalance(account: Account): Promise { - if (account instanceof AvalancheAccount) { + if (isAccountPAYGCompatible(account)) { try { - // @note: refactor in SDK calling init inside this method - const superfluidAccount = createFromAvalancheAccount(account) - await superfluidAccount.init() - + const superfluidAccount = await createFromEVMAccount( + account as EVMAccount, + ) const balance = await superfluidAccount.getALEPHBalance() return balance.toNumber() } catch (e) { diff --git a/src/domain/connect/index.ts b/src/domain/connect/index.ts index 7ec1920c..0d77e11f 100644 --- a/src/domain/connect/index.ts +++ b/src/domain/connect/index.ts @@ -24,4 +24,5 @@ export class ConnectionProviderManager { export const connectionProviderManager = new ConnectionProviderManager([ BlockchainId.ETH, BlockchainId.AVAX, + BlockchainId.BASE, ]) diff --git a/src/domain/executable.ts b/src/domain/executable.ts index fc19b3d1..d41e53cb 100644 --- a/src/domain/executable.ts +++ b/src/domain/executable.ts @@ -32,6 +32,7 @@ import { import Err from '@/helpers/errors' import { BlockchainId } from './connect/base' import { NodeManager } from './node' +import { isBlockchainSupported as isBlockchainPAYGCompatible } from '@aleph-sdk/superfluid' type ExecutableCapabilitiesProps = { internetAccess?: boolean @@ -370,9 +371,9 @@ export abstract class ExecutableManager { } if (payment.type === PaymentMethod.Stream) { if (!payment.receiver) throw Err.ReceivedRequired - if (payment.chain === BlockchainId.AVAX) + if (isBlockchainPAYGCompatible(payment.chain)) return { - chain: BlockchainId.AVAX, + chain: payment.chain, type: SDKPaymentType.superfluid, receiver: payment.receiver, } diff --git a/src/domain/instance.ts b/src/domain/instance.ts index 7a294632..9eef45d9 100644 --- a/src/domain/instance.ts +++ b/src/domain/instance.ts @@ -305,8 +305,6 @@ export class InstanceManager const { streamCost, streamDuration, receiver } = newInstance.payment - await account.init() - const alephxBalance = await account.getALEPHBalance() const alephxFlow = await account.getALEPHFlow(receiver) const totalFlow = alephxFlow.add(streamCost / getHours(streamDuration)) diff --git a/src/helpers/errors.ts b/src/helpers/errors.ts index 2c2b42c4..c7f38304 100644 --- a/src/helpers/errors.ts +++ b/src/helpers/errors.ts @@ -47,7 +47,7 @@ export default { 'Invalid Superfluid/AVAX receiver reward address. Please set it up in your CRN account profile', ), StreamNotSupported: new Error( - 'Stream payments are only supported on Avalanche', + 'Stream payments are only supported on Avalanche or Base', ), MaxFlowRate: new Error( `Current maximum total flow rate of 1 ALEPH/hour exceeded. Delete other instances or lower the VM cost`, diff --git a/src/helpers/schemas/base.ts b/src/helpers/schemas/base.ts index 845286f9..20d0391a 100644 --- a/src/helpers/schemas/base.ts +++ b/src/helpers/schemas/base.ts @@ -101,4 +101,8 @@ export const paymentMethodSchema = z.enum([ PaymentMethod.Stream, ]) -export const blockchainSchema = z.enum([BlockchainId.ETH, BlockchainId.AVAX]) +export const blockchainSchema = z.enum([ + BlockchainId.ETH, + BlockchainId.AVAX, + BlockchainId.BASE, +]) diff --git a/src/hooks/pages/computing/useNewInstancePage.ts b/src/hooks/pages/computing/useNewInstancePage.ts index c96cf944..b6ff25e0 100644 --- a/src/hooks/pages/computing/useNewInstancePage.ts +++ b/src/hooks/pages/computing/useNewInstancePage.ts @@ -1,7 +1,11 @@ import { useAppState } from '@/contexts/appState' import { FormEvent, useCallback, useEffect, useMemo } from 'react' import { useRouter } from 'next/router' -import { createFromAvalancheAccount } from '@aleph-sdk/superfluid' +import { + createFromEVMAccount, + isAccountSupported as isAccountPAYGCompatible, + isBlockchainSupported as isBlockchainPAYGCompatible, +} from '@aleph-sdk/superfluid' import { useForm } from '@/hooks/common/useForm' import { EnvVarField } from '@/hooks/form/useAddEnvVars' import { @@ -38,10 +42,10 @@ import { } from '@/hooks/form/useCheckoutNotification' import { EntityAddAction } from '@/store/entity' import { useConnection } from '@/hooks/common/useConnection' -import { AvalancheAccount } from '@aleph-sdk/avalanche' import Err from '@/helpers/errors' import { BlockchainId } from '@/domain/connect/base' import { PaymentConfiguration } from '@/domain/executable' +import { EVMAccount } from '@aleph-sdk/evm' export type NewInstanceFormState = NameAndTagsField & { image: InstanceImageField @@ -161,16 +165,14 @@ export function useNewInstancePage(): UseNewInstancePage { if (!isValid) throw Err.InvalidCRNSpecs if ( - blockchain !== BlockchainId.AVAX || - !(account instanceof AvalancheAccount) + !isBlockchainPAYGCompatible(blockchain) || + !isAccountPAYGCompatible(account) ) { handleConnect({ blockchain: BlockchainId.AVAX }) throw Err.InvalidNetwork } - // @note: refactor in SDK calling init inside this method - superfluidAccount = createFromAvalancheAccount(account) - await superfluidAccount.init() + superfluidAccount = await createFromEVMAccount(account as EVMAccount) payment = { chain: BlockchainId.AVAX, diff --git a/src/hooks/pages/solutions/manage/useManageInstance.ts b/src/hooks/pages/solutions/manage/useManageInstance.ts index 6bc4493a..9f36f88a 100644 --- a/src/hooks/pages/solutions/manage/useManageInstance.ts +++ b/src/hooks/pages/solutions/manage/useManageInstance.ts @@ -6,10 +6,13 @@ import { useAppState } from '@/contexts/appState' import { useInstanceStatus } from '@/hooks/common/useInstanceStatus' import { useSSHKeyManager } from '@/hooks/common/useManager/useSSHKeyManager' import { SSHKey } from '@/domain/ssh' -import { createFromAvalancheAccount } from '@aleph-sdk/superfluid' +import { + createFromEVMAccount, + isAccountSupported as isAccountPAYGCompatible, + isBlockchainSupported as isBlockchainPAYGCompatible, +} from '@aleph-sdk/superfluid' import { useConnection } from '@/hooks/common/useConnection' import { PaymentType } from '@aleph-sdk/message' -import { AvalancheAccount } from '@aleph-sdk/avalanche' import { useRequestInstances } from '@/hooks/common/useRequestEntity/useRequestInstances' import { EntityDelAction } from '@/store/entity' import { @@ -21,6 +24,7 @@ import { BlockchainId } from '@/domain/connect/base' import { useCopyToClipboardAndNotify, useNotification } from '@aleph-front/core' import { useNodeManager } from '@/hooks/common/useManager/useNodeManager' import { CRN } from '@/domain/node' +import { EVMAccount } from '@aleph-sdk/evm' export type ManageInstance = { instance?: Instance @@ -77,22 +81,18 @@ export function useManageInstance(): ManageInstance { }, [sshKeyManager, instance]) const handleEnsureNetwork = useCallback(async () => { - let superfluidAccount if (!instance) return if (instance.payment?.type === PaymentType.superfluid) { if ( - blockchain !== BlockchainId.AVAX || - !(account instanceof AvalancheAccount) + !isBlockchainPAYGCompatible(blockchain) || + !isAccountPAYGCompatible(account) ) { handleConnect({ blockchain: BlockchainId.AVAX }) - throw Err.ConnectYourPaymentWallet + throw Err.InvalidNetwork } - // @note: refactor in SDK calling init inside this method - superfluidAccount = createFromAvalancheAccount(account) - await superfluidAccount.init() - return superfluidAccount + return await createFromEVMAccount(account as EVMAccount) } else if (blockchain !== BlockchainId.ETH) { handleConnect({ blockchain: BlockchainId.ETH }) throw Err.ConnectYourPaymentWallet diff --git a/src/hooks/pages/useHeader.ts b/src/hooks/pages/useHeader.ts index d6d36fec..2d8a648d 100644 --- a/src/hooks/pages/useHeader.ts +++ b/src/hooks/pages/useHeader.ts @@ -95,6 +95,12 @@ export function useHeader(): UseHeaderReturn { name: 'Avalanche', wallets, }, + { + id: BlockchainId.BASE, + icon: 'base', + name: 'Base', + wallets, + }, ], [wallets], )