Skip to content

Commit

Permalink
feat: ✨ add icp provider and connect fnc
Browse files Browse the repository at this point in the history
  • Loading branch information
wilmacedo committed Feb 20, 2024
1 parent 39c5bab commit 2374d4a
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/icp/connect.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { NoAvailableAccountsError, NoProviderAvailableError } from '@/errors';
import { UserRejectedError } from '@/errors/user-rejected-error';
import { describe, expect, it, vi } from 'vitest';
import { web3Window } from '..';
import { connect } from './connect';

vi.mock('@/types', () => ({
web3Window: {
ic: {
requestConnect: vi.fn(),
plug: {
principalId: 'wil-123',
},
},
},
}))

const principalId = 'wil-123';

describe('Connect case', () => {
it('should successfully connects and retrieves an account', async () => {
web3Window.ic.requestConnect.mockResolvedValue(true)
const account = await connect()

expect(account).toEqual(principalId)
})

it('should throws error when no provider is available', async () => {
web3Window.ic.requestConnect.mockResolvedValue(false)

await expect(connect()).rejects.toThrow(NoProviderAvailableError)
})

it('should throws error when no accounts are available', async () => {
web3Window.ic.requestConnect.mockResolvedValue(true)
web3Window.ic.plug.principalId = undefined;

await expect(connect()).rejects.toThrow(NoAvailableAccountsError)
})

it('should throws error when the user rejects the connection', async () => {
web3Window.ic.requestConnect.mockRejectedValue(new Error('The agent creation was rejected'))

await expect(connect()).rejects.toThrow(UserRejectedError)
})
})
24 changes: 24 additions & 0 deletions src/icp/connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NoAvailableAccountsError, NoProviderAvailableError } from '@/errors';
import { UserRejectedError } from '@/errors/user-rejected-error';
import { web3Window } from '@/types';
import type { PrincipalAddress } from './types';

export async function connect(): Promise<PrincipalAddress> {
try {
const hasConnected = await web3Window.ic.requestConnect();
if (!hasConnected)
throw new NoProviderAvailableError()

const account: PrincipalAddress | undefined = web3Window.ic.plug.principalId;
if (!account || account.length === 0)
throw new NoAvailableAccountsError()

return account
}
catch (error) {
if ((error as Error).message.toLowerCase().includes('the agent creation was rejected'))
throw new UserRejectedError()

throw error
}
}
27 changes: 27 additions & 0 deletions src/icp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ProviderEntity } from '@/entities/provider-entity';
import type { Account, Balance } from '..';
import { connect } from './connect';

export class InternetComputerProvider implements ProviderEntity {
async connect(): Promise<Account[]> {
const principalAddress = await connect()

return [{ name: 'Principal Account', address: principalAddress }]
}

getBalance(address: string): Promise<Balance> {
throw new Error('Method not implemented.');
}

signMessage(address: string, message: string): Promise<string> {
throw new Error('Method not implemented.');
}

signatureVerify(message: string, signature: string, address: string): boolean {
throw new Error('Method not implemented.');
}

joinPool(address: string, poolId: number, amount: number): Promise<string> {
throw new Error('Method not implemented.');
}
}
1 change: 1 addition & 0 deletions src/icp/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type PrincipalAddress = string
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './ada/index'
export * from './icp/index'
export * from './networks'
export * from './substrate/dot/index'
export * from './substrate/ksm/index'
Expand Down
7 changes: 7 additions & 0 deletions src/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,19 @@ export const Networks = {
decimals: 5,
minStakeAmount: 1, // TODO: Validate min stake amount
},
icp: {
id: 4,
name: 'Internet Computer',
decimals: 5, // TODO: Validate decimals
minStakeAmount: 1, // TODO: Validate min stake amount
},
}

export enum Network {
POLKADOT = 'dot',
KUSAMA = 'ksm',
CARDANO = 'ada',
INTERNET_COMPUTER = 'icp',
}

export type NetworkKey = keyof typeof Networks
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type ProviderBuilderProps<T extends NetworkKey> = T extends 'dot' | 'ksm'
export type Web3Window = {
injectedWeb3: any
cardano: any
ic: any
} & Window & typeof globalThis

export const web3Window = (window as Web3Window)
3 changes: 3 additions & 0 deletions src/web3-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CardanoProvider } from './ada';
import type { CardanoProviderProps } from './ada/types';
import type { ProviderEntity } from './entities/provider-entity';
import { InvalidNetworkError } from './errors/invalid-network-error';
import { InternetComputerProvider } from './icp';
import type { NetworkData, NetworkKey } from './networks';
import { getNetworkKeyById, isValidNetwork } from './networks';
import { PolkadotProvider } from './substrate/dot';
Expand Down Expand Up @@ -33,6 +34,8 @@ export class Web3Provider {
return new KusamaProvider(props as SubstrateProviderProps)
case 'ada':
return new CardanoProvider(props as CardanoProviderProps)
case 'icp':
return new InternetComputerProvider()
default:
throw new InvalidNetworkError()
}
Expand Down

0 comments on commit 2374d4a

Please sign in to comment.