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 program counter, fix types issue #2145

Merged
merged 27 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bd136a3
Add program counter, fix types issue
gooxpf Apr 12, 2024
f699c2f
Fix current chain issue
gooxpf Apr 12, 2024
879b799
Fix signAndSend transaction types
gooxpf Apr 12, 2024
9ef2433
Remove unnecessary chain, minor code style fixing
gooxpf Apr 12, 2024
3f6a7eb
Remove local net program id
gooxpf Apr 12, 2024
69cae33
Remove local net from program counter test
gooxpf Apr 12, 2024
410ebbd
Remove console error
gooxpf Apr 12, 2024
076cd4f
Add getWalletProvider and getWalletProviderType to solana modal
gooxpf Apr 16, 2024
90dfb32
Add get wallet connection
gooxpf Apr 16, 2024
616f5e7
Merge branch 'V4' of github.com:WalletConnect/web3modal into feat/sol…
gooxpf Apr 17, 2024
177e942
chore: enable wallet tests for solana
gooxpf Apr 17, 2024
243470b
Merge branch 'V4' of github.com:WalletConnect/web3modal into feat/sol…
gooxpf Apr 17, 2024
db78483
Merge branch 'V4' of github.com:WalletConnect/web3modal into feat/sol…
gooxpf Apr 18, 2024
8496655
Changed returns to throw error
gooxpf Apr 18, 2024
02ba6fa
Merge remote-tracking branch 'origin/feat/solana-program-counter-v3' …
gooxpf Apr 18, 2024
12fe487
Remove unnecessary comment
gooxpf Apr 18, 2024
2d56a30
Rename error message, and check airdropped balance, minor imports imp…
gooxpf Apr 19, 2024
5ee921e
Fix solana scaffold imports
gooxpf Apr 19, 2024
775b4cf
Merge branch 'V4' of github.com:WalletConnect/web3modal into feat/sol…
gooxpf Apr 19, 2024
a4f0700
Fix imports style
gooxpf Apr 19, 2024
df48194
Remove unnecessary comment
gooxpf Apr 19, 2024
7b35aec
Fix import types in client
gooxpf Apr 19, 2024
a9293de
Add connection settings to w3m modal
gooxpf Apr 19, 2024
2ef1b2e
Remove airdrop from solana contract
gooxpf Apr 19, 2024
e430f0a
Add confirmed default value for connection
gooxpf Apr 19, 2024
fe61b4c
Merge branch 'V4' of github.com:WalletConnect/web3modal into feat/sol…
gooxpf Apr 19, 2024
22327d2
Merge branch 'V4' into feat/solana-program-counter-v3
enesozturk Apr 19, 2024
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
14 changes: 13 additions & 1 deletion apps/laboratory/src/components/Solana/SolanaTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
import { SolanaSignTransactionTest } from './SolanaSignTransactionTest'
import { SolanaSendTransactionTest } from './SolanaSendTransactionTest'
import { SolanaSignMessageTest } from './SolanaSignMessageTest'
import { solana } from '../../utils/ChainsUtil'
import { SolanaWriteContractTest } from './SolanaWriteContractTest'
import { solana, solanaDevnet, solanaTestnet } from '../../utils/ChainsUtil'

export function SolanaTests() {
const { isConnected, currentChain } = useWeb3ModalAccount()
Expand Down Expand Up @@ -51,6 +52,17 @@ export function SolanaTests() {
</Heading>
<SolanaSendTransactionTest />
</Box>
{(currentChain?.chainId === solanaTestnet.chainId ||
currentChain?.chainId === solanaDevnet.chainId) && (
<Stack divider={<StackDivider />} spacing="4">
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Counter Program Instruction
</Heading>
<SolanaWriteContractTest />
</Box>
</Stack>
)}
</Stack>
</CardBody>
</Card>
Expand Down
121 changes: 121 additions & 0 deletions apps/laboratory/src/components/Solana/SolanaWriteContractTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState } from 'react'
import { Button, useToast } from '@chakra-ui/react'
import {
SystemProgram,
PublicKey,
Keypair,
Transaction,
TransactionInstruction,
LAMPORTS_PER_SOL,
Connection
} from '@solana/web3.js'
import { useWeb3ModalAccount, useWeb3ModalProvider } from '@web3modal/solana/react'

import { COUNTER_ACCOUNT_SIZE } from '../../utils/SolanaConstants'
import { deserializeCounterAccount, detectProgramId } from '../../utils/SolanaUtil'

export function SolanaWriteContractTest() {
const toast = useToast()
const { address, currentChain } = useWeb3ModalAccount()
const { walletProvider, connection } = useWeb3ModalProvider()
const [loading, setLoading] = useState(false)

async function onIncrementCounter() {
setLoading(true)

const PROGRAM_ID = new PublicKey(detectProgramId(currentChain?.chainId ?? ''))

try {
if (!walletProvider || !address) {
throw new Error('User is disconnected')
}

if (!connection) {
throw new Error('No connection set')
}

const counterKeypair = Keypair.generate()
const counter = counterKeypair.publicKey

const balance = await connection.getBalance(walletProvider.publicKey)
if (balance < LAMPORTS_PER_SOL / 100) {
const airdropConnection = new Connection(currentChain?.rpcUrl ?? '')
const signature = await airdropConnection.requestAirdrop(
walletProvider.publicKey,
LAMPORTS_PER_SOL
)

const latestBlockHash = await connection.getLatestBlockhash()
await airdropConnection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature
})
throw Error('Not enough SOL in wallet')
gooxpf marked this conversation as resolved.
Show resolved Hide resolved
}

const allocIx: TransactionInstruction = SystemProgram.createAccount({
fromPubkey: walletProvider.publicKey,
newAccountPubkey: counter,
lamports: await connection.getMinimumBalanceForRentExemption(COUNTER_ACCOUNT_SIZE),
space: COUNTER_ACCOUNT_SIZE,
programId: PROGRAM_ID
})

const incrementIx: TransactionInstruction = new TransactionInstruction({
programId: PROGRAM_ID,
keys: [
{
pubkey: counter,
isSigner: false,
isWritable: true
}
],
data: Buffer.from([0x0])
})

const tx = new Transaction().add(allocIx).add(incrementIx)

tx.feePayer = walletProvider.publicKey
tx.recentBlockhash = (await connection.getLatestBlockhash('confirmed')).blockhash

await walletProvider.signAndSendTransaction(tx, [counterKeypair])

const counterAccountInfo = await connection.getAccountInfo(counter, {
commitment: 'confirmed'
})

if (!counterAccountInfo) {
throw new Error('Expected counter account to have been created')
}

const counterAccount = deserializeCounterAccount(counterAccountInfo?.data)

if (counterAccount.count !== 1) {
throw new Error('Expected count to have been 1')
}

toast({
title: 'Succcess',
description: `[alloc+increment] count is: ${counterAccount.count}`,
status: 'success',
isClosable: true
})
} catch (err) {
toast({
title: 'Transaction failed',
description: 'Failed to increment counter',
status: 'error',
isClosable: true
})
} finally {
setLoading(false)
}
}

return (
<Button isDisabled={loading} data-testid="sign-message-button" onClick={onIncrementCounter}>
Increment Counter With Sign
</Button>
)
}
18 changes: 18 additions & 0 deletions apps/laboratory/src/utils/SolanaConstants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { solana, solanaDevnet, solanaTestnet } from './ChainsUtil'

export const COUNTER_ACCOUNT_SIZE = 8

export const SolanaConstantsUtil = {
// You can add local net in chains if you're using local validator
chains: [solana, solanaTestnet, solanaDevnet],
programIds: [
{
chainId: solanaDevnet.chainId,
programId: 'Cb5aXEgXptKqHHWLifvXu5BeAuVLjojQ5ypq6CfQj1hy'
},
{
chainId: solanaTestnet.chainId,
programId: 'FZn4xQoKKvcxDADDRdqNAAPnVv9qYCbUTbP3y4Rn1BBr'
}
]
}
15 changes: 15 additions & 0 deletions apps/laboratory/src/utils/SolanaUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SolanaConstantsUtil } from './SolanaConstants'

export function deserializeCounterAccount(data?: Buffer): { count: number } {
if (data?.byteLength !== 8) {
throw Error('Need exactly 8 bytes to deserialize counter')
}

return {
count: Number(data[0])
}
}

export function detectProgramId(chainId: string): string {
return SolanaConstantsUtil.programIds.find(chain => chain.chainId === chainId)?.programId ?? ''
}
8 changes: 4 additions & 4 deletions apps/laboratory/tests/shared/utils/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ const customProjectProperties: CustomProjectProperties = {
},
// Exclude email.spec.ts, siwe.spec.ts, and canary.spec.ts from solana, not yet implemented
'Desktop Chrome/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts|wallet\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Brave/solana': {
useOptions: braveOptions,
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts|wallet\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Firefox/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts|wallet\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Safari/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts|wallet\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/solana/exports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Web3Modal } from '../src/client.js'

import type { Web3ModalOptions } from '../src/client.js'

export type { Web3ModalOptions } from '../src/client.js'
export type { Web3Modal, Web3ModalOptions } from '../src/client.js'

export { defaultSolanaConfig } from '../src/utils/defaultConfig.js'

Expand Down
6 changes: 5 additions & 1 deletion packages/solana/exports/react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import { getWeb3Modal } from '@web3modal/scaffold-react'

import { Web3Modal } from '../src/client.js'

import { SolStoreUtil } from '../src/utils/scaffold/SolanaStoreUtil.js'

import type { Web3ModalOptions } from '../src/client.js'
import type { Provider } from '../src/utils/scaffold/SolanaTypesUtil.js'
import { SolStoreUtil } from '../src/utils/scaffold/SolanaStoreUtil.js'

// -- Setup -------------------------------------------------------------------
let modal: Web3Modal | undefined = undefined

// -- Types -------------------------------------------------------------------
export type { Web3Modal, Web3ModalOptions } from '../src/client.js'

export function createWeb3Modal(options: Web3ModalOptions) {
if (!modal) {
modal = new Web3Modal({
Expand Down
12 changes: 12 additions & 0 deletions packages/solana/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ export class Web3Modal extends Web3ModalScaffold {
return address ? SolStoreUtil.state.address : address
}

public getWalletProvider() {
return SolStoreUtil.state.provider
}

public getWalletProviderType() {
return SolStoreUtil.state.providerType
}

public getWalletConnection() {
return SolStoreUtil.state.connection
}

public async checkActiveProviders() {
const walletId = localStorage.getItem(SolConstantsUtil.WALLET_ID)

Expand Down
6 changes: 6 additions & 0 deletions packages/solana/src/connectors/baseConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { SolStoreUtil } from '../utils/scaffold/SolanaStoreUtil.js'
import { getHashedName, getNameAccountKey } from '../utils/hash.js'
import { NameRegistry } from '../utils/nameService.js'

import type { ConfirmOptions, Signer, TransactionSignature } from '@solana/web3.js'
import type {
BlockResult,
AccountInfo,
Expand All @@ -40,6 +41,11 @@ export interface Connector {
transaction: Transaction | VersionedTransaction
) => Promise<{ signatures: { signature: string }[] }>
sendTransaction: (transaction: Transaction | VersionedTransaction) => Promise<string>
signAndSendTransaction: (
transaction: Transaction | VersionedTransaction,
signers: Signer[],
confirmOptions?: ConfirmOptions
) => Promise<TransactionSignature>
getAccount: (
requestedAddress?: string,
encoding?: 'base58' | 'base64' | 'jsonParsed'
Expand Down
7 changes: 4 additions & 3 deletions packages/solana/src/connectors/universalProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ export class UniversalProviderFactory {
public static async getProvider() {
if (!UniversalProviderFactory.provider) {
await UniversalProviderFactory.init()
}
if (!UniversalProviderFactory.provider) {
throw new Error('Failed to initialize universal provider')

if (!UniversalProviderFactory.provider) {
throw new Error('Failed to initialize universal provider')
}
}

return UniversalProviderFactory.provider
Expand Down
3 changes: 2 additions & 1 deletion packages/solana/src/connectors/walletAdapters.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom'
import { SolflareWalletAdapter } from '@solana/wallet-adapter-solflare'
import { TrustWalletAdapter } from '@solana/wallet-adapter-trust'
import { BackpackWalletAdapter } from '@solana/wallet-adapter-backpack'

import { PhantomWalletAdapter } from './walletAdapters/index.js'

import type { BaseWalletAdapter } from '@solana/wallet-adapter-base'
import type { Connector } from '@web3modal/scaffold'

Expand Down
47 changes: 47 additions & 0 deletions packages/solana/src/connectors/walletAdapters/PhantomAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { PhantomWalletAdapter as SolanaPhantomWalletAdapter } from '@solana/wallet-adapter-phantom'
import { Transaction, VersionedTransaction } from '@solana/web3.js'

import { SolStoreUtil } from '../../utils/scaffold/index.js'

import type { ConfirmOptions, Signer } from '@solana/web3.js'

export class PhantomWalletAdapter extends SolanaPhantomWalletAdapter {
async signAndSendTransaction(
transactionParam: Transaction | VersionedTransaction,
signers: Signer[],
confirmOptions?: ConfirmOptions
) {
if (!SolStoreUtil.state.connection) {
throw Error('Not Connected')
}

if (transactionParam instanceof VersionedTransaction) {
throw Error('it doesnt work with versioned transaction')
gooxpf marked this conversation as resolved.
Show resolved Hide resolved
}

if (signers.length) {
transactionParam.partialSign(...signers)
}

const signature = await this.sendTransaction(
transactionParam,
SolStoreUtil.state.connection,
confirmOptions
)

if (signature) {
const latestBlockHash = await SolStoreUtil.state.connection?.getLatestBlockhash()
if (latestBlockHash?.blockhash) {
await SolStoreUtil.state.connection?.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature
})

return signature
}
}

throw Error('Transaction Failed')
}
}
1 change: 1 addition & 0 deletions packages/solana/src/connectors/walletAdapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PhantomWalletAdapter } from './PhantomAdapter.js'
Loading
Loading