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

Feature/phantom new #143

Merged
merged 7 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
"@heroicons/vue": "^1.0.6",
"@ledgerhq/hw-app-eth": "^6.29.4",
"@ledgerhq/hw-transport-webusb": "^6.27.4",
"@solana/web3.js": "^1.63.1",
"@walletconnect/client": "^1.8.0",
"@walletconnect/qrcode-modal": "^1.8.0",
"borsh": "^0.7.0",
"buffer": "^6.0.3",
"ethers": "^5.6.9",
"iotex-antenna": "^0.31.3",
Expand Down
87 changes: 64 additions & 23 deletions apps/web/src/components/Wallet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
</p>
</div>
<div class="coinbase-div">
<button class="coinbase-btn" @click="connectWallet('CoinbaseWallet')">
<button
class="coinbase-btn"
@click="connectWallet('CoinbaseWallet')"
>
{{ coinbaseButtonText }}
</button>
<p>
Expand All @@ -20,15 +23,33 @@
</p>
</div>
<div class="ioPay-div">
<button class="iopay-btn" @click="connectWallet('IoPay')">
<button
class="iopay-btn"
@click="connectWallet('IoPay')"
>
{{ ioPayButtonText }}
</button>
<p>
Connected ioPay Account:
<span> {{ ioPayAccountsResult }} </span>
</p>
</div>
<button class="ledger-btn" @click="connectWallet('Ledger')">
<div class="phantom-div">
<button
class="phantom-btn"
@click="connectWallet('Phantom')"
>
{{ phantomButtonText }}
</button>
<p>
Connected phantom Account:
<span> {{ phantomAccountsResult }} </span>
</p>
</div>
<button
class="ledger-btn"
@click="connectWallet('Ledger')"
>
Connect Ledger
</button>
<div>
Expand All @@ -38,18 +59,6 @@
>
WalletConnect
</button>
<button
class="wallet-connect-btn"
@click="sendTransaction('WalletConnect')"
>
Send WalletConnect Transaction
</button>
<button
class="wallet-connect-btn"
@click="disconnectWallet('WalletConnect')"
>
Disable WalletConnect
</button>
</div>
</div>
<div class="form-container">
Expand All @@ -58,17 +67,29 @@
v-model="message"
type="text"
placeholder="Write a message to sign"
/>
<button @click="signMessage(message)">Sign Message</button>
>
<button @click="signMessage(message)">
Sign Message
</button>
<p>{{ signedMessage }}</p>
</div>
<form @submit.prevent="sendTransaction(selectedProvider)">
<form @submit.prevent="sendTransaction()">
<label for="address">Address</label>
<input v-model="toAddress" type="text" placeholder="To Address" />
<br />
<input
v-model="toAddress"
type="text"
placeholder="To Address"
>
<br>
<label for="amount">Amount</label>
<input v-model="amount" type="text" placeholder="Amount Ether" />
<button type="submit">Send Transaction</button>
<input
v-model="amount"
type="text"
placeholder="Amount Ether"
>
<button type="submit">
Send Transaction
</button>
</form>
</div>
</div>
Expand All @@ -87,14 +108,15 @@ const coinbaseButtonText = ref<string>('Connect Coinbase')
const coinbaseAccountsResult = ref<string>('Address Not Active')
const ioPayButtonText = ref<string>('Connect ioPay')
const ioPayAccountsResult = ref<string>('Address Not Active')
const phantomButtonText = ref<string>('Connect Phantom')
const phantomAccountsResult = ref<string>('Address Not Active')

const {
selectedProvider,
selectedAccount,
toAddress,
amount,
connectWallet,
disconnectWallet,
sendTransaction,
signMessage,
} = useWallet()
Expand All @@ -107,20 +129,35 @@ watchEffect(() => {
ioPayButtonText.value = 'Connect ioPay'
coinbaseAccountsResult.value = 'Not Active'
ioPayAccountsResult.value = 'Not Active'
phantomButtonText.value = 'Connect Phantom'
phantomAccountsResult.value = 'Not Active'
} else if (selectedProvider.value === 'CoinbaseWallet') {
metamaskButtonText.value = 'Connect Metamask'
coinbaseButtonText.value = 'Coinbase Connected'
ioPayButtonText.value = 'Connect ioPay'
metamaskAccountsResult.value = 'Not Active'
coinbaseAccountsResult.value = selectedAccount.value
ioPayAccountsResult.value = 'Not Active'
phantomButtonText.value = 'Connect Phantom'
phantomAccountsResult.value = 'Not Active'
} else if (selectedProvider.value === 'IoPay') {
metamaskButtonText.value = 'Connect MetaMask'
coinbaseButtonText.value = 'Connect Coinbase'
ioPayButtonText.value = 'Connected'
metamaskAccountsResult.value = 'Not Active'
coinbaseAccountsResult.value = 'Not Active'
ioPayAccountsResult.value = selectedAccount.value || 'Not Active'
phantomButtonText.value = 'Connect Phantom'
phantomAccountsResult.value = 'Not Active'
} else if (selectedProvider.value === 'Phantom') {
metamaskButtonText.value = 'Connect MetaMask'
coinbaseButtonText.value = 'Connect Coinbase'
ioPayButtonText.value = 'Connect ioPay'
phantomButtonText.value = 'Connected'
metamaskAccountsResult.value = 'Not Active'
coinbaseAccountsResult.value = 'Not Active'
ioPayAccountsResult.value = 'Not Active'
phantomAccountsResult.value = selectedAccount.value || 'Not Active'
}
})
</script>
Expand Down Expand Up @@ -168,6 +205,10 @@ button {
background-color: rgb(0, 0, 0);
}

.phantom-btn {
background-color: purple;
}

.connect-wallet-container {
display: flex;
flex-direction: column;
Expand Down
68 changes: 68 additions & 0 deletions apps/web/src/composables/solana.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { ref } from 'vue'
import {
Connection,
Transaction,
SystemProgram,
PublicKey,
} from '@solana/web3.js'
import { BrowserProviders } from '@/interfaces/BrowserProviders'
import { ProviderString } from '@/types/ProviderString'
import { TransactionInit } from '@/interfaces/TransactionInit'
import { MessageInit } from '@/interfaces/MessageInit'

export default function useSolana() {
const solanaProviderList = ['Phantom']
const availableProviders = ref<BrowserProviders>(getBrowserProviders())
const solanaPublicKey = ref({})

async function requestSolanaAddress(provider: ProviderString) {
const phantomProvider =
availableProviders.value[provider as keyof BrowserProviders]
const resp = await phantomProvider.connect()
solanaPublicKey.value = resp.publicKey
const address = resp.publicKey.toString()
return address
}

async function sendSolanaTransaction({ from, to, value, providerString }: TransactionInit) {
const network = 'https://api.devnet.solana.com'
const connection = new Connection(network)
const { blockhash } = await connection.getLatestBlockhash('finalized')
const toAddress = new PublicKey(to)
const fromAddress = new PublicKey(from)
const lamports = Number(value) * 1000000000
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromAddress,
toPubkey: toAddress,
lamports,
})
)
transaction.feePayer = fromAddress
transaction.recentBlockhash = blockhash
const { signature } = await availableProviders.value[providerString as keyof BrowserProviders]
.signAndSendTransaction(transaction)
const signatureStatus = await connection.getSignatureStatus(signature)
return signatureStatus
}

async function signSolanaMessage(messageInit: MessageInit): Promise<string> {
const { providerString, hashedMessage } = messageInit
const { signature } = await availableProviders.value[providerString as keyof BrowserProviders]
.signMessage(hashedMessage)
return signature
}

return { solanaProviderList, requestSolanaAddress, sendSolanaTransaction, signSolanaMessage }
}

function getBrowserProviders() {
const phantom: any = window.phantom?.solana?.isPhantom
? window.phantom?.solana
: undefined
const providers = {
Phantom: undefined,
}
providers.Phantom = phantom
return providers
}
45 changes: 25 additions & 20 deletions apps/web/src/composables/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ import useIoPay from '@/composables/iopay'
import useLedger from '@/composables/ledger'
import useEthers from '@/composables/ethers'
import useWalletConnect from '@/composables/walletConnect'
import useSolana from '@/composables/solana'
import { ProviderString } from '@/types/ProviderString'
import { TransactionInit } from '@/interfaces/TransactionInit'
import { MessageInit } from '@/interfaces/MessageInit'

const { ethersProviderList, requestEthersAccount, sendEthersTransaction, signEthersMessage } = useEthers()
const {
enableWalletConnect,
disableWalletConnect,
sendWalletConnectTransaction,
} = useWalletConnect()
const { enableWalletConnect, disableWalletConnect, sendWalletConnectTransaction } = useWalletConnect()
const { solanaProviderList, requestSolanaAddress, sendSolanaTransaction, signSolanaMessage } = useSolana()

const amount = ref<string>('0.001')
const toAddress = ref<string>('0x728474D29c2F81eb17a669a7582A2C17f1042b57')
const toAddress = ref<string>('7aVow9eVQjwn7Y4y7tAbPM1pfrE1TzjmJhxcRt8QwX5F')
// Test ethereum send to address : 0xD4e5faa8aD7d499Aa03BDDE2a3116E66bc8F8203
// Test solana address: 7aVow9eVQjwn7Y4y7tAbPM1pfrE1TzjmJhxcRt8QwX5F
// Test iotex send to address: acc://06da5e904240736b1e21ca6dbbd5f619860803af04ff3d54/acme

export default function useWallet() {
Expand Down Expand Up @@ -51,6 +50,9 @@ export default function useWallet() {
const accounts = await requestEthersAccount(provider as ProviderString)
const address = accounts[0]
setSelectedAccount(address)
} else if (solanaProviderList.includes(provider)) {
const address = await requestSolanaAddress(provider as ProviderString)
setSelectedAccount(address)
} else if (provider === 'IoPay') {
const accounts = await getIoPayAccounts()
const { address } = accounts[0]
Expand All @@ -67,23 +69,25 @@ export default function useWallet() {
}
}

async function sendTransaction(providerString: ProviderString) {
const tx: TransactionInit = {
async function sendTransaction() {
const txInit: TransactionInit = {
from: selectedAccount.value,
to: toAddress.value,
value: amount.value,
providerString
providerString: selectedProvider.value
}

try {
if (providerString === 'WalletConnect') {
await sendWalletConnectTransaction(tx)
} else if (ethersProviderList.includes(providerString)) {
await sendEthersTransaction(tx)
if (txInit.providerString === 'WalletConnect') {
await sendWalletConnectTransaction(txInit)
} else if (ethersProviderList.includes(txInit.providerString)) {
await sendEthersTransaction(txInit)
} else if (solanaProviderList.includes(txInit.providerString)) {
await sendSolanaTransaction(txInit)
} else if (selectedProvider.value === 'IoPay') {
await sendIoPayTransaction(tx)
await sendIoPayTransaction(txInit)
} else if (selectedProvider.value === 'Ledger') {
await sendLedgerTransaction(tx)
await sendLedgerTransaction(txInit)
} else {
throw new Error('Provider selected not yet supported')
}
Expand All @@ -93,18 +97,19 @@ export default function useWallet() {
}

async function signMessage(message: string) {
const hashedMessage = ethers.utils.id(message)
const messageInit: MessageInit = {
hashedMessage,
hashedMessage: ethers.utils.id(message),
providerString: selectedProvider.value,
}
// TODO: Mock sending hash and signature to backend for verification
try {
if (ethersProviderList.includes(selectedProvider.value)) {
if (ethersProviderList.includes(messageInit.providerString)) {
await signEthersMessage(messageInit)
} else if (selectedProvider.value === 'IoPay') {
} else if (solanaProviderList.includes(messageInit.providerString)) {
await signSolanaMessage(messageInit)
} else if (messageInit.providerString === 'IoPay') {
await signIoPayMessage(messageInit)
} else if (selectedProvider.value === 'Ledger') {
} else if (messageInit.providerString === 'Ledger') {
await signLedgerMessage(messageInit)
} else {
console.log('signMessage not yet supported for this wallet provider')
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ declare type APIGatewayResponse = {
declare global {
interface Window {
ethereum: any;
phantom: any;
}
}
1 change: 1 addition & 0 deletions apps/web/src/interfaces/BrowserProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import { EthersProvider } from '@/interfaces/EthersProvider'
export interface BrowserProviders {
MetaMask?: EthersProvider
CoinbaseWallet?: EthersProvider
Phantom?: any // TODO: Fix this.
}
4 changes: 2 additions & 2 deletions apps/web/src/interfaces/TransactionInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export interface TransactionInit extends ethers.providers.TransactionRequest {
to: string;
/** The value of the transaction */
value: string;
/** The optional provider of the transaction */
providerString?: ProviderString;
/** The provider string of the transaction */
providerString: ProviderString;
}
1 change: 1 addition & 0 deletions apps/web/src/types/ProviderString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export type ProviderString =
| 'IoPay'
| 'Ledger'
| 'WalletConnect'
| 'Phantom'
| ''
Loading