add evm send with native and erc-20 token support
This commit is contained in:
@@ -16,7 +16,8 @@
|
|||||||
"build:native": "swiftc -O -o src/bun/native/biometric-helper src/bun/native/biometric-helper.swift"
|
"build:native": "swiftc -O -o src/bun/native/biometric-helper src/bun/native/biometric-helper.swift"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alchemy/wallet-apis": "^5.0.0-beta.28",
|
"@alchemy/common": "^5.0.0",
|
||||||
|
"@alchemy/wallet-apis": "^5.0.0",
|
||||||
"@koins/utils": "workspace:*",
|
"@koins/utils": "workspace:*",
|
||||||
"drizzle-orm": "^1.0.0-beta.22",
|
"drizzle-orm": "^1.0.0-beta.22",
|
||||||
"electrobun": "^1.18.1",
|
"electrobun": "^1.18.1",
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import { syncTransactionHistory } from '../../lib/sync'
|
|||||||
import { eq, and } from 'drizzle-orm'
|
import { eq, and } from 'drizzle-orm'
|
||||||
import { db } from '../../lib/db'
|
import { db } from '../../lib/db'
|
||||||
import { getClient } from '../../lib/viem'
|
import { getClient } from '../../lib/viem'
|
||||||
import { formatGwei } from 'viem'
|
import { formatGwei, parseEther, parseUnits, encodeFunctionData, createWalletClient } from 'viem'
|
||||||
|
import { mnemonicToAccount } from 'viem/accounts'
|
||||||
|
import { getChain } from '../../lib/viem/getChain'
|
||||||
|
import { getChainID } from '../../lib/alchemy/network'
|
||||||
|
import { alchemyTransport } from '@alchemy/common'
|
||||||
import { sqlite } from '../../lib/sqlite'
|
import { sqlite } from '../../lib/sqlite'
|
||||||
import { txHistory, evmWallets } from '../../lib/db/schema'
|
import { txHistory, evmWallets } from '../../lib/db/schema'
|
||||||
import type {
|
import type {
|
||||||
@@ -566,5 +570,64 @@ export function createEvmHandlers(
|
|||||||
db.delete(evmWallets).where(eq(evmWallets.id, id)).run()
|
db.delete(evmWallets).where(eq(evmWallets.id, id)).run()
|
||||||
console.log('[rpc] evmDeleteWallet complete')
|
console.log('[rpc] evmDeleteWallet complete')
|
||||||
},
|
},
|
||||||
|
evmSendTransfer: async ({
|
||||||
|
seed,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
chainid,
|
||||||
|
contractAddress,
|
||||||
|
tokenDecimals,
|
||||||
|
}: {
|
||||||
|
seed: string
|
||||||
|
to: string
|
||||||
|
amount: string
|
||||||
|
chainid: string
|
||||||
|
contractAddress?: string
|
||||||
|
tokenDecimals?: number
|
||||||
|
}) => {
|
||||||
|
const key = await Bun.secrets.get({
|
||||||
|
service: 'koins',
|
||||||
|
name: 'alchemy_key',
|
||||||
|
})
|
||||||
|
if (!key) throw new Error('API key not set')
|
||||||
|
const account = mnemonicToAccount(seed)
|
||||||
|
const id = getChainID(chainid)
|
||||||
|
if (!id) throw new Error('Unsupported chain')
|
||||||
|
const chain = getChain(id)
|
||||||
|
const walletClient = createWalletClient({
|
||||||
|
account,
|
||||||
|
chain,
|
||||||
|
transport: alchemyTransport({ apiKey: key }),
|
||||||
|
})
|
||||||
|
if (contractAddress && tokenDecimals !== undefined) {
|
||||||
|
const erc20Abi = [
|
||||||
|
{
|
||||||
|
name: 'transfer',
|
||||||
|
type: 'function',
|
||||||
|
inputs: [
|
||||||
|
{ name: 'to', type: 'address' },
|
||||||
|
{ name: 'amount', type: 'uint256' },
|
||||||
|
],
|
||||||
|
outputs: [{ name: '', type: 'bool' }],
|
||||||
|
},
|
||||||
|
] as const
|
||||||
|
const data = encodeFunctionData({
|
||||||
|
abi: erc20Abi,
|
||||||
|
functionName: 'transfer',
|
||||||
|
args: [to as `0x${string}`, parseUnits(amount, tokenDecimals)],
|
||||||
|
})
|
||||||
|
const hash = await walletClient.sendTransaction({
|
||||||
|
to: contractAddress as `0x${string}`,
|
||||||
|
data,
|
||||||
|
value: 0n,
|
||||||
|
})
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
const hash = await walletClient.sendTransaction({
|
||||||
|
to: to as `0x${string}`,
|
||||||
|
value: parseEther(amount),
|
||||||
|
})
|
||||||
|
return hash
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -487,6 +487,11 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="flex gap-2 flex-wrap">
|
<div class="flex gap-2 flex-wrap">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onclick={() => navigate('/multicoin/send')}>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onclick={() => navigate('/settings')}>
|
onclick={() => navigate('/settings')}>
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ export type TransactionDetails = {
|
|||||||
|
|
||||||
export type TokenBalanceResult = {
|
export type TokenBalanceResult = {
|
||||||
symbol: string
|
symbol: string
|
||||||
|
decimals: number
|
||||||
balance: string
|
balance: string
|
||||||
contractAddress: string
|
contractAddress: string
|
||||||
logo?: string
|
logo?: string
|
||||||
@@ -163,6 +164,7 @@ export type EvmRpcRequests = {
|
|||||||
evmListWallets: { params: {}; response: EvmWalletInfo[] }
|
evmListWallets: { params: {}; response: EvmWalletInfo[] }
|
||||||
evmGetSeed: { params: { vaultKey: string }; response: string }
|
evmGetSeed: { params: { vaultKey: string }; response: string }
|
||||||
evmDeleteWallet: { params: { id: string }; response: void }
|
evmDeleteWallet: { params: { id: string }; response: void }
|
||||||
|
evmSendTransfer: { params: { seed: string; to: string; amount: string; chainid: string; contractAddress?: string; tokenDecimals?: number }; response: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MoneroRpcRequests = {
|
export type MoneroRpcRequests = {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export type NetworkId = (typeof networks)[number]['id']
|
|||||||
|
|
||||||
export type TokenBalance = {
|
export type TokenBalance = {
|
||||||
symbol: string
|
symbol: string
|
||||||
|
decimals: number
|
||||||
balance: string
|
balance: string
|
||||||
contractAddress: string
|
contractAddress: string
|
||||||
logo?: string
|
logo?: string
|
||||||
@@ -406,6 +407,25 @@ export const EvmWallet = () => {
|
|||||||
transactions = txs ?? []
|
transactions = txs ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const send = async (
|
||||||
|
to: string,
|
||||||
|
amount: string,
|
||||||
|
contractAddress?: string,
|
||||||
|
tokenDecimals?: number,
|
||||||
|
) => {
|
||||||
|
if (!electrobun.rpc || !seed) throw new Error('Wallet not unlocked')
|
||||||
|
const hash = await electrobun.rpc.request.evmSendTransfer({
|
||||||
|
seed,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
chainid: net().chainid,
|
||||||
|
contractAddress,
|
||||||
|
tokenDecimals,
|
||||||
|
})
|
||||||
|
await refresh()
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
const lock = () => {
|
const lock = () => {
|
||||||
clearWallet()
|
clearWallet()
|
||||||
}
|
}
|
||||||
@@ -531,6 +551,7 @@ export const EvmWallet = () => {
|
|||||||
unlockWallet,
|
unlockWallet,
|
||||||
deleteWallet,
|
deleteWallet,
|
||||||
clearSelection,
|
clearSelection,
|
||||||
|
send,
|
||||||
syncTxHistory,
|
syncTxHistory,
|
||||||
setAutoSync,
|
setAutoSync,
|
||||||
flushTxCache,
|
flushTxCache,
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { evmWallet as wallet } from '$lib/states/evm-wallet.svelte.js'
|
||||||
|
import { Button } from '$lib/components/ui/button/index.js'
|
||||||
|
import { Input } from '$lib/components/ui/input/index.js'
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
} from '$lib/components/ui/select/index.js'
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
} from '$lib/components/ui/card/index.js'
|
||||||
|
import { navigate } from 'sv-router/generated'
|
||||||
|
|
||||||
|
const w = wallet
|
||||||
|
|
||||||
|
type TokenOption = {
|
||||||
|
symbol: string
|
||||||
|
balance: string
|
||||||
|
contractAddress: string
|
||||||
|
decimals: number
|
||||||
|
logo?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokens = $derived<TokenOption[]>([
|
||||||
|
{
|
||||||
|
symbol: w.symbol,
|
||||||
|
balance: w.balance,
|
||||||
|
contractAddress: '',
|
||||||
|
decimals: 18,
|
||||||
|
},
|
||||||
|
...w.tokenBalances.map((t) => ({
|
||||||
|
symbol: t.symbol,
|
||||||
|
balance: t.balance,
|
||||||
|
contractAddress: t.contractAddress,
|
||||||
|
decimals: t.decimals,
|
||||||
|
logo: t.logo,
|
||||||
|
})),
|
||||||
|
])
|
||||||
|
|
||||||
|
let selectedSymbol = $state(w.symbol)
|
||||||
|
let recipient = $state('')
|
||||||
|
let amount = $state('')
|
||||||
|
let sending = $state(false)
|
||||||
|
let sentResult = $state<{ txHash: string } | null>(null)
|
||||||
|
let sendError = $state('')
|
||||||
|
|
||||||
|
const selectedToken = $derived(
|
||||||
|
tokens.find((t) => t.symbol === selectedSymbol) ?? tokens[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
const exceedsBalance = $derived(
|
||||||
|
amount !== '' &&
|
||||||
|
selectedToken.balance !== '0' &&
|
||||||
|
parseFloat(amount) > parseFloat(selectedToken.balance),
|
||||||
|
)
|
||||||
|
|
||||||
|
const canSend = $derived(
|
||||||
|
recipient.length === 42 &&
|
||||||
|
recipient.startsWith('0x') &&
|
||||||
|
amount !== '' &&
|
||||||
|
parseFloat(amount) > 0 &&
|
||||||
|
!exceedsBalance &&
|
||||||
|
!sending,
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleSend = async () => {
|
||||||
|
sending = true
|
||||||
|
sendError = ''
|
||||||
|
sentResult = null
|
||||||
|
try {
|
||||||
|
const txHash = await w.send(
|
||||||
|
recipient,
|
||||||
|
amount,
|
||||||
|
selectedToken.contractAddress || undefined,
|
||||||
|
selectedToken.decimals,
|
||||||
|
)
|
||||||
|
sentResult = { txHash }
|
||||||
|
recipient = ''
|
||||||
|
amount = ''
|
||||||
|
} catch (e) {
|
||||||
|
sendError = e instanceof Error ? e.message : 'Send failed'
|
||||||
|
} finally {
|
||||||
|
sending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-auto mt-16 max-w-md">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onclick={() => navigate(w.network === 'eth' ? '/multicoin' : `/multicoin/${w.network}`)}
|
||||||
|
class="mb-4">
|
||||||
|
← Back
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Send</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Balance: {selectedToken.balance} {selectedToken.symbol}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<form
|
||||||
|
onsubmit={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
handleSend()
|
||||||
|
}}
|
||||||
|
class="space-y-4">
|
||||||
|
<div class="space-y-1.5">
|
||||||
|
<label class="text-xs font-medium">Asset</label>
|
||||||
|
<Select type="single" bind:value={selectedSymbol}>
|
||||||
|
<SelectTrigger>
|
||||||
|
{selectedToken.symbol}
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{#each tokens as t}
|
||||||
|
<SelectItem value={t.symbol}>
|
||||||
|
{t.symbol} ({t.balance})
|
||||||
|
</SelectItem>
|
||||||
|
{/each}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-1.5">
|
||||||
|
<label class="text-xs font-medium">Recipient Address</label>
|
||||||
|
<Input
|
||||||
|
placeholder="0x..."
|
||||||
|
bind:value={recipient} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-1.5">
|
||||||
|
<label class="text-xs font-medium">Amount ({selectedToken.symbol})</label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
step="0.000000000000000001"
|
||||||
|
min="0"
|
||||||
|
placeholder="0.0"
|
||||||
|
bind:value={amount} />
|
||||||
|
{#if exceedsBalance}
|
||||||
|
<p class="text-xs text-red-500">
|
||||||
|
Amount exceeds balance
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button type="submit" disabled={!canSend} class="w-full">
|
||||||
|
{sending ? 'Sending...' : 'Send'}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{#if sendError}
|
||||||
|
<p class="mt-3 text-xs text-red-500">{sendError}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if sentResult}
|
||||||
|
<div
|
||||||
|
class="mt-4 space-y-2 rounded-md border border-green-500/30 bg-green-500/5 p-3">
|
||||||
|
<p class="text-xs font-medium text-green-600">
|
||||||
|
Transaction Sent
|
||||||
|
</p>
|
||||||
|
<p class="font-mono text-xs break-all">
|
||||||
|
<a
|
||||||
|
href="{w.explorerUrl}{sentResult.txHash}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="underline hover:text-green-500">
|
||||||
|
{sentResult.txHash}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
"apps/desktop": {
|
"apps/desktop": {
|
||||||
"name": "koins",
|
"name": "koins",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alchemy/wallet-apis": "^5.0.0-beta.28",
|
"@alchemy/common": "^5.0.0",
|
||||||
|
"@alchemy/wallet-apis": "^5.0.0",
|
||||||
"@koins/utils": "workspace:*",
|
"@koins/utils": "workspace:*",
|
||||||
"drizzle-orm": "^1.0.0-beta.22",
|
"drizzle-orm": "^1.0.0-beta.22",
|
||||||
"electrobun": "^1.18.1",
|
"electrobun": "^1.18.1",
|
||||||
@@ -72,11 +73,11 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="],
|
"@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="],
|
||||||
|
|
||||||
"@alchemy/common": ["@alchemy/common@5.0.0-beta.28", "", { "dependencies": { "zod": "^3.23.0" }, "peerDependencies": { "viem": "^2.45.0" } }, "sha512-VyqYyfYPuRTXpu8X+fFIL2JU9iS4ZnOl9wXmDS0s/3H3Y5wYJzz/dZ1Vo7u33B9L+aWPkSMGHVJun1AZdNEacA=="],
|
"@alchemy/common": ["@alchemy/common@5.0.2", "", { "dependencies": { "zod": "^3.23.0" }, "peerDependencies": { "viem": "^2.45.0" } }, "sha512-ORFjRhAJ07BUjhNqjgx2b4khWu0sNNEnnTXj3DT7UKFxZvK79cpyoE/6E0D17OWiz40y+uk6eRtkWog5bNWVpg=="],
|
||||||
|
|
||||||
"@alchemy/wallet-api-types": ["@alchemy/wallet-api-types@0.1.0-alpha.27", "", { "dependencies": { "@alchemy/common": "5.0.0-beta.4", "deep-equal": "^2.2.3", "ox": "^0.6.12", "typebox": "^1.0.81", "viem": "^2.45.0" }, "peerDependencies": { "typescript": "^5.8.2" } }, "sha512-d6DaAASwa3k7vpXEbG96hUiV+41CBGfTRNiXsjG5UgX4tox3Z0Dlf9QC+SBkyzc1/PiJx9fCuQxYNfrELqPxkw=="],
|
"@alchemy/wallet-api-types": ["@alchemy/wallet-api-types@0.2.0-alpha.3", "", { "dependencies": { "@alchemy/common": "5.0.0-beta.32", "deep-equal": "^2.2.3", "ox": "^0.6.12", "viem": "^2.45.0", "zod": "^4.4.1" }, "peerDependencies": { "typescript": "^5.8.2" } }, "sha512-VaNj8gzGfPveo8i6l3aX4YovQezu4oDuAqyAy2k1LqsLf18pn2+iw3cV/WiFTwMrdQXLtnDYzS9D6NdkgEokzw=="],
|
||||||
|
|
||||||
"@alchemy/wallet-apis": ["@alchemy/wallet-apis@5.0.0-beta.28", "", { "dependencies": { "@alchemy/common": "5.0.0-beta.28", "@alchemy/wallet-api-types": "0.1.0-alpha.27", "deep-equal": "^2.2.3", "ox": "^0.11.1", "typebox": "1.0.81" }, "peerDependencies": { "viem": "^2.45.0" } }, "sha512-ySr+ASorGI7bxPZ1fPH/CpszyXEVbUBLEfqWPzLmQiC5gvC186HppBFYPUrVUfVDU7izSNrkX7r64e99ZcppgA=="],
|
"@alchemy/wallet-apis": ["@alchemy/wallet-apis@5.0.2", "", { "dependencies": { "@alchemy/common": "5.0.2", "@alchemy/wallet-api-types": "0.2.0-alpha.3", "deep-equal": "^2.2.3", "ox": "^0.11.1", "zod": "^4.4.1" }, "peerDependencies": { "@solana/kit": ">=6.0.0", "@solana/web3.js": "^1.95.0", "viem": "^2.45.0" }, "optionalPeers": ["@solana/kit", "@solana/web3.js"] }, "sha512-HmwOAvpe248LOQaJ3Der2owT82l0OwxBfVbwiXd7WXlJ+k04L1ooFKo5AjiWXMaoJQzpIkh37n66SUmyVVd4PA=="],
|
||||||
|
|
||||||
"@ark/schema": ["@ark/schema@0.56.0", "", { "dependencies": { "@ark/util": "0.56.0" } }, "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA=="],
|
"@ark/schema": ["@ark/schema@0.56.0", "", { "dependencies": { "@ark/util": "0.56.0" } }, "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA=="],
|
||||||
|
|
||||||
@@ -1050,12 +1051,10 @@
|
|||||||
|
|
||||||
"@alchemy/common/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
"@alchemy/common/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||||
|
|
||||||
"@alchemy/wallet-api-types/@alchemy/common": ["@alchemy/common@5.0.0-beta.4", "", { "peerDependencies": { "viem": "^2.45.0" } }, "sha512-A9IGGG6QA+UEtf+mFiuNfuruS0wTlSsXx2jIWXeeJ18VYMEFmPFFpPP2tWfGLKpxyuA1QQqkHSQqs6dBpG1EZw=="],
|
"@alchemy/wallet-api-types/@alchemy/common": ["@alchemy/common@5.0.0-beta.32", "", { "dependencies": { "zod": "^3.23.0" }, "peerDependencies": { "viem": "^2.45.0" } }, "sha512-gVUrMhnhdD8UUipd70XUbmxm3PX3OhHK1TSi3ODBGOH3Jd9SoH0+mFagSn62pwi5XFPCOg3UGGXj9bmLKFlGhA=="],
|
||||||
|
|
||||||
"@alchemy/wallet-api-types/ox": ["ox@0.6.12", "", { "dependencies": { "@adraffy/ens-normalize": "^1.10.1", "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@scure/bip32": "^1.5.0", "@scure/bip39": "^1.4.0", "abitype": "^1.0.6", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-78hziRGLj0qTDa0UW4+ynv9tW2Cp1vmCfGokL8D7kiSDh6Y0LAfHL+HaDN4l2a9jcrOG3fexTDtLNtDNkEwLtg=="],
|
"@alchemy/wallet-api-types/ox": ["ox@0.6.12", "", { "dependencies": { "@adraffy/ens-normalize": "^1.10.1", "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@scure/bip32": "^1.5.0", "@scure/bip39": "^1.4.0", "abitype": "^1.0.6", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-78hziRGLj0qTDa0UW4+ynv9tW2Cp1vmCfGokL8D7kiSDh6Y0LAfHL+HaDN4l2a9jcrOG3fexTDtLNtDNkEwLtg=="],
|
||||||
|
|
||||||
"@alchemy/wallet-apis/typebox": ["typebox@1.0.81", "", {}, "sha512-bCslZUmZESHhBn4kHDghzH2oo3qu8m2W89xDLxQHv/aPvY4i81Nd1jvijlBp9wSpsVytDSfSoosbiBAjgsNb2Q=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
|
||||||
@@ -1118,6 +1117,8 @@
|
|||||||
|
|
||||||
"vite/rolldown": ["rolldown@1.0.0-rc.18", "", { "dependencies": { "@oxc-project/types": "=0.128.0", "@rolldown/pluginutils": "1.0.0-rc.18" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.18", "@rolldown/binding-darwin-arm64": "1.0.0-rc.18", "@rolldown/binding-darwin-x64": "1.0.0-rc.18", "@rolldown/binding-freebsd-x64": "1.0.0-rc.18", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.18", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.18", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.18", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.18", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.18", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.18", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg=="],
|
"vite/rolldown": ["rolldown@1.0.0-rc.18", "", { "dependencies": { "@oxc-project/types": "=0.128.0", "@rolldown/pluginutils": "1.0.0-rc.18" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.18", "@rolldown/binding-darwin-arm64": "1.0.0-rc.18", "@rolldown/binding-darwin-x64": "1.0.0-rc.18", "@rolldown/binding-freebsd-x64": "1.0.0-rc.18", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.18", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.18", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.18", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.18", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.18", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.18", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.18", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg=="],
|
||||||
|
|
||||||
|
"@alchemy/wallet-api-types/@alchemy/common/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||||
|
|
||||||
"@types/bun/bun-types/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
|
"@types/bun/bun-types/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
|
||||||
|
|
||||||
"axios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
"axios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||||
|
|||||||
Reference in New Issue
Block a user