Add create multisig form schema
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import { ChainInfo } from "@/context/ChainsContext/types";
|
||||
import { pubkeyToAddress } from "@cosmjs/amino";
|
||||
import { StargateClient } from "@cosmjs/stargate";
|
||||
import { z } from "zod";
|
||||
import { checkAddressOrPubkey } from "../../../lib/displayHelpers";
|
||||
|
||||
export const getCreateMultisigSchema = (chain: ChainInfo) =>
|
||||
z
|
||||
.object({
|
||||
members: z.array(
|
||||
z.object({
|
||||
member: z
|
||||
.string()
|
||||
.trim()
|
||||
.superRefine(async (member, ctx) => {
|
||||
if (!member) {
|
||||
return z.NEVER;
|
||||
}
|
||||
|
||||
const addressOrPubkeyError = checkAddressOrPubkey(member, chain.addressPrefix);
|
||||
|
||||
if (addressOrPubkeyError) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: addressOrPubkeyError });
|
||||
} else {
|
||||
try {
|
||||
const address = member.startsWith(chain.addressPrefix)
|
||||
? member
|
||||
: pubkeyToAddress(
|
||||
{ type: "tendermint/PubKeySecp256k1", value: member },
|
||||
chain.addressPrefix,
|
||||
);
|
||||
|
||||
const client = await StargateClient.connect(chain.nodeAddress);
|
||||
const accountOnChain = await client.getAccount(address);
|
||||
|
||||
if (!accountOnChain || !accountOnChain.pubkey) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "This account needs to send a transaction to appear on chain",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
return z.NEVER;
|
||||
}
|
||||
}
|
||||
}),
|
||||
}),
|
||||
),
|
||||
threshold: z.coerce
|
||||
.number({ invalid_type_error: "Threshold must be a number" })
|
||||
.int("Threshold can't have decimals")
|
||||
.min(1, "Threshold must be at least 1"),
|
||||
})
|
||||
.superRefine(({ members }, ctx) => {
|
||||
if (members.length !== 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const firstEmptyMemberIndex = members.findIndex(({ member }) => member.trim() === "");
|
||||
|
||||
if (firstEmptyMemberIndex !== -1) {
|
||||
const issue = {
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "At least 2 members needed",
|
||||
path: [`members.${firstEmptyMemberIndex}.member`],
|
||||
};
|
||||
|
||||
ctx.addIssue(issue);
|
||||
}
|
||||
})
|
||||
.superRefine(({ members }, ctx) => {
|
||||
const addresses = members.map(({ member }) => {
|
||||
if (!member.startsWith(chain.addressPrefix)) {
|
||||
try {
|
||||
const address = pubkeyToAddress(
|
||||
{ type: "tendermint/PubKeySecp256k1", value: member },
|
||||
chain.addressPrefix,
|
||||
);
|
||||
|
||||
return address;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return member;
|
||||
});
|
||||
|
||||
const dupedAddresses = addresses.filter((member, i) => addresses.indexOf(member) !== i);
|
||||
|
||||
const dupedAddressesIndexes: number[][] = [];
|
||||
|
||||
for (const dupedAddress of dupedAddresses) {
|
||||
const dupedIndexes = [];
|
||||
|
||||
for (let i = 0; i < addresses.length; ++i) {
|
||||
const index = addresses.indexOf(dupedAddress, i);
|
||||
if (index !== -1) {
|
||||
dupedIndexes.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
dupedAddressesIndexes.push(dupedIndexes.sort());
|
||||
}
|
||||
|
||||
if (dupedAddressesIndexes.length) {
|
||||
for (const dupedIndexes of dupedAddressesIndexes) {
|
||||
for (const duplicateIndex of dupedIndexes) {
|
||||
const issue = {
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Members cannot be duplicate (${dupedIndexes
|
||||
.map((index) => `#${index + 1}`)
|
||||
.join(", ")})`,
|
||||
path: [`members.${duplicateIndex}.member`],
|
||||
};
|
||||
|
||||
ctx.addIssue(issue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return z.NEVER;
|
||||
}
|
||||
})
|
||||
.refine(
|
||||
({ members, threshold }) => threshold <= members.filter(({ member }) => member !== "").length,
|
||||
({ members }) => ({
|
||||
message: `Threshold can't be higher than the number of members (${
|
||||
members.filter(({ member }) => member !== "").length
|
||||
})`,
|
||||
path: ["threshold"],
|
||||
}),
|
||||
);
|
||||
Reference in New Issue
Block a user