diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index b5f2bd78..5bc45c70 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -32,7 +32,8 @@ module.exports = {
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-misused-promises": "off",
- "react-hooks-addons/no-unused-deps": ["warn", { effectComment: "used" }]
+ "react-hooks-addons/no-unused-deps": ["warn", { effectComment: "used" }],
+ "@typescript-eslint/no-unused-vars": ["warn", { vars: "local", args: "after-used", ignoreRestSiblings: true }]
},
globals: {
JSX: true,
diff --git a/packages/good-design/package.json b/packages/good-design/package.json
index 05fb5fd7..bb37ecc2 100644
--- a/packages/good-design/package.json
+++ b/packages/good-design/package.json
@@ -27,7 +27,6 @@
"@babel/preset-react": "^7.16.0",
"@babel/preset-typescript": "^7.16.0",
"@babel/runtime": "^7.18.9",
- "@gooddollar/web3sdk-v2": "latest",
"@storybook/addon-actions": "^6.5.12",
"@storybook/addon-essentials": "^6.5.12",
"@storybook/addon-links": "^6.5.12",
@@ -73,6 +72,7 @@
"@babel/core": "^7.18.10",
"@babel/runtime": "^7.18.9",
"@gooddollar/goodprotocol": "^2.0.3",
+ "@gooddollar/web3sdk-v2": "workspace:^",
"@lingui/macro": "^3.14.0",
"@lingui/react": "^3.14.0",
"@magiklabs/react-sdk": "^1.0.8",
diff --git a/packages/good-design/src/core/layout/ActionHeader.tsx b/packages/good-design/src/core/layout/ActionHeader.tsx
index 35911f70..8cecf9a9 100644
--- a/packages/good-design/src/core/layout/ActionHeader.tsx
+++ b/packages/good-design/src/core/layout/ActionHeader.tsx
@@ -4,7 +4,7 @@ import { Title } from "./";
interface ActionHeaderProps {
textColor: any;
- /** text to complete the 'To complete this action, ...' sentence */
+ /** text to complete the 'To complete this action, ...' copy */
actionText: string;
}
diff --git a/packages/good-design/src/core/web3/index.ts b/packages/good-design/src/core/web3/index.ts
index a677f99e..6958e930 100644
--- a/packages/good-design/src/core/web3/index.ts
+++ b/packages/good-design/src/core/web3/index.ts
@@ -1,4 +1,3 @@
export * from "./WalletAndChainGuard";
-export * from "./SwitchChainModal";
+export * from "./modals";
export * from "./ExplorerLink";
-export * from "./KimaModal";
diff --git a/packages/good-design/src/core/web3/KimaModal.tsx b/packages/good-design/src/core/web3/modals/KimaModal.tsx
similarity index 90%
rename from packages/good-design/src/core/web3/KimaModal.tsx
rename to packages/good-design/src/core/web3/modals/KimaModal.tsx
index b844c2c6..aa87c171 100644
--- a/packages/good-design/src/core/web3/KimaModal.tsx
+++ b/packages/good-design/src/core/web3/modals/KimaModal.tsx
@@ -1,8 +1,8 @@
import React, { useEffect } from "react";
-import { useModal } from "../../hooks/useModal";
+import { useModal } from "../../../hooks/useModal";
import { Box, Text } from "native-base";
-import { LearnButton } from "../buttons";
-import { Title } from "../layout";
+import { LearnButton } from "../../buttons";
+import { Title } from "../../layout";
type BridgeNetworks = {
origin: string;
diff --git a/packages/good-design/src/core/web3/modals/SignTxModal.tsx b/packages/good-design/src/core/web3/modals/SignTxModal.tsx
new file mode 100644
index 00000000..71698ba8
--- /dev/null
+++ b/packages/good-design/src/core/web3/modals/SignTxModal.tsx
@@ -0,0 +1,96 @@
+import React, { useEffect } from "react";
+import { Box, Heading, useColorModeValue, useToast, Text } from "native-base";
+import { useNotifications } from "@usedapp/core";
+import type { TransactionReceipt, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider";
+import { useModal } from "../../../hooks/useModal";
+import { ActionHeader } from "../../layout";
+import { LearnButton } from "../../buttons";
+
+// usedapp type definitions without walletConnected
+type NotificationPayload = { submittedAt: number } & (
+ | { type: "transactionPendingSignature"; transactionName?: string; transactionRequest?: TransactionRequest }
+ | { type: "transactionStarted"; transaction: TransactionResponse; transactionName?: string }
+ | {
+ type: "transactionSucceed";
+ transaction: TransactionResponse;
+ receipt: TransactionReceipt;
+ transactionName?: string;
+ originalTransaction?: TransactionResponse;
+ }
+ | {
+ type: "transactionFailed";
+ transaction: TransactionResponse;
+ receipt: TransactionReceipt;
+ transactionName?: string;
+ originalTransaction?: TransactionResponse;
+ }
+);
+
+export type Notification = { id: string } & NotificationPayload;
+
+//todo: add proper (customizable) styles
+const SimpleTxToast = ({ title, desc }: { title: string; desc: string }) => (
+
+ {title}
+ txName: {desc}
+
+);
+
+export type SignTxProps = {
+ children?: any;
+} & ({ withToast: boolean; onSubmit?: never } | { withToast?: never; onSubmit: () => void });
+
+/**
+ * A modal to wrap your component or page with and show a modal re-active to a
+ * pending signature for a usedapp useContractFunction call
+ * it assumes you have already wrapped your app with the Web3Provider out of the @gooddollar/sdk-v2 package
+ * @param children
+ * @param withToast - if true, will show a simple toast
+ * @param onSubmitted - if withToast false, provide a callback to handle what happens after tx is submitted
+ * @returns JSX.Element
+ */
+export const SignTxModal = ({ children, withToast, onSubmit }: SignTxProps) => {
+ const doWithToast = withToast;
+ const { notifications } = useNotifications();
+ const toast = useToast();
+ const textColor = useColorModeValue("goodGrey.500", "white");
+
+ const { Modal, showModal, hideModal } = useModal();
+
+ useEffect(() => {
+ const localNotif = notifications as Notification[];
+ if (localNotif[0]?.type.includes("transaction")) {
+ const { type, transactionName = "" } = localNotif[0];
+ switch (type) {
+ case "transactionPendingSignature":
+ showModal();
+ break;
+ case "transactionStarted":
+ hideModal();
+ if (doWithToast) {
+ toast.show({
+ render: () => ,
+ placement: "top-right"
+ });
+ } else {
+ onSubmit?.();
+ }
+ break;
+ default:
+ hideModal();
+ break;
+ }
+ }
+ }, [notifications]);
+
+ return (
+
+ }
+ body={}
+ closeText="x"
+ />
+ {children}
+
+ );
+};
diff --git a/packages/good-design/src/core/web3/SwitchChainModal.tsx b/packages/good-design/src/core/web3/modals/SwitchChainModal.tsx
similarity index 84%
rename from packages/good-design/src/core/web3/SwitchChainModal.tsx
rename to packages/good-design/src/core/web3/modals/SwitchChainModal.tsx
index 3c7914a8..8041c6ea 100644
--- a/packages/good-design/src/core/web3/SwitchChainModal.tsx
+++ b/packages/good-design/src/core/web3/modals/SwitchChainModal.tsx
@@ -3,9 +3,9 @@ import React, { useEffect, useState } from "react";
import { useConfig } from "@usedapp/core";
import { useSwitchNetwork } from "@gooddollar/web3sdk-v2";
import { find } from "lodash";
-import { useModal } from "../../hooks/useModal";
-import { ActionHeader } from "../layout";
-import { LearnButton } from "../buttons";
+import { useModal } from "../../../hooks/useModal";
+import { ActionHeader } from "../../layout";
+import { LearnButton } from "../../buttons";
export interface SwitchChainProps {
children?: any;
@@ -14,7 +14,6 @@ export interface SwitchChainProps {
/**
* A modal to wrap your component or page with and show a modal re-active to switchChain requests
* it assumes you have already wrapped your app with the Web3Provider out of the @gooddollar/sdk-v2 package
- * @param {boolean} switching indicating if there is a pending switch request triggered
* @param children
* @returns JSX.Element
*/
@@ -37,7 +36,6 @@ export const SwitchChainModal = ({ children }: SwitchChainProps) => {
}
});
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [setOnSwitchNetwork]);
const networkName = find(config.networks, _ => _.chainId === requestedChain)?.chainName;
diff --git a/packages/good-design/src/core/web3/modals/index.ts b/packages/good-design/src/core/web3/modals/index.ts
new file mode 100644
index 00000000..04793e33
--- /dev/null
+++ b/packages/good-design/src/core/web3/modals/index.ts
@@ -0,0 +1,3 @@
+export * from "./SwitchChainModal";
+export * from "./SignTxModal";
+export * from "./KimaModal";
diff --git a/packages/good-design/src/stories/W3Wrapper.tsx b/packages/good-design/src/stories/W3Wrapper.tsx
index 23524828..49d3815f 100644
--- a/packages/good-design/src/stories/W3Wrapper.tsx
+++ b/packages/good-design/src/stories/W3Wrapper.tsx
@@ -19,6 +19,9 @@ const config: Config = {
readOnlyUrls: {
122: "https://rpc.fuse.io",
42220: "https://forno.celo.org"
+ },
+ notifications: {
+ expirationPeriod: 0
}
};
@@ -30,7 +33,7 @@ export const W3Wrapper = ({ children, withMetaMask, env = "fuse" }: PageProps) =
if (!withMetaMask) {
const rpc = new ethers.providers.JsonRpcProvider("https://rpc.fuse.io");
-
+
rpc.getSigner = () => w as any;
setProvider(rpc);
}
diff --git a/packages/good-design/src/stories/apps/bridge/MicroBridgeController.stories.tsx b/packages/good-design/src/stories/apps/bridge/MicroBridgeController.stories.tsx
index 378a4448..98a93da6 100644
--- a/packages/good-design/src/stories/apps/bridge/MicroBridgeController.stories.tsx
+++ b/packages/good-design/src/stories/apps/bridge/MicroBridgeController.stories.tsx
@@ -2,13 +2,13 @@ import { WalletAndChainGuard } from "../../../core/web3/WalletAndChainGuard";
import React from "react";
import { MicroBridgeController } from "../../../apps/bridge/MicroBridgeController";
import { W3Wrapper } from "../../W3Wrapper";
-import { SwitchChainModal } from "../../../core/web3/SwitchChainModal";
+import { SwitchChainModal } from "../../../core/web3/modals/SwitchChainModal";
export default {
title: "Apps/MicroBridgeController",
component: MicroBridgeController,
decorators: [
- (Story:any) => (
+ (Story: any) => (
diff --git a/packages/good-design/src/stories/core/web3/SignTxModal.stories.tsx b/packages/good-design/src/stories/core/web3/SignTxModal.stories.tsx
new file mode 100644
index 00000000..21e92176
--- /dev/null
+++ b/packages/good-design/src/stories/core/web3/SignTxModal.stories.tsx
@@ -0,0 +1,114 @@
+import React, { useCallback, useEffect, useState } from "react";
+import { SignTxModal } from "../../../core";
+import { W3Wrapper } from "../../W3Wrapper";
+import BaseButton from "../../../core/buttons/BaseButton";
+import { Box, HStack, Center, Heading } from "native-base";
+import { useNotifications, useEthers } from "@usedapp/core";
+import { ethers } from "ethers";
+import { JsonRpcSigner } from "@ethersproject/providers";
+import useTestContractFunction from "../../hooks/useTestContractFunction";
+
+const SignTxModalExample = () => {
+ const { notifications } = useNotifications();
+ const [signer, setSigner] = useState(undefined);
+ const { send, transferState } = useTestContractFunction({ signer });
+ const { activateBrowserWallet, library, account } = useEthers();
+ const [connected, setConnected] = useState(false);
+
+ const connect = useCallback(async () => {
+ await (activateBrowserWallet as any)();
+ setConnected(true);
+ }, []);
+
+ useEffect(() => {
+ if (library && !signer && account) {
+ const signer = (library as ethers.providers.JsonRpcProvider)?.getSigner();
+ setSigner(signer);
+ }
+ }, [library, connected]);
+
+ useEffect(() => {
+ console.log("notifications -->", { notifications, transferState });
+ }, [notifications, transferState]);
+
+ return (
+
+
+ {!connected ? (
+
+ ) : (
+ <>
+
+ >
+ )}
+
+
+ {notifications.map(notification => {
+ // this first if check is needed because of a weird type inference
+ if (notification.type === "walletConnected") return;
+ else if (notification.type.includes("transaction"))
+ return (
+
+ Notifications
+
+
+ id: {notification.id}{" "}
+
+
+ type: {notification.type}{" "}
+
+
+ transactionName: {notification.transactionName}{" "}
+
+
+ submittedAt: {notification.submittedAt}{" "}
+
+
+
+ );
+ })}
+
+
+ );
+};
+
+export default {
+ title: "Core/Web3/SignTxModal",
+ component: SignTxModalExample,
+ decorators: [
+ (Story: any) => (
+
+
+
+ )
+ ],
+ argTypes: {}
+};
+
+export const SignTxModalStory = {
+ args: {}
+};
diff --git a/packages/good-design/src/stories/hooks/useTestContractFunction.tsx b/packages/good-design/src/stories/hooks/useTestContractFunction.tsx
new file mode 100644
index 00000000..584acba7
--- /dev/null
+++ b/packages/good-design/src/stories/hooks/useTestContractFunction.tsx
@@ -0,0 +1,37 @@
+import React, { useCallback, useState } from "react";
+import { useEthers } from "@usedapp/core";
+import { ethers, Contract } from "ethers";
+import { JsonRpcSigner } from "@ethersproject/providers";
+import { useContractFunctionWithDefaultGasFees } from "@gooddollar/web3sdk-v2";
+import Contracts from "@gooddollar/goodprotocol/releases/deployment.json";
+// import {
+// IGoodDollar,
+// } from "@gooddollar/goodprotocol/types";
+import GoodDollarABI from "@gooddollar/goodprotocol/artifacts/abis/IGoodDollar.min.json";
+
+interface CustomProps {
+ signer?: JsonRpcSigner;
+}
+
+const useTestContractFunction = (params: CustomProps) => {
+ const { signer } = params;
+ const { account } = useEthers();
+ const gdContract = new Contract(Contracts["fuse"].GoodDollar, GoodDollarABI.abi, signer) as any;
+
+ const { state: transferState, send: sendTransfer } = useContractFunctionWithDefaultGasFees(
+ gdContract,
+ "transferAndCall",
+ {
+ transactionName: "SelfTransfer"
+ }
+ );
+
+ const send = useCallback(async () => {
+ const callData = ethers.constants.HashZero;
+ await sendTransfer(account, "10000", callData);
+ }, [account, sendTransfer, signer]);
+
+ return { send, transferState };
+};
+
+export default useTestContractFunction;
diff --git a/packages/sdk-v2/src/sdk/base/hooks/useGasFees.ts b/packages/sdk-v2/src/sdk/base/hooks/useGasFees.ts
index 72339e4b..80204854 100644
--- a/packages/sdk-v2/src/sdk/base/hooks/useGasFees.ts
+++ b/packages/sdk-v2/src/sdk/base/hooks/useGasFees.ts
@@ -30,8 +30,9 @@ export const useGasFees = () => {
export function useContractFunctionWithDefaultGasFees>(
contract: T | Falsy,
functionName: FN,
- options?: TransactionOptions
+ customOptions?: TransactionOptions
) {
+ const options = { enablePendingSignatureNotification: true, ...customOptions };
const { send, ...rest } = useContractFunction(contract, functionName, options);
const gasFees = useGasFees();
const newSend = useCallback(
diff --git a/packages/sdk-v2/src/sdk/claim/react.ts b/packages/sdk-v2/src/sdk/claim/react.ts
index 999a361a..90cfdb04 100644
--- a/packages/sdk-v2/src/sdk/claim/react.ts
+++ b/packages/sdk-v2/src/sdk/claim/react.ts
@@ -42,7 +42,7 @@ export const useClaim = (refresh: QueryParams["refresh"] = "never") => {
const ubi = useGetContract("UBIScheme", true, "claim", chainId) as UBIScheme;
const identity = useGetContract("Identity", true, "claim", chainId) as IIdentity;
- const claimCall = useContractFunctionWithDefaultGasFees(ubi, "claim");
+ const claimCall = useContractFunctionWithDefaultGasFees(ubi, "claim", { transactionName: "Claimed Daily UBI" });
const results = useCalls(
[
diff --git a/packages/sdk-v2/src/sdk/microbridge/react.ts b/packages/sdk-v2/src/sdk/microbridge/react.ts
index 3bc2e4de..85bb18c5 100644
--- a/packages/sdk-v2/src/sdk/microbridge/react.ts
+++ b/packages/sdk-v2/src/sdk/microbridge/react.ts
@@ -109,7 +109,9 @@ export const useBridge = (withRelay = false) => {
const [selfRelayStatus, setSelfRelay] = useState | undefined>();
// const bridgeTo = useContractFunction(bridgeContract, "bridgeTo", {});
- const transferAndCall = useContractFunctionWithDefaultGasFees(g$Contract, "transferAndCall");
+ const transferAndCall = useContractFunctionWithDefaultGasFees(g$Contract, "transferAndCall", {
+ transactionName: "BridgeTransfer"
+ });
const bridgeRequestId = (transferAndCall.state?.receipt?.logs || [])
.filter(log => log.address === bridgeContract.address)
.map(log => bridgeContract.interface.parseLog(log))?.[0]?.args?.id;
diff --git a/yarn.lock b/yarn.lock
index 178f798a..1affd717 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3255,7 +3255,7 @@ __metadata:
"@babel/preset-typescript": ^7.16.0
"@babel/runtime": ^7.18.9
"@gooddollar/goodprotocol": ^2.0.3
- "@gooddollar/web3sdk-v2": latest
+ "@gooddollar/web3sdk-v2": "workspace:^"
"@lingui/macro": ^3.14.0
"@lingui/react": ^3.14.0
"@magiklabs/react-sdk": ^1.0.8
@@ -3438,7 +3438,7 @@ __metadata:
languageName: node
linkType: hard
-"@gooddollar/web3sdk-v2@workspace:packages/sdk-v2":
+"@gooddollar/web3sdk-v2@workspace:^, @gooddollar/web3sdk-v2@workspace:packages/sdk-v2":
version: 0.0.0-use.local
resolution: "@gooddollar/web3sdk-v2@workspace:packages/sdk-v2"
dependencies: