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

Wallet adapter v2 #197

Merged
merged 4 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 5 additions & 2 deletions apps/nextjs-example/components/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ import { AutoConnectProvider, useAutoConnect } from "./AutoConnectProvider";
import { FC, ReactNode } from "react";
import face from "../lib/faceInitialization";
import { AlertProvider, useAlert } from "./AlertProvider";
import {IdentityConnectWallet} from "@identity-connect/wallet-adapter-plugin";
import { IdentityConnectWallet } from "@identity-connect/wallet-adapter-plugin";

const WalletContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
const { autoConnect } = useAutoConnect();
const { setErrorAlertMessage } = useAlert();

const wallets = [
new IdentityConnectWallet("57fa42a9-29c6-4f1e-939c-4eefa36d9ff5", {networkName: NetworkName.Testnet}),
// TODO IdentityConnectWallet and BloctoWallet to use Network enum from @aptos-labs/ts-sdk
new IdentityConnectWallet("57fa42a9-29c6-4f1e-939c-4eefa36d9ff5", {
networkName: NetworkName.Testnet,
}),
// Blocto supports Testnet/Mainnet for now.
new BloctoWallet({
network: NetworkName.Testnet,
Expand Down
19 changes: 19 additions & 0 deletions apps/nextjs-example/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default function Button(props: {
color: string | undefined;
onClick: () => void;
disabled: boolean;
message: string;
}) {
const { color, onClick, disabled, message } = props;
return (
<button
className={`bg-${color}-500 text-white font-bold py-2 px-4 rounded mr-4 ${
disabled ? "opacity-50 cursor-not-allowed" : `hover:bg-${color}-700`
}`}
onClick={onClick}
disabled={disabled}
>
{message}
</button>
);
}
15 changes: 15 additions & 0 deletions apps/nextjs-example/components/Col.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function Col(props: {
title?: boolean;
border?: boolean;
children?: React.ReactNode;
}) {
return (
<td
className={`px-8 py-4 ${props.border ? "border-t" : ""} w-${
props.title ? "1/4" : "3/4"
}`}
>
{props.children}
</td>
);
}
3 changes: 3 additions & 0 deletions apps/nextjs-example/components/Row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Row(props: { children?: React.ReactNode }) {
return <tr>{props.children}</tr>;
}
179 changes: 179 additions & 0 deletions apps/nextjs-example/components/transactionFlow/MultiAgent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import {
Account,
AccountAuthenticator,
AnyRawTransaction,
} from "@aptos-labs/ts-sdk";
import { useWallet } from "@aptos-labs/wallet-adapter-react";

import { useState, useEffect } from "react";
import { aptosClient } from "../../utils";
import { useAlert } from "../AlertProvider";
import Button from "../Button";
import Col from "../Col";
import Row from "../Row";
export const APTOS_COIN = "0x1::aptos_coin::AptosCoin";
type MultiAgentTransactionProps = {
isSendableNetwork: (connected: boolean, network?: string) => boolean;
};

export default function MultiAgentTransaction({
isSendableNetwork,
}: MultiAgentTransactionProps) {
const { connected, account, network, signTransaction, submitTransaction } =
useWallet();

const [secondarySignerAccount, setSecondarySignerAccount] =
useState<Account>();
const [transactionToSubmit, setTransactionToSubmit] =
useState<AnyRawTransaction | null>(null);
const { setSuccessAlertHash } = useAlert();

const [senderAuthenticator, setSenderAuthenticator] =
useState<AccountAuthenticator>();
const [secondarySignerAuthenticator, setSecondarySignerAuthenticator] =
useState<AccountAuthenticator>();

let sendable = isSendableNetwork(connected, network?.name);

useEffect(() => {
if (!sendable) return;
if (!account) return;
if (!network) return;

const secondarySigner = Account.generate();

// Generate a raw transaction using the SDK
const generate = async (): Promise<AnyRawTransaction> => {
const transactionToSign = await aptosClient(
network?.name.toLowerCase()
).generateTransaction({
sender: account.address,
secondarySignerAddresses: [secondarySigner.accountAddress],
data: {
function: "0x1::coin::transfer",
typeArguments: [APTOS_COIN],
functionArguments: [account.address, 1], // 1 is in Octas
},
});
return transactionToSign;
};

// Fund secondary signer account to create it on chain
const fundSecondarySigner = async () => {
await aptosClient(network.name.toLowerCase()).fundAccount({
accountAddress: secondarySigner.accountAddress.toString(),
amount: 100_000_000,
});
};

// Fund current connected account to create it on chain
const fundCurrentAccount = async () => {
await aptosClient(network.name.toLowerCase()).fundAccount({
accountAddress: account.address,
amount: 100_000_000,
});
};

// We fund the secondary signer account to create it on chain
// We fund the current connected account to create it on chain
// Then we generate the transaction with the current connected account
// as the sender and the secondary signer account
fundSecondarySigner().then(() => {
setSecondarySignerAccount(secondarySigner);
fundCurrentAccount().then(() => {
generate().then((transactionToSign) =>
setTransactionToSubmit(transactionToSign)
);
});
});
}, [network, account, sendable]);

const onSenderSignTransaction = async () => {
if (!transactionToSubmit) {
throw new Error("No Transaction to sign");
}
try {
const authenticator = await signTransaction(transactionToSubmit);
setSenderAuthenticator(authenticator);
} catch (error) {
console.error(error);
}
};

const onSecondarySignerSignTransaction = async () => {
if (!transactionToSubmit) {
throw new Error("No Transaction to sign");
}
try {
const authenticator = await signTransaction(transactionToSubmit);
setSecondarySignerAuthenticator(authenticator);
} catch (error) {
console.error(error);
}
};

const onSubmitTransaction = async () => {
if (!transactionToSubmit) {
throw new Error("No Transaction to sign");
}
if (!senderAuthenticator) {
throw new Error("No senderAuthenticator");
}
if (!secondarySignerAuthenticator) {
throw new Error("No secondarySignerAuthenticator");
}
try {
const response = await submitTransaction({
transaction: transactionToSubmit,
senderAuthenticator: senderAuthenticator,
additionalSignersAuthenticators: [secondarySignerAuthenticator],
});
setSuccessAlertHash(response.hash, network?.name);
} catch (error) {
console.error(error);
}
};

return (
<>
<Row>
<Col title={true} border={true}>
<h3>Multi Agent Transaction Flow</h3>
</Col>
<Col border={true}>
<Button
color={"blue"}
onClick={onSenderSignTransaction}
disabled={!sendable || !transactionToSubmit}
message={"Sign as sender"}
/>

<Button
color={"blue"}
onClick={onSecondarySignerSignTransaction}
disabled={!sendable || !senderAuthenticator}
message={"Sign as secondary signer"}
/>
<Button
color={"blue"}
onClick={onSubmitTransaction}
disabled={!sendable || !secondarySignerAuthenticator}
message={"Submit transaction"}
/>
</Col>
</Row>
{secondarySignerAccount && secondarySignerAuthenticator && (
<Row>
<Col title={true}>
<h3>Secondary Signer details</h3>
</Col>
<Col>
<p>Private Key: {secondarySignerAccount.privateKey.toString()}</p>
<p>Public Key: {secondarySignerAccount.publicKey.toString()}</p>
<p>Address: {secondarySignerAccount.accountAddress.toString()}</p>
</Col>
</Row>
)}
</>
0xmaayan marked this conversation as resolved.
Show resolved Hide resolved
);
}
Loading