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

Async transactions on Ethereum #3

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,17 @@ This template provides a minimal setup to get Solan Wallet Adapter integrated wi

- [ ] durable nonce with safe/squads account - https://x.com/SquadsProtocol/status/1837047617127358585
- [ ] schedule transactions on Ethereum

## Ethereum

### NOTES

- Metamask (Phantom) does not support `eth_signTransaction`
- https://github.com/MetaMask/metamask-extension/issues/3475
- https://x.com/CT_IOE/status/1534658825843683328
- https://x.com/1inch/status/1334992381242961930
- Ethereum transaction data structure - https://ethereum.stackexchange.com/questions/1990/what-is-the-ethereum-transaction-data-structure
- Multisig
- ECDSA threshold signature or multi-party signature: https://github.com/ZenGo-X/multi-party-ecdsa
- Smart Contract: https://github.com/gnosis/MultiSigWallet
-
1 change: 1 addition & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@solana/web3.js": "1.95.3",
"@tanstack/react-query": "5.59.15",
"@tanstack/react-router": "^1.69.0",
"@wagmi/core": "^2.14.1",
"bs58": "6.0.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
15 changes: 15 additions & 0 deletions apps/client/src/components/EthProvider/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { http, createConfig } from "wagmi";
import { sepolia } from "wagmi/chains";

declare module "wagmi" {
interface Register {
config: typeof wagmiConfig;
}
}

export const wagmiConfig = createConfig({
chains: [sepolia],
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com"),
},
});
Original file line number Diff line number Diff line change
@@ -1,27 +1,6 @@
import { Button } from "@/components/ui/button";
import {
http,
WagmiProvider,
createConfig,
useAccount,
useConnect,
useDisconnect,
} from "wagmi";
import { mainnet, sepolia } from "wagmi/chains";

declare module "wagmi" {
interface Register {
config: typeof config;
}
}

const config = createConfig({
chains: [mainnet, sepolia],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
},
});
import { WagmiProvider, useAccount, useConnect, useDisconnect } from "wagmi";
import { wagmiConfig } from "./config";

const WalletConnect = ({ children }: { children: React.ReactNode }) => {
const { address } = useAccount();
Expand Down Expand Up @@ -57,7 +36,7 @@ const WalletConnect = ({ children }: { children: React.ReactNode }) => {

export const EthProvider = ({ children }: { children: React.ReactNode }) => {
return (
<WagmiProvider config={config}>
<WagmiProvider config={wagmiConfig}>
<WalletConnect>
{/* */}
{children}
Expand Down
98 changes: 89 additions & 9 deletions apps/client/src/routes/eth.index.lazy.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,98 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { createLazyFileRoute } from "@tanstack/react-router";
import { useAccount, useBalance } from "wagmi";
import { prepareTransactionRequest } from "@wagmi/core";
import { useRef, useState } from "react";
import { toast } from "sonner";
import { parseEther } from "viem";
import { useAccount, useConfig, useSignMessage } from "wagmi";

function IndexPage() {
const account = useAccount();
const result = useBalance({
address: account.address,
});
function TransferForm() {
const config = useConfig();
const { connector: activeConnector, address } = useAccount();
const { signMessageAsync } = useSignMessage();

const formRef = useRef<HTMLFormElement>(null);
const [busy, setBusy] = useState(false);

const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setBusy(true);

try {
const recipient = event.currentTarget.recipient.value;
const amount = event.currentTarget.amount.value;

if (!recipient) throw new Error("Recipient not provided");
if (!amount) throw new Error("Amount not provided");

const tx = await prepareTransactionRequest(config, {
to: recipient as `0x${string}`,
value: parseEther(amount),
});
console.log("Tx: ", tx);

const provider = await activeConnector?.getProvider();
const test = await provider?.request!({
method: "eth_signTransaction",
params: [
{
to: "0xA0Cf798816D4b9b9866b5330EEa46a18382f251e",
from: "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
value: "0x0",
},
],
});
console.log("Test: ", test);
const signedTx = await signMessageAsync?.({
account: address,
message: { raw: tx },
});
console.log("Signed Tx: ", signedTx);
if (!signedTx) throw new Error("Transaction not signed");

// const hash = await walletClient.account.client(config, {
// serializedTransaction: signedTx as `0x${string}`,
// });
// console.log("TxHash: ", hash);

formRef.current?.reset();
toast.info("Transaction sent!");
} catch (error) {
console.log(error);
toast.error("Transaction failed!");
} finally {
setBusy(false);
}
};

return (
<form
onSubmit={onSubmit}
ref={formRef}
className="flex flex-col gap-2 text-left"
>
<label htmlFor="recipient">Recipient:</label>
<Input
id="recipient"
type="text"
required
defaultValue={"0x3A169379eF86164aeA75dd05cB7daF32C966F24c"}
/>
<label htmlFor="amount">Amount:</label>
<Input id="amount" type="text" required defaultValue={"0.0001"} />
<Button disabled={busy} type="submit" className="mt-4">
Send Transaction
</Button>
</form>
);
}

function IndexPage() {
return (
<div className="flex flex-wrap gap-4">
<div className="p-8 bg-zinc-900 shadow-md w-full md:w-1/3">
<p className="text-2xl">
Balance: {result.data?.formatted} {result.data?.symbol}
</p>
<TransferForm />
</div>
</div>
);
Expand Down
33 changes: 29 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.