Skip to content

Commit

Permalink
feat: sapi sign with vault (+fix fee estimate)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xKheops committed Aug 27, 2024
1 parent dde349f commit bed2b3d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 68 deletions.
43 changes: 27 additions & 16 deletions apps/extension/src/ui/domains/Sign/Qr/QrSubstrate.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { isJsonPayload } from "@extension/core"
import { SignerPayloadJSON, SignerPayloadRaw } from "@extension/core"
import { AccountJsonQr } from "@extension/core"
import { POLKADOT_VAULT_DOCS_URL } from "@extension/shared"
import { HexString } from "@polkadot/util/types"
import { Chain } from "@talismn/chaindata-provider"
import { ChevronLeftIcon, InfoIcon, LoaderIcon, PolkadotVaultIcon } from "@talismn/icons"
import { classNames } from "@talismn/util"
import { ChainLogo } from "@ui/domains/Asset/ChainLogo"
import { ScanQr } from "@ui/domains/Sign/Qr/ScanQr"
import { useChainByGenesisHash } from "@ui/hooks/useChainByGenesisHash"
import { ReactElement, useState } from "react"
import { Trans, useTranslation } from "react-i18next"
import { Button, Drawer, Tooltip, TooltipContent, TooltipTrigger } from "talisman-ui"

import { AccountJsonQr, isJsonPayload, SignerPayloadJSON, SignerPayloadRaw } from "@extension/core"
import { POLKADOT_VAULT_DOCS_URL } from "@extension/shared"
import { ChainLogo } from "@ui/domains/Asset/ChainLogo"
import { ScanQr } from "@ui/domains/Sign/Qr/ScanQr"
import { useChainByGenesisHash } from "@ui/hooks/useChainByGenesisHash"

import { ExtrinsicQrCode } from "./ExtrinsicQrCode"
import { MetadataQrCode } from "./MetadataQrCode"
import { NetworkSpecsQrCode } from "./NetworkSpecsQrCode"
Expand Down Expand Up @@ -48,7 +47,7 @@ interface Props {
className?: string
genesisHash?: HexString
onSignature?: (result: { signature: `0x${string}` }) => void
onReject: () => void
onReject?: () => void
payload: SignerPayloadJSON | SignerPayloadRaw
containerId: string
skipInit?: boolean
Expand Down Expand Up @@ -84,9 +83,11 @@ export const QrSubstrate = ({
return (
<div className={classNames("flex w-full flex-col items-center", className)}>
<div className="flex w-full items-center gap-12">
<Button className="w-full" onClick={onReject}>
{t("Cancel")}
</Button>
{!!onReject && (
<Button className="w-full" onClick={onReject}>
{t("Cancel")}
</Button>
)}
<Button className="w-full" primary onClick={() => setScanState({ page: "SEND" })}>
{t("Sign with QR")}
</Button>
Expand All @@ -111,8 +112,8 @@ export const QrSubstrate = ({
setScanState((scanState) => {
// if back is clicked and we're on the first page, reject the signing attempt
// (which is INIT when skipInit is false, or SEND when it's true)
if (scanState.page === "INIT") onReject()
if (skipInit && scanState.page === "SEND") onReject()
if (scanState.page === "INIT") onReject?.()
if (skipInit && scanState.page === "SEND") onReject?.()

// if we're on the SEND page, go back to the INIT page
if (!skipInit && scanState.page === "SEND") return { page: "INIT" }
Expand Down Expand Up @@ -207,7 +208,12 @@ export const QrSubstrate = ({
>
{scanState.page === "SEND" && (
<>
<Button className="w-full" onClick={onReject}>
<Button
className="w-full"
onClick={() => {
onReject ? onReject() : setScanState({ page: "INIT" })
}}
>
{t("Cancel")}
</Button>
<Button className="w-full" primary onClick={() => setScanState({ page: "RECEIVE" })}>
Expand All @@ -221,7 +227,12 @@ export const QrSubstrate = ({
</Button>
)}
{scanState.page === "RECEIVE" && onSignature && (
<Button className="w-full" onClick={onReject}>
<Button
className="w-full"
onClick={() => {
onReject ? onReject() : setScanState({ page: "INIT" })
}}
>
{t("Cancel")}
</Button>
)}
Expand All @@ -245,7 +256,7 @@ const SendPage = ({
account: AccountJsonQr
genesisHash: HexString | undefined
payload: SignerPayloadJSON | SignerPayloadRaw
reject: () => void
reject?: () => void
setScanState: React.Dispatch<React.SetStateAction<ScanState>>
scanState: SendScanState
qrCodeSource: QrCodeSource | undefined
Expand Down
46 changes: 0 additions & 46 deletions apps/extension/src/ui/domains/Staking/useInlineStakingWizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,52 +175,6 @@ export const useInlineStakingWizard = () => {
[setState]
)

// const submit = useCallback(async () => {
// const { address, tokenId, poolId, plancks } = state
// if (!sapi || !address || !tokenId || !poolId || !plancks) return

// setState((prev) => ({ ...prev, isSubmitting: true, submitErrorMessage: null }))

// try {
// const { hash } = await sapi.signAndSubmit(
// "NominationPools",
// "join",
// {
// amount: plancks,
// pool_id: poolId,
// },
// { address: address }
// )

// setState((prev) => ({ ...prev, isSubmitting: false, step: "follow-up", hash }))
// } catch (err) {
// log.error("Failed to submit", { state, err })
// setState((prev) => ({
// ...prev,
// isSubmitting: false,
// submitErrorMessage: "Something went wrong",
// }))
// }
// }, [sapi, setState, state])

// useEffect(() => {
// console.log("[sapi] useInlineStakingWizard", {
// payload: payloadAndMetadata?.payload,
// feeEstimate,
// isLoadingFeeEstimate,
// isLoadingPayload,
// errorPayload,
// errorFeeEstimate,
// })
// }, [
// errorFeeEstimate,
// errorPayload,
// feeEstimate,
// isLoadingFeeEstimate,
// isLoadingPayload,
// payloadAndMetadata?.payload,
// ])

return {
account,
token,
Expand Down
47 changes: 43 additions & 4 deletions apps/extension/src/ui/domains/Transactions/SapiSendButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AlertCircleIcon } from "@talismn/icons"
import { toHex } from "@talismn/scale"
import { AccountType, SignerPayloadJSON } from "extension-core"
import { AccountJsonQr, AccountType, SignerPayloadJSON } from "extension-core"
import { log } from "extension-shared"
import { FC, Suspense, useCallback, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
Expand All @@ -10,6 +10,7 @@ import { Hex } from "viem"
import { useScaleApi } from "@ui/hooks/sapi/useScaleApi"
import { useAccountByAddress } from "@ui/hooks/useAccountByAddress"

import { QrSubstrate } from "../Sign/Qr/QrSubstrate"
import { SignHardwareSubstrate } from "../Sign/SignHardwareSubstrate"

type SapiSendButtonProps = {
Expand Down Expand Up @@ -72,9 +73,47 @@ const HardwareAccountSendButton: FC<SapiSendButtonProps> = ({
)
}

const QrAccountSendButton: FC<SapiSendButtonProps> = () => {
// TODO
return null
const QrAccountSendButton: FC<SapiSendButtonProps> = ({ containerId, payload, onSubmitted }) => {
const account = useAccountByAddress(payload?.address)
const [error, setError] = useState<string>()
const { data: sapi } = useScaleApi(payload?.genesisHash)

const handleSigned = useCallback(
async ({ signature }: { signature: Hex }) => {
if (!payload || !signature || !sapi) return

setError(undefined)
try {
const { hash } = await sapi.submit(payload, signature)
onSubmitted(hash)
} catch (err) {
log.error("Failed to submit", { payload, err })
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setError((err as any)?.message ?? "Failed to submit")
}
},
[onSubmitted, payload, sapi]
)

if (!account) return null

return (
<div className="flex w-full flex-col gap-6">
{error && (
<div className="text-alert-warn bg-grey-900 flex w-full items-center gap-5 rounded-sm px-5 py-6 text-xs">
<AlertCircleIcon className="text-lg" />
<div>{error}</div>
</div>
)}
<QrSubstrate
containerId={containerId ?? "main"}
genesisHash={payload.genesisHash}
payload={payload}
account={account as AccountJsonQr}
onSignature={handleSigned}
/>
</div>
)
}

const LocalAccountSendButton: FC<SapiSendButtonProps> = ({
Expand Down
8 changes: 6 additions & 2 deletions apps/extension/src/ui/util/scaleApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,14 +295,18 @@ const getFeeEstimate = async (
const binary = Binary.fromBytes(bytes)

try {
const { partialFee } = await getRuntimeCallValue<{ partialFee: bigint }>(
const result = await getRuntimeCallValue<{ partial_fee: bigint }>(
chainId,
builder,
"TransactionPaymentApi",
"query_info",
[binary, bytes.length]
)
return partialFee
if (!result?.partial_fee) {
// console.warn("partialFee is not found", { result })
throw new Error("partialFee is not found")
}
return result.partial_fee
} catch (err) {
log.error("Failed to get fee estimate using getRuntimeCallValue", { error: err })
}
Expand Down

0 comments on commit bed2b3d

Please sign in to comment.