Skip to content

Commit

Permalink
update ether formatting and url sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
iainnash committed Dec 21, 2023
1 parent f3d77c0 commit 6634890
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 79 deletions.
99 changes: 21 additions & 78 deletions src/app/NewSafeProposal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,27 @@ import {
useEffect,
useState,
} from "react";
import { Address, Hex } from "viem";
import { validateAddress, validateETH, yupAddress } from "../utils/validators";
import { Address, Hex, formatEther } from "viem";
import { validateAddress, validateETH } from "../utils/validators";
import { GenericField } from "../components/GenericField";
import { useSearchParams } from "react-router-dom";
import { InferType, array, number, object, string } from "yup";
import { DataActionPreview } from "../components/DataActionPreview";
import Safe, { EthersAdapter } from "@safe-global/protocol-kit";
import { WalletProviderContext } from "./Root";
import { ethers } from "ethers";
import { contractNetworks } from "../chains";
import { SafeInformationContext } from "./ViewSafe";
import {
DEFAULT_ACTION_ITEM,
DEFAULT_PROPOSAL,
Proposal,
proposalSchema,
} from "../schemas/proposal";
import { useSetParamsFromQuery } from "../hooks/useSetParamsFromQuery";
import { useLoadProposalFromQuery } from "../hooks/useLoadProposalFromQuery";
import {
transformValuesFromWei,
transformValuesToWei,
} from "../utils/etherFormatting";

const FormActionItem = ({
name,
Expand Down Expand Up @@ -51,44 +61,6 @@ const FormActionItem = ({
);
};

const proposalSchema = object({
nonce: number().nullable(),
actions: array(
object({
to: yupAddress,
value: string()
.default("0")
.matches(
/^[0-9]+(\.[0-9]+)?$/,
"Needs to be a ETH price (0, 1, or 0.23)"
)
.required(),
data: string()
.default("0x")
.matches(
/^0x(?:[0-9A-Za-z][0-9A-Za-z])*$/,
"Data is required to match hex format"
)
.required(),
})
),
});

interface Proposal extends InferType<typeof proposalSchema> {
// using interface instead of type generally gives nicer editor feedback
}

const DEFAULT_ACTION_ITEM = {
to: "0x",
value: "0",
data: "0x",
};

const DEFAULT_PROPOSAL = {
nonce: null,
actions: [DEFAULT_ACTION_ITEM],
};

const createSafeAdapter = async ({
provider,
safeAddress,
Expand Down Expand Up @@ -194,37 +166,6 @@ const useSafe = ({
return safe;
};

const useLoadProposalFromQuery = () => {
const [proposal, setProposal] = useState<undefined | Proposal>();
const [params] = useSearchParams();

useEffect(() => {
const targets = params.get("targets")?.split("|");
const calldatas = params.get("calldatas")?.split("|");
const values = params.get("values")?.split("|");
if (targets && calldatas) {
// ensure the 3 lengths are the same. check if values also has the same length if its not empty
// check the inverse of the above, if inverse is true, return:
if (
targets.length !== calldatas.length ||
(values?.length && values?.length !== targets.length)
) {
console.log("invalid lengths");
return;
}

const actions = targets.map((target, index) => ({
to: target,
data: calldatas[index]!,
value: (values && values[index]) || "0",
}));
setProposal({ actions });
}
}, [params, setProposal]);

return proposal;
};

const useGetSafeTxApprovals = ({ proposal }: { proposal: Proposal }) => {
const safeInformation = useContext(SafeInformationContext);

Expand All @@ -235,7 +176,6 @@ const useGetSafeTxApprovals = ({ proposal }: { proposal: Proposal }) => {

const loadApprovers = useCallback(async () => {
if (!safeSdk || !safeSdk2) return;
// const { safeSdk, safeSdk2 } = await getSafeSDK(safeAddress);
const txn = await createSafeTransaction({
proposal,
safe: safeSdk,
Expand Down Expand Up @@ -380,7 +320,7 @@ const ViewProposal = ({
<>
<View.Item>Proposal #{indx}</View.Item>
<View.Item>To: {action.to as Address}</View.Item>
<View.Item>Value: {action.value}</View.Item>
<View.Item>Value: {formatEther(BigInt(action.value))}</View.Item>
{action.data ? (
<>
<View.Item>Data: {action.data}</View.Item>
Expand Down Expand Up @@ -433,10 +373,13 @@ const EditProposal = ({
setProposal: (result: Proposal) => void;
setIsEditing: (editing: boolean) => void;
}) => {
const setProposalParams = useSetParamsFromQuery();
const onSubmit = useCallback(
(result: Proposal) => {
setProposal(result);
// setParams({ proposal: JSON.stringify(result) });
setProposal(transformValuesToWei(result));
if (proposal) {
setProposalParams(proposal);
}
setIsEditing(false);
},
[setIsEditing, setProposal]
Expand All @@ -449,7 +392,7 @@ const EditProposal = ({
<Card>
<Formik
validationSchema={proposalSchema}
initialValues={defaultActions}
initialValues={transformValuesFromWei(defaultActions)}
onSubmit={onSubmit}
>
{({ handleSubmit, values, isValid }) => (
Expand Down
1 change: 0 additions & 1 deletion src/components/GenericField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const GenericField = ({
}) => {
return ({ field: { name, value, onChange }, form: { errors } }: any) => {
const error = get(errors, name);
// console.log({ error, errors, value, name });

return (
<View paddingTop={1} paddingBottom={1}>
Expand Down
34 changes: 34 additions & 0 deletions src/hooks/useLoadProposalFromQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { Proposal } from "../schemas/proposal";

export const useLoadProposalFromQuery = () => {
const [proposal, setProposal] = useState<undefined | Proposal>();
const [params] = useSearchParams();

useEffect(() => {
const targets = params.get("targets")?.split("|");
const calldatas = params.get("calldatas")?.split("|");
const values = params.get("values")?.split("|");
if (targets && calldatas) {
// ensure the 3 lengths are the same. check if values also has the same length if its not empty
// check the inverse of the above, if inverse is true, return:
if (
targets.length !== calldatas.length ||
(values?.length && values?.length !== targets.length)
) {
console.log("invalid lengths");
return;
}

const actions = targets.map((target, index) => ({
to: target,
data: calldatas[index]!,
value: (values && values[index]) || "0",
}));
setProposal({ actions });
}
}, [params, setProposal]);

return proposal;
};
19 changes: 19 additions & 0 deletions src/hooks/useSetParamsFromQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useCallback } from "react";
import { useSearchParams } from "react-router-dom";
import { Proposal } from "../schemas/proposal";

export const useSetParamsFromQuery = () => {
const [_, setParams] = useSearchParams();

return useCallback((proposal: Proposal) => {
if (!proposal.actions?.length) {
return;
}
console.log('setting params', proposal.actions);
setParams({
targets: proposal.actions!.map((action) => action.to).join('|'),
data: proposal.actions!.map((action) => action.data).join('|'),
value: proposal.actions!.map((action) => action.value).join('|'),
})
}, [setParams]);
}
40 changes: 40 additions & 0 deletions src/schemas/proposal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { InferType, array, number, object, string } from "yup";
import { yupAddress } from "../utils/validators";

export const proposalSchema = object({
nonce: number().nullable(),
actions: array(
object({
to: yupAddress,
value: string()
.default("0")
.matches(
/^[0-9]+(\.[0-9]+)?$/,
"Needs to be a ETH price (0, 1, or 0.23)"
)
.required(),
data: string()
.default("0x")
.matches(
/^0x(?:[0-9A-Za-z][0-9A-Za-z])*$/,
"Data is required to match hex format"
)
.required(),
})
),
});

export interface Proposal extends InferType<typeof proposalSchema> {
// using interface instead of type generally gives nicer editor feedback
}

export const DEFAULT_ACTION_ITEM = {
to: "0x",
value: "0",
data: "0x",
};

export const DEFAULT_PROPOSAL = {
nonce: null,
actions: [DEFAULT_ACTION_ITEM],
};
22 changes: 22 additions & 0 deletions src/utils/etherFormatting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { formatEther, parseEther } from "viem";
import { Proposal } from "../schemas/proposal";

export function transformValuesToWei(proposal: Proposal): Proposal {
return {
...proposal,
actions: proposal.actions?.map((action) => ({
...action,
value: parseEther(action.value).toString(),
})),
};
}

export function transformValuesFromWei(proposal: Proposal): Proposal {
return {
...proposal,
actions: proposal.actions?.map((action) => ({
...action,
value: formatEther(BigInt(action.value)),
})),
};
}

0 comments on commit 6634890

Please sign in to comment.