diff --git a/components/account/AccountButton.tsx b/components/account/AccountButton.tsx
index 53717b2c8..e88789054 100644
--- a/components/account/AccountButton.tsx
+++ b/components/account/AccountButton.tsx
@@ -88,11 +88,11 @@ const AccountButton: FC<{
selectWallet,
disconnectWallet,
isNovaWallet,
- proxyFor,
+ getProxyFor,
realAddress,
} = useWallet();
- const proxy = proxyFor?.[activeAccount?.address];
+ const proxy = getProxyFor(activeAccount?.address);
const accountModals = useAccountModals();
const { locationAllowed, isUsingVPN } = useUserLocation();
@@ -266,17 +266,23 @@ const AccountButton: FC<{
-
-
- {shortenAddress(realAddress, 7, 7)}
+ {realAddress && (
+
+
+ {shortenAddress(
+ realAddress,
+ 7,
+ 7,
+ )}
+
+
+
+
-
-
-
-
+ )}
diff --git a/components/account/AccountModalContent.tsx b/components/account/AccountModalContent.tsx
index d5c2672a9..2add34cf3 100644
--- a/components/account/AccountModalContent.tsx
+++ b/components/account/AccountModalContent.tsx
@@ -7,10 +7,9 @@ import { ZTG } from "@zeitgeistpm/sdk-next";
import { useChainConstants } from "lib/hooks/queries/useChainConstants";
const AccountModalContent: FC = () => {
- const { activeAccount, disconnectWallet, accounts, selectAccount, proxyFor } =
+ const { activeAccount, disconnectWallet, accounts, selectAccount } =
useWallet();
- const proxy = proxyFor?.[activeAccount?.address];
const { data: activeBalance } = useZtgBalance(activeAccount?.address);
const { data: constants } = useChainConstants();
diff --git a/components/create/editor/Editor.tsx b/components/create/editor/Editor.tsx
index 2122309d8..4435e8c01 100644
--- a/components/create/editor/Editor.tsx
+++ b/components/create/editor/Editor.tsx
@@ -42,7 +42,7 @@ const QuillEditor = dynamic(() => import("components/ui/QuillEditor"), {
const createMarketStateAtom = persistentAtom({
key: "market-creation-form",
defaultValue: MarketDraft.empty(),
- migrations: [],
+ migrations: [() => MarketDraft.empty()],
});
export const MarketEditor = () => {
diff --git a/components/create/editor/Publishing.tsx b/components/create/editor/Publishing.tsx
index 30696b9ea..caaad09d7 100644
--- a/components/create/editor/Publishing.tsx
+++ b/components/create/editor/Publishing.tsx
@@ -43,20 +43,20 @@ export const Publishing = ({ editor }: PublishingProps) => {
const params = useMemo(() => {
let signer = wallet.getSigner();
- const real =
- wallet.proxyFor?.enabled && wallet.proxyFor?.address
- ? (wallet.activeAccount as KeyringPairOrExtSigner)
- : signer;
+ if (!editor.isValid || !chainTime || !signer) return;
- if (editor.isValid && chainTime && signer) {
+ const proxy = wallet.getProxyFor(wallet.activeAccount?.address);
+
+ if (proxy && proxy.enabled) {
return marketFormDataToExtrinsicParams(
editor.form,
- real,
+ { address: wallet.realAddress } as KeyringPairOrExtSigner,
chainTime,
signer,
);
}
- return;
+
+ return marketFormDataToExtrinsicParams(editor.form, signer, chainTime);
}, [editor.form, chainTime, wallet.activeAccount]);
const feesEnabled = !(
@@ -87,12 +87,12 @@ export const Publishing = ({ editor }: PublishingProps) => {
(a) => a.name === editor.form.currency,
);
- const { data: ztgBalance } = useBalance(wallet.activeAccount?.address, {
+ const { data: ztgBalance } = useBalance(wallet.realAddress, {
Ztg: null,
});
const { data: foreignAssetBalance } = useBalance(
- wallet.activeAccount?.address,
+ wallet.realAddress,
baseCurrency?.assetId,
);
diff --git a/components/create/editor/Summary.tsx b/components/create/editor/Summary.tsx
index e2db7989e..25d85e33f 100644
--- a/components/create/editor/Summary.tsx
+++ b/components/create/editor/Summary.tsx
@@ -211,9 +211,7 @@ export const MarketSummary = ({ editor }: MarketSummaryProps) => {
: Intl.DateTimeFormat("default", {
dateStyle: "medium",
timeStyle: "short",
- }).format(
- blockDate(chainTime!, form.gracePeriod?.block!).getTime(),
- )}
+ }).format(new Date(form.gracePeriod?.date!).getTime())}
diff --git a/components/create/editor/inputs/BlockPeriod.tsx b/components/create/editor/inputs/BlockPeriod.tsx
index 9cf770f5c..8b1361f5c 100644
--- a/components/create/editor/inputs/BlockPeriod.tsx
+++ b/components/create/editor/inputs/BlockPeriod.tsx
@@ -64,7 +64,7 @@ export const BlockPeriodPicker: React.FC
= ({
name,
value: {
type: "date",
- block: dateBlock(chainTime, new Date(event.target.value)),
+ date: event.target.value,
},
},
});
@@ -78,7 +78,7 @@ export const BlockPeriodPicker: React.FC = ({
name,
value: {
type: "date",
- block: dateBlock(chainTime, new Date(event.target.value)),
+ date: event.target.value,
},
},
});
@@ -159,11 +159,7 @@ export const BlockPeriodPicker: React.FC = ({
}`}
placeholder="Set Custom Date"
isValid={value?.type === "date" && isValid}
- value={
- chainTime && value?.type === "date"
- ? blockDate(chainTime, value.block).toISOString()
- : undefined
- }
+ value={chainTime && value?.type === "date" ? value.date : undefined}
onChange={handleDateChange}
onBlur={handleDateBlur}
/>
diff --git a/components/create/editor/inputs/DateTime.tsx b/components/create/editor/inputs/DateTime.tsx
index bff9a0312..f2079a57c 100644
--- a/components/create/editor/inputs/DateTime.tsx
+++ b/components/create/editor/inputs/DateTime.tsx
@@ -68,7 +68,11 @@ export const DateTimePicker: React.FC = ({
ref={inputRef}
name={name}
type="datetime-local"
- value={moment(value).format("YYYY-MM-DDTHH:mm")}
+ value={
+ value
+ ? moment(value).format("YYYY-MM-DDTHH:mm")
+ : moment().hours(0).minutes(0).format("YYYY-MM-DDTHH:mm")
+ }
onChange={handleChange}
onBlurCapture={handleBlur}
/>
diff --git a/components/create/editor/inputs/Oracle.tsx b/components/create/editor/inputs/Oracle.tsx
index 49637a813..6518edc6d 100644
--- a/components/create/editor/inputs/Oracle.tsx
+++ b/components/create/editor/inputs/Oracle.tsx
@@ -48,6 +48,7 @@ export const OracleInput = forwardRef(
};
const handleUseConnectedAccount = () => {
+ if (!wallet?.realAddress) return;
onChange?.({
type: "change",
target: {
@@ -68,11 +69,11 @@ export const OracleInput = forwardRef(
};
const isSelectedAccount = wallet.realAddress === value;
- const proxy = wallet.proxyFor?.[wallet.activeAccount?.address];
+ const proxy = wallet.getProxyFor(wallet.activeAccount?.address);
const accountname =
- proxy && proxy.enabled
+ proxy && proxy?.enabled
? "Proxied"
- : wallet.activeAccount.name ?? "Account";
+ : wallet.activeAccount?.name ?? "Account";
return (
@@ -123,18 +124,23 @@ export const OracleInput = forwardRef(
isSelectedAccount ? "bg-nyanza-base" : "bg-gray-200"
}`}
>
-
-
- {accountname ? (
- <>
- {accountname} {shortenAddress(wallet.realAddress, 0, 6)}
- >
- ) : (
- <>{shortenAddress(wallet.realAddress, 6, 6)}>
- )}
-
+ {wallet.realAddress && (
+ <>
+
+
+ {accountname ? (
+ <>
+ {accountname}{" "}
+ {shortenAddress(wallet.realAddress, 0, 6)}
+ >
+ ) : (
+ <>{shortenAddress(wallet.realAddress, 6, 6)}>
+ )}
+
+ >
+ )}
diff --git a/components/create/editor/inputs/answers/Categorical.tsx b/components/create/editor/inputs/answers/Categorical.tsx
index 55efcc197..b9859f288 100644
--- a/components/create/editor/inputs/answers/Categorical.tsx
+++ b/components/create/editor/inputs/answers/Categorical.tsx
@@ -23,7 +23,7 @@ import { MdOutlineDragIndicator } from "react-icons/md";
import { FormEvent } from "../../types";
export type CategoricalAnswersInputProps = {
- name?: string;
+ name: string;
value?: CategoricalAnswers | YesNoAnswers;
onChange?: (event: FormEvent) => void;
onBlur?: (event: FormEvent) => void;
@@ -57,7 +57,9 @@ export const CategoricalAnswersInput = ({
value: {
type: "categorical",
answers:
- value?.answers.map((v, i) => (i === index ? answer : v)) ?? [],
+ value?.answers.map((v: string, i: number) =>
+ i === index ? answer : v,
+ ) ?? [],
},
},
});
@@ -93,10 +95,12 @@ export const CategoricalAnswersInput = ({
const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event;
- if (active.id !== over.id) {
+ if (over && active.id !== over.id) {
const oldIndex = value?.answers.findIndex((v) => v === active.id);
const newIndex = value?.answers.findIndex((v) => v === over.id);
+ if (!oldIndex || !newIndex || !value?.answers) return;
+
onChange?.({
type: "change",
target: {
@@ -112,7 +116,8 @@ export const CategoricalAnswersInput = ({
const draggingDisabled =
disabled ||
- value?.answers.length < 2 ||
+ !value?.answers ||
+ value?.answers?.length < 2 ||
uniq(value?.answers).length < value?.answers.length;
return (
@@ -135,7 +140,7 @@ export const CategoricalAnswersInput = ({
) => void;
onBlur?: (event: FormEvent) => void;
@@ -50,7 +50,7 @@ export const ScalarAnswersInput = ({
name,
value: {
type: "scalar",
- numberType: value.numberType,
+ numberType: value?.numberType ?? "number",
answers: (value?.answers.map((v, i) =>
i === index ? newValue : v,
) ?? []) as [number, number],
@@ -75,7 +75,7 @@ export const ScalarAnswersInput = ({
name,
value: {
type: "scalar",
- numberType: value.numberType,
+ numberType: value?.numberType ?? "number",
answers: (value?.answers.map((v, i) =>
i === index ? newValue : v,
) ?? []) as [number, number],
diff --git a/components/create/editor/inputs/answers/index.tsx b/components/create/editor/inputs/answers/index.tsx
index 9f97b8684..1c20c8d35 100644
--- a/components/create/editor/inputs/answers/index.tsx
+++ b/components/create/editor/inputs/answers/index.tsx
@@ -87,6 +87,7 @@ export const AnswersInput = ({
{value?.type === "categorical" && (
)}
{value?.type === "yes/no" && (
-
+
)}
>
diff --git a/components/portfolio/PortfolioIdentity.tsx b/components/portfolio/PortfolioIdentity.tsx
index e8fbd9402..eb2dd6baf 100644
--- a/components/portfolio/PortfolioIdentity.tsx
+++ b/components/portfolio/PortfolioIdentity.tsx
@@ -10,7 +10,7 @@ const PortfolioIdentity = ({ address }: { address: string }) => {
const wallet = useWallet();
const { data: identity } = useIdentity(address);
- const proxy = wallet.proxyFor?.[wallet.activeAccount?.address];
+ const proxy = wallet.getProxyFor(wallet.activeAccount?.address);
const isProxying = Boolean(
proxy && proxy.enabled && proxy.address === address,
diff --git a/lib/hooks/useCrossChainExtrinsic.ts b/lib/hooks/useCrossChainExtrinsic.ts
index 0ce636aa4..f8261586c 100644
--- a/lib/hooks/useCrossChainExtrinsic.ts
+++ b/lib/hooks/useCrossChainExtrinsic.ts
@@ -44,15 +44,16 @@ export const useCrossChainExtrinsic = (
let extrinsic = extrinsicFn(params);
- const proxy = wallet?.proxyFor?.[wallet.activeAccount?.address];
+ const proxy = wallet?.getProxyFor(wallet.activeAccount?.address);
let signer = wallet.getSigner();
- if (proxy?.enabled && proxy?.address) {
+ if (extrinsic && proxy?.enabled && proxy?.address) {
console.info("Proxying cross chain transaction");
extrinsic = sdk.api.tx.proxy.proxy(proxy?.address, "Any", extrinsic);
}
- if (!extrinsic || !sourceChainApi || !destinationChainApi) return;
+ if (!signer || !extrinsic || !sourceChainApi || !destinationChainApi)
+ return;
signAndSend(
extrinsic,
signer,
diff --git a/lib/hooks/useExtrinsic.ts b/lib/hooks/useExtrinsic.ts
index 448d00558..082758550 100644
--- a/lib/hooks/useExtrinsic.ts
+++ b/lib/hooks/useExtrinsic.ts
@@ -31,13 +31,15 @@ export const useExtrinsic = (
throw new Error("SDK is not RPC");
}
+ let signer = wallet.getSigner();
+ if (!signer) return;
+
setIsLoading(true);
let extrinsic = extrinsicFn(params);
if (!extrinsic) return;
- const proxy = wallet?.proxyFor?.[wallet.activeAccount?.address];
- let signer = wallet.getSigner();
+ const proxy = wallet?.getProxyFor(wallet.activeAccount?.address);
if (proxy?.enabled && proxy?.address) {
console.info("Proxying transaction");
diff --git a/lib/state/chaintime.ts b/lib/state/chaintime.ts
index 649bab1fb..78747ca85 100644
--- a/lib/state/chaintime.ts
+++ b/lib/state/chaintime.ts
@@ -10,7 +10,7 @@ const store = getDefaultStore();
let sub: Subscription;
-store.sub(sdkAtom, () => {
+const onSdkChange = () => {
const sdk = store.get(sdkAtom);
if (sub) sub.unsubscribe();
if (isRpcSdk(sdk)) {
@@ -18,7 +18,16 @@ store.sub(sdkAtom, () => {
store.set(chainTimeAtom, time);
});
}
-});
+};
+
+/**
+ * In dev the subscription is sometimes not set up on first render.
+ * So we need to check if the sdk is already set up and if so update the chaintime atom.
+ */
+const sdk = store.get(sdkAtom);
+if (sdk) onSdkChange();
+
+store.sub(sdkAtom, onSdkChange);
export const useChainTime = (): ChainTime | null => {
const [chainTime] = useAtom(chainTimeAtom);
diff --git a/lib/state/market-creation/editor.ts b/lib/state/market-creation/editor.ts
index 1efa681c6..2299c963d 100644
--- a/lib/state/market-creation/editor.ts
+++ b/lib/state/market-creation/editor.ts
@@ -16,7 +16,7 @@ import {
MarketCreationStep,
MarketCreationStepType,
marketCreationSteps,
- stepForFormKey,
+ sectionForFormKey,
stepFormKeys,
} from "./types/step";
import { useMarketCreationFormValidator } from "./types/validation";
@@ -148,6 +148,8 @@ export const useMarketDraftEditor = ({
const validator = useMarketCreationFormValidator(draft.form);
const fieldsState = useMemo(() => {
+ if (!validator) return FieldsState.empty();
+
const parsed = validator.safeParse(draft.form);
const fieldsState = marketCreationFormKeys.reduce(
@@ -267,7 +269,7 @@ export const useMarketDraftEditor = ({
touchState: { ...draft.touchState, [key]: true },
};
if (!draft.isWizard) {
- const section = stepForFormKey(key);
+ const section = sectionForFormKey(key);
newDraft.stepReachState[section] = true;
}
update(newDraft);
@@ -280,7 +282,7 @@ export const useMarketDraftEditor = ({
touchState: { ...draft.touchState, [key]: true },
};
if (!draft.isWizard) {
- const section = stepForFormKey(key);
+ const section = sectionForFormKey(key);
newDraft.stepReachState[section] = true;
}
update(newDraft);
@@ -309,7 +311,7 @@ export const useMarketDraftEditor = ({
const prevAnswersLength = usePrevious(draft.form.answers?.answers?.length);
useEffect(() => {
- if (!draft.form.answers) return;
+ if (!draft.form.answers || !draft.form.liquidity) return;
const baseAmount = minBaseLiquidity[draft.form.currency!]
? `${minBaseLiquidity[draft.form.currency!] / 2}`
diff --git a/lib/state/market-creation/types/draft.ts b/lib/state/market-creation/types/draft.ts
index 0816c7290..fe0af4f99 100644
--- a/lib/state/market-creation/types/draft.ts
+++ b/lib/state/market-creation/types/draft.ts
@@ -46,7 +46,7 @@ export type MarketDraftState = {
/**
* Create a new empty draft state.
*/
-export const empty = (): MarketDraftState => ({
+export const empty = () => ({
isWizard: true,
currentStep: {
label: "Currency",
@@ -79,4 +79,4 @@ export const empty = (): MarketDraftState => ({
Currency: true,
},
isPublished: false,
-});
+} satisfies MarketDraftState);
diff --git a/lib/state/market-creation/types/form.ts b/lib/state/market-creation/types/form.ts
index 248df7b3e..28ac98188 100644
--- a/lib/state/market-creation/types/form.ts
+++ b/lib/state/market-creation/types/form.ts
@@ -1,7 +1,6 @@
import {
CreateMarketBaseParams,
CreateMarketParams,
- MarketMetadata,
MetadataStorage,
RpcContext,
ZTG,
@@ -11,9 +10,11 @@ import { KeyringPairOrExtSigner } from "@zeitgeistpm/sdk/dist/types";
import { ChainTime } from "@zeitgeistpm/utility/dist/time";
import Decimal from "decimal.js";
import { BLOCK_TIME_SECONDS } from "lib/constants";
+import { getMetadataForCurrency } from "lib/constants/supported-currencies";
import moment from "moment";
import { DeepRequired } from "react-hook-form";
import * as z from "zod";
+import { tickersForAnswers } from "../util/tickers";
import { timelineAsBlocks } from "./timeline";
import {
IOAnswers,
@@ -34,8 +35,6 @@ import {
IOTags,
IOYesNoAnswers,
} from "./validation";
-import { tickersForAnswers } from "../util/tickers";
-import { getMetadataForCurrency } from "lib/constants/supported-currencies";
/**
* This is the type of the full market creation form data that is used to create a market.
diff --git a/lib/state/market-creation/types/step.ts b/lib/state/market-creation/types/step.ts
index f7e06ed60..45b5b5ee2 100644
--- a/lib/state/market-creation/types/step.ts
+++ b/lib/state/market-creation/types/step.ts
@@ -75,11 +75,14 @@ export const stepFormKeys: Record<
* Get the market step type a given form key is related to.
* @param key - the form key to get the section for
*/
-export const stepForFormKey = (
+export const sectionForFormKey = (
key: keyof MarketFormData,
): MarketCreationStepType => {
for (const sectionKey in stepFormKeys) {
if (stepFormKeys[sectionKey].includes(key))
return sectionKey as MarketCreationStepType;
}
+ throw new Error(
+ `[SHOULD BE UNREACHABLE] No section found for form key ${key}`,
+ );
};
diff --git a/lib/state/market-creation/types/timeline.ts b/lib/state/market-creation/types/timeline.ts
index e474d1752..039e48348 100644
--- a/lib/state/market-creation/types/timeline.ts
+++ b/lib/state/market-creation/types/timeline.ts
@@ -25,19 +25,19 @@ export const timelineAsBlocks = (
const gracePeriodEndBlock =
form.gracePeriod?.type === "date"
- ? form.gracePeriod?.block
+ ? dateBlock(chainTime, new Date(form.gracePeriod?.date))
: marketEndBlock +
(form.gracePeriod ? durationasBlocks(form.gracePeriod) : 0);
const reportPeriodEndBlock =
form.reportingPeriod?.type === "date"
- ? form.reportingPeriod?.block
+ ? dateBlock(chainTime, new Date(form.reportingPeriod?.date))
: gracePeriodEndBlock +
(form.reportingPeriod ? durationasBlocks(form.reportingPeriod) : 0);
const disputePeriodEndBlock =
form.disputePeriod?.type === "date"
- ? form.disputePeriod?.block
+ ? dateBlock(chainTime, new Date(form.disputePeriod?.date))
: reportPeriodEndBlock +
(form.disputePeriod ? durationasBlocks(form.disputePeriod) : 0);
diff --git a/lib/state/market-creation/types/validation.ts b/lib/state/market-creation/types/validation.ts
index f68ed5fd1..e6f110c04 100644
--- a/lib/state/market-creation/types/validation.ts
+++ b/lib/state/market-creation/types/validation.ts
@@ -36,7 +36,7 @@ export const createMarketFormValidator = ({
chainTime,
}: MarketValidationDependencies) => {
const timeline = timelineAsBlocks(form, chainTime).unwrap();
- console.log(timeline);
+
return z
.object({
currency: IOCurrency,
@@ -138,10 +138,13 @@ export const createMarketFormValidator = ({
*/
export const useMarketCreationFormValidator = (
form: Partial,
-): ReturnType => {
+): ReturnType | undefined => {
const { data: deadlineConstants } = useMarketDeadlineConstants();
const chainTime = useChainTime();
+
return useMemo(() => {
+ if (!deadlineConstants || !chainTime) return undefined;
+
return createMarketFormValidator({
form,
deadlineConstants,
@@ -228,7 +231,12 @@ export const IOEndDate = z
export const IOPeriodDateOption = z.object({
type: z.literal("date"),
- block: z.number(),
+ date: z
+ .string()
+ .datetime()
+ .refine((date) => new Date(date) > new Date(), {
+ message: "End date must be in the future",
+ }),
});
export const IOPeriodDurationOption = z.object({
diff --git a/lib/state/market-creation/util/tickers.ts b/lib/state/market-creation/util/tickers.ts
index f4a70f985..0cdddb2e8 100644
--- a/lib/state/market-creation/util/tickers.ts
+++ b/lib/state/market-creation/util/tickers.ts
@@ -36,31 +36,35 @@ export const tickersForAnswers = (
* Generate appropriate tickers for categorical answers.
*/
export const createCategoricalTickers = (
- answers: string[],
-): { [key: string]: string } => {
- const tickers: { [key: string]: string } = {};
- const usedTickers: { [key: string]: boolean } = {};
+ strings: string[],
+): Record => {
+ const tokens: Record = {};
- for (const description of answers) {
- const words = description.split(" ");
+ for (const str of strings) {
+ const words = str.split(" ");
+ let token = "";
- let ticker = (
- words[0].slice(0, 3) + words[words.length - 1].slice(0, 3)
- ).toUpperCase();
+ for (let i = 0; i < words.length; i++) {
+ const word = words[i];
+ const truncatedWord = word.slice(0, 3);
- if (usedTickers[ticker]) {
- let count = 1;
- let newTicker = ticker;
- while (usedTickers[newTicker]) {
- count++;
- newTicker = ticker + String(count);
+ if (i === words.length - 1) {
+ token += truncatedWord.toUpperCase();
+ } else {
+ token += truncatedWord;
}
- ticker = newTicker;
}
- usedTickers[ticker] = true;
- tickers[description] = ticker;
+ tokens[str] = token;
}
- return tickers;
+ return tokens;
+};
+
+const input = ["foo bar", "foo bar baz", "foo bar baz qux"];
+
+const output = {
+ "foo bar": "FOOBAR",
+ "foo bar baz": "FOOBAZ",
+ "foo bar baz qux": "FOOQUX",
};
diff --git a/lib/state/util/persistent-atom.ts b/lib/state/util/persistent-atom.ts
index a79b2342c..75aa48547 100644
--- a/lib/state/util/persistent-atom.ts
+++ b/lib/state/util/persistent-atom.ts
@@ -1,6 +1,6 @@
import { atom, getDefaultStore, createStore } from "jotai";
import { RESET, atomWithStorage } from "jotai/utils";
-import { tryCatch } from "@zeitgeistpm/utility/dist/option";
+import { tryCatch, fromNullable } from "@zeitgeistpm/utility/dist/option";
export type PersistentAtomConfig = {
/**
@@ -10,7 +10,7 @@ export type PersistentAtomConfig = {
/**
* Default value if no value is stored.
*/
- defaultValue: Versioned;
+ defaultValue: T;
/**
* Migrations to run on the stored value.
* @note index is used as version number.
@@ -45,14 +45,15 @@ export type Migration = (state: A) => B;
* @returns WritableAtom(opts: PersistentAtomConfig>) => {
- const parsedStorageValue = tryCatch(
- () =>
- JSON.parse(globalThis.localStorage?.getItem(opts.key)) as Versioned,
- ).unwrapOr(opts.defaultValue);
+ const parsedStorageValue = fromNullable(
+ globalThis.localStorage?.getItem(opts.key),
+ )
+ .bind((raw) => tryCatch(() => JSON.parse(raw) as Versioned))
+ .unwrapOr(opts.defaultValue);
const storageAtom = atomWithStorage>(
opts.key,
- (parsedStorageValue ?? opts.defaultValue) as Versioned,
+ parsedStorageValue,
);
const store = opts.store ?? getDefaultStore();
@@ -61,25 +62,27 @@ export const persistentAtom = (opts: PersistentAtomConfig>) => {
const nextVersion = opts.migrations?.length ?? 0;
if (nextVersion > initialVersion) {
- console.group(`state-migration:${opts.key}`);
+ let newState = initialState;
+ const migrations = opts.migrations?.slice(initialVersion);
- const migrations = opts.migrations.slice(initialVersion);
+ if (migrations) {
+ console.group(`state-migration:${opts.key}`);
+ console.info(`initial [version: ${initialVersion}]`, initialState);
- console.info(`initial [version: ${initialVersion}]`, initialState);
+ newState = migrations.reduce((acc, migration, version) => {
+ const nextVersion = initialVersion + version + 1;
+ const nextState = { ...migration(acc), __version: nextVersion };
- const newState = migrations.reduce((acc, migration, version) => {
- const nextVersion = initialVersion + version + 1;
- const nextState = { ...migration(acc), __version: nextVersion };
+ if (migrations.length == 1 || nextVersion !== 1) {
+ const step = version == migrations.length - 1 ? "final" : "next";
+ console.info(`${step} [version: ${nextVersion}]`, nextState);
+ }
- if (migrations.length == 1 || nextVersion !== 1) {
- const step = version == migrations.length - 1 ? "final" : "next";
- console.info(`${step} [version: ${nextVersion}]`, nextState);
- }
-
- return nextState;
- }, initialState);
+ return nextState;
+ }, initialState);
- console.groupEnd();
+ console.groupEnd();
+ }
store.set(storageAtom, { ...newState, __version: nextVersion });
}
diff --git a/lib/state/wallet.ts b/lib/state/wallet.ts
index 03c21bffe..ba5e1010c 100644
--- a/lib/state/wallet.ts
+++ b/lib/state/wallet.ts
@@ -10,48 +10,51 @@ import { TalismanWallet } from "../wallets/talisman-wallet";
import { Wallet, WalletAccount } from "../wallets/types";
import { persistentAtom } from "./util/persistent-atom";
-export type UseWallet = WalletState &
- Pick & {
- /**
- * The real address of the current wallet.
- * Use this to read data from the blockchain or the indexer when it comes to assets and markets.
- * It will be the address the activeAccount is proxying for if proxy execution is enabled.
- */
- realAddress?: string;
- /**
- * The active account of the current wallet.
- */
- activeAccount?: WalletAccount;
- /**
- * Whether the wallet is nova wallet.
- */
- isNovaWallet: boolean;
- /**
- * Get the active signer for transactions. Is either the real account or the proxy account.
- */
- getSigner: () => KeyringPairOrExtSigner | null;
- /**
- * Select a wallet.
- * @param wallet the selected wallet id or instance
- * @returns void
- */
- selectWallet: (wallet: Wallet | string) => void;
- /**
- * Select an address.
- * @param account the address to select
- * @returns void
- */
- selectAccount: (account: string) => void;
- /**
- * Disconnect the wallet.
- * @returns void
- */
- disconnectWallet: () => void;
- /**
- * Set if proxy execution is enabled.
- */
- setProxyFor: (real: string, conf: ProxyConfig) => void;
- };
+export type UseWallet = WalletState & {
+ /**
+ * The real address of the current wallet.
+ * Use this to read data from the blockchain or the indexer when it comes to assets and markets.
+ * It will be the address the activeAccount is proxying for if proxy execution is enabled.
+ */
+ realAddress?: string;
+ /**
+ * The active account of the current wallet.
+ */
+ activeAccount?: WalletAccount;
+ /**
+ * Whether the wallet is nova wallet.
+ */
+ isNovaWallet: boolean;
+ /**
+ * Get the active signer for transactions. Is either the real account or the proxy account.
+ */
+ getSigner: () => KeyringPairOrExtSigner | undefined;
+ /**
+ * Select a wallet.
+ * @param wallet the selected wallet id or instance
+ * @returns void
+ */
+ selectWallet: (wallet: Wallet | string) => void;
+ /**
+ * Select an address.
+ * @param account the address to select
+ * @returns void
+ */
+ selectAccount: (account: string) => void;
+ /**
+ * Disconnect the wallet.
+ * @returns void
+ */
+ disconnectWallet: () => void;
+ /**
+ * Set if proxy execution is enabled.
+ */
+ setProxyFor: (real: string, conf: ProxyConfig) => void;
+ /**
+ * Get the proxy config for an address(real).
+ */
+ getProxyFor: (address?: string) => ProxyConfig | undefined;
+};
export type ProxyConfig = {
enabled: boolean;
@@ -161,15 +164,15 @@ const userConfigAtom = persistentAtom({
if (
selectedAddress &&
- tryCatch(() => encodeAddress(selectedAddress)).isNone()
+ tryCatch(() => encodeAddress(selectedAddress!)).isNone()
) {
console.log("Invalid address in localStorage, disconnecting wallet.");
return {};
}
return {
- walletId,
- selectedAddress,
+ walletId: walletId ?? undefined,
+ selectedAddress: selectedAddress ?? undefined,
};
}
@@ -195,7 +198,7 @@ export const supportedWallets = [
new TalismanWallet(),
];
-let accountsSubscriptionUnsub: VoidFunction | undefined;
+let accountsSubscriptionUnsub: VoidFunction | undefined | null;
/**
* Enable a wallet by enabling the extension and setting the wallet atom state to connected.
@@ -232,15 +235,16 @@ const enableWallet = async (walletId: Wallet | string) => {
store.set(walletAtom, (state) => {
return {
...state,
- connected: accounts.length > 0,
- accounts: accounts.map((account) => {
- return {
- ...account,
- address: encodeAddress(account.address, 73),
- };
- }),
+ connected: Boolean(accounts && accounts.length > 0),
+ accounts:
+ accounts?.map((account) => {
+ return {
+ ...account,
+ address: encodeAddress(account.address, 73),
+ };
+ }) ?? [],
errors:
- accounts.length === 0
+ accounts?.length === 0
? [
{
extensionName: wallet.extensionName,
@@ -260,7 +264,7 @@ const enableWallet = async (walletId: Wallet | string) => {
accounts: [],
errors: [
{
- extensionName: wallet?.extensionName,
+ extensionName: wallet?.extensionName ?? "unknown wallet",
type: "InteractionDenied",
},
],
@@ -273,8 +277,9 @@ const enableWallet = async (walletId: Wallet | string) => {
/**
* Enable wallet on first load if wallet id is set.
*/
-if (store.get(userConfigAtom).walletId) {
- enableWallet(store.get(userConfigAtom).walletId);
+const initialWalletId = store.get(userConfigAtom).walletId;
+if (initialWalletId) {
+ enableWallet(initialWalletId);
}
/**
@@ -301,7 +306,12 @@ export const useWallet = (): UseWallet => {
};
const getSigner = (): KeyringPairOrExtSigner | undefined => {
- if (walletState.wallet == null || !activeAccount) return;
+ if (
+ walletState.wallet == null ||
+ !activeAccount ||
+ !walletState.wallet.signer
+ )
+ return;
return {
address: activeAccount.address,
signer: walletState.wallet.signer,
@@ -331,6 +341,10 @@ export const useWallet = (): UseWallet => {
});
};
+ const getProxyFor = (address: string): ProxyConfig | undefined => {
+ return userConfig.proxyFor?.[address];
+ };
+
const activeAccount = useMemo(() => {
const userSelectedAddress = walletState.accounts.find((acc) => {
return (
@@ -365,5 +379,6 @@ export const useWallet = (): UseWallet => {
disconnectWallet,
isNovaWallet,
setProxyFor,
+ getProxyFor,
};
};
diff --git a/pages/settings.tsx b/pages/settings.tsx
index a477a0b84..fd93095cb 100644
--- a/pages/settings.tsx
+++ b/pages/settings.tsx
@@ -204,7 +204,7 @@ const ProxySettings = () => {
const [sdk] = useSdkv2();
const wallet = useWallet();
- const proxy = wallet.proxyFor?.[wallet.activeAccount?.address];
+ const proxy = wallet.getProxyFor(wallet.activeAccount?.address);
const {
register,
@@ -221,6 +221,7 @@ const ProxySettings = () => {
});
const onSubmit = (data: ProxyConfig) => {
+ if (!wallet.activeAccount?.address) return;
wallet.setProxyFor(wallet.activeAccount?.address, data);
reset(data);
};