-
Notifications
You must be signed in to change notification settings - Fork 1
feat: WalletConnect, prototype #1933
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
|
||
import { Button, Card, CardBody, Link, Text, Tooltip } from "@chakra-ui/react" | ||
import { truncate } from "@umami/tezos" | ||
|
||
import { CrossedCircleIcon } from "../../../assets/icons" | ||
|
||
/** | ||
* Types | ||
*/ | ||
interface IProps { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't use interfaces, |
||
name?: string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why all the props are optional? |
||
url?: string | ||
topic?: string | ||
onDelete: () => Promise<void> | ||
} | ||
|
||
/** | ||
* Component | ||
*/ | ||
export default function PairingCard({ name, url, topic, onDelete }: IProps) { | ||
return ( | ||
<Card className="relative mb-6 min-h-[70px] border border-light"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't use classNames in the app. please check out chakra docs |
||
<CardBody className="flex flex-row items-center justify-between overflow-hidden p-4"> | ||
<div className="flex-1"> | ||
<Text className="ml-9" data-testid={"pairing-text-" + topic}> | ||
{name} | ||
</Text> | ||
<Link className="ml-9" data-testid={"pairing-text-" + topic} href={url}> | ||
{truncate(url?.split("https://")[1] ?? "Unknown", 23)} | ||
</Link> | ||
</div> | ||
<Tooltip content="Delete" placement="left"> | ||
<Button className="min-w-auto text-error border-0 p-1 hover:bg-red-100 transition-all" | ||
data-testid={"pairing-delete-" + topic} | ||
onClick={onDelete} | ||
> | ||
<CrossedCircleIcon alt="delete icon" /> | ||
</Button> | ||
</Tooltip> | ||
</CardBody> | ||
</Card> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
|
||
import { Text } from "@chakra-ui/react" | ||
import { SettingsStore, web3wallet } from "@umami/state" | ||
import { type PairingTypes } from "@walletconnect/types" | ||
import { getSdkError } from "@walletconnect/utils" | ||
import { Fragment, useEffect } from "react" | ||
import { useSnapshot } from "valtio" | ||
|
||
import PairingCard from "./PairingCard" | ||
|
||
export default function PairingsPage() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please don't use default exports and function declarations like this. instead please use fatarrow functions like
|
||
const { pairings } = useSnapshot(SettingsStore.state) | ||
// const [walletPairings ] = useState(web3wallet.core.pairing.getPairings()) | ||
|
||
async function onDelete(topic: string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here as above |
||
await web3wallet.disconnectSession({ topic, reason: getSdkError("USER_DISCONNECTED") }) | ||
const newPairings = pairings.filter(pairing => pairing.topic !== topic) | ||
SettingsStore.setPairings(newPairings as PairingTypes.Struct[]) | ||
} | ||
|
||
useEffect(() => { | ||
SettingsStore.setPairings(web3wallet.core.pairing.getPairings()) | ||
}, []) | ||
|
||
// console.log("pairings", walletPairings) | ||
return ( | ||
<Fragment> | ||
{pairings.length ? ( | ||
pairings.map(pairing => { | ||
const { peerMetadata } = pairing | ||
|
||
return ( | ||
<PairingCard | ||
key={pairing.topic} | ||
data-testid={"pairing-" + pairing.topic} | ||
logo={peerMetadata?.icons[0]} | ||
name={peerMetadata?.name} | ||
onDelete={() => onDelete(pairing.topic)} | ||
topic={pairing.topic} | ||
url={peerMetadata?.url} | ||
/> | ||
) | ||
}) | ||
) : ( | ||
<Text css={{ opacity: "0.5", textAlign: "center", marginTop: "$20" }}>No pairings</Text> | ||
)} | ||
</Fragment> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { formatJsonRpcError, formatJsonRpcResult } from "@json-rpc-tools/utils"; | ||
import { type TezosToolkit } from "@taquito/taquito"; | ||
import { | ||
type Account, | ||
type ImplicitAccount, | ||
type SecretKeyAccount, | ||
estimate, | ||
executeOperations, | ||
toAccountOperations, | ||
} from "@umami/core"; | ||
import { | ||
TEZOS_SIGNING_METHODS, | ||
} from "@umami/state"; | ||
import { type Network } from "@umami/tezos"; | ||
import { type SignClientTypes } from "@walletconnect/types"; | ||
import { getSdkError } from "@walletconnect/utils"; | ||
|
||
export async function approveTezosRequest( | ||
requestEvent: SignClientTypes.EventArguments["session_request"], | ||
tezosToolkit: TezosToolkit, | ||
signer: Account, | ||
network: Network | ||
) { | ||
const { params, id } = requestEvent; | ||
const { request } = params; | ||
|
||
console.log("approveTezosRequest", request); | ||
|
||
switch (request.method) { | ||
case TEZOS_SIGNING_METHODS.TEZOS_GET_ACCOUNTS: { | ||
console.log("TEZOS_GET_ACCOUNTS"); | ||
return formatJsonRpcResult(id, [{ | ||
algo: (signer as SecretKeyAccount).curve, | ||
address: signer.address.pkh, | ||
pubkey: (signer as SecretKeyAccount).pk, | ||
}]); | ||
} | ||
|
||
case TEZOS_SIGNING_METHODS.TEZOS_SEND: { | ||
console.log("TEZOS_SEND"); | ||
try { | ||
const operation = toAccountOperations(request.params.operations, signer as ImplicitAccount); | ||
const estimatedOperations = await estimate(operation, network); | ||
console.log("TEZOS_SEND: executing operation", estimatedOperations); | ||
const { opHash } = await executeOperations(estimatedOperations, tezosToolkit); | ||
console.log("TEZOS_SEND: executed operation", request.params.method, operation, opHash); | ||
return formatJsonRpcResult(id, { hash: opHash }); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
console.error("Tezos_send operation failed with error: ", error.message); | ||
return formatJsonRpcError(id, error.message); | ||
} else { | ||
console.error("Tezos_send operation failed with unknown error: ", error); | ||
return formatJsonRpcError(id, "TEZOS_SEND failed with unknown error."); | ||
} | ||
} | ||
} | ||
|
||
case TEZOS_SIGNING_METHODS.TEZOS_SIGN: { | ||
const result = await tezosToolkit.signer.sign(request.params.payload); | ||
console.log("TEZOS_SIGN", result.prefixSig); | ||
return formatJsonRpcResult(id, { signature: result.prefixSig }); | ||
} | ||
|
||
default: | ||
throw new Error(getSdkError("INVALID_METHOD").message); | ||
} | ||
} | ||
|
||
export function rejectTezosRequest(request: SignClientTypes.EventArguments["session_request"]) { | ||
const { id } = request; | ||
|
||
return formatJsonRpcError(id, getSdkError("USER_REJECTED_METHODS").message); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
interface Props { | ||
address?: string; | ||
} | ||
|
||
export default function ChainAddressMini({ address }: Props) { | ||
if (!address || address === "N/A") {return <></>;} | ||
return ( | ||
<> | ||
<div> | ||
<span style={{ marginLeft: "5px" }}> | ||
{address.substring(0, 6)}...{address.substring(address.length - 6)} | ||
</span> | ||
</div> | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Card, CardBody } from "@chakra-ui/react"; | ||
import { type ReactNode } from "react"; | ||
|
||
interface Props { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this interface can be replaced with |
||
children: ReactNode | ReactNode[]; | ||
rgb: string; | ||
flexDirection: "row" | "col"; | ||
alignItems: "center" | "flex-start"; | ||
flexWrap?: "wrap" | "nowrap"; | ||
} | ||
|
||
export default function ChainCard({ rgb, children, flexDirection, alignItems, flexWrap }: Props) { | ||
return ( | ||
<Card | ||
className="mb-6 min-h-[70px] shadow-md rounded-lg border" | ||
style={{ | ||
borderColor: `rgba(${rgb}, 0.4)`, | ||
boxShadow: `0 0 10px 0 rgba(${rgb}, 0.15)`, | ||
backgroundColor: `rgba(${rgb}, 0.25)`, | ||
}} | ||
> | ||
<CardBody | ||
className={`flex justify-between overflow-hidden | ||
${flexWrap === "wrap" ? "flex-wrap" : "flex-nowrap"} | ||
${flexDirection === "row" ? "flex-row" : "flex-col"} | ||
${alignItems === "center" ? "items-center" : "items-start"} | ||
`} | ||
> | ||
{children} | ||
</CardBody> | ||
</Card> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { getChainData } from "@umami/state"; | ||
import { useMemo } from "react"; | ||
|
||
import { TezosLogoIcon } from "../../assets/icons"; | ||
|
||
interface Props { | ||
chainId?: string; // namespace + ":" + reference | ||
} | ||
|
||
export default function ChainDataMini({ chainId }: Props) { | ||
const chainData = useMemo(() => getChainData(chainId), [chainId]); | ||
|
||
if (!chainData) {return <></>;} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return null |
||
return ( | ||
<> | ||
<div> | ||
<TezosLogoIcon size="sm" /> | ||
<span style={{ marginLeft: "5px" }}>{chainData.name}</span> | ||
</div> | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Card } from "@chakra-ui/react"; | ||
|
||
import ChainAddressMini from "./ChainAddressMini"; | ||
|
||
type SmartAccount = { | ||
address: string; | ||
type: string; | ||
}; | ||
|
||
interface Props { | ||
account: SmartAccount; | ||
} | ||
|
||
export default function ChainSmartAddressMini({ account }: Props) { | ||
return ( | ||
<div> | ||
<div> | ||
<Card>({account.type})</Card> | ||
<ChainAddressMini address={account.address} /> | ||
</div> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Card, Divider } from "@chakra-ui/react"; | ||
import { ModalStore } from "@umami/state"; | ||
import { useSnapshot } from "valtio"; | ||
|
||
import RequestModalContainer from "./RequestModalContainer"; | ||
|
||
|
||
export default function LoadingModal() { | ||
const state = useSnapshot(ModalStore.state); | ||
const message = state.data?.loadingMessage; | ||
|
||
return ( | ||
<RequestModalContainer title=""> | ||
<div style={{ textAlign: "center", padding: "20px" }}> | ||
<div> | ||
<div> | ||
<h3>Loading your request...</h3> | ||
</div> | ||
</div> | ||
{message ? ( | ||
<div style={{ textAlign: "center" }}> | ||
<Divider /> | ||
<Card>{message}</Card> | ||
</div> | ||
) : null} | ||
</div> | ||
</RequestModalContainer> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sure we don't need it. most likely you need to use redux that's already included