Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: input validation #281

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/implementations/title-escrow/acceptSurrendered.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { acceptSurrendered } from "./acceptSurrendered";
jest.mock("@govtechsg/token-registry/contracts");

const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = {
tokenRegistry: "0x1122",
tokenId: "0x12345",
tokenRegistry: "0x0000000000000000000000000000000000000001",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { endorseNominatedBeneficiary } from "./endorseNominatedBeneficiary";
jest.mock("@govtechsg/token-registry/contracts");

const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = {
tokenId: "0xzyxw",
tokenRegistry: "0x1234",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
tokenRegistry: "0x0000000000000000000000000000000000000001",
newBeneficiary: "0x1232",
network: "sepolia",
dryRun: false,
Expand All @@ -25,7 +25,7 @@ describe("title-escrow", () => {
// @ts-ignore mock static method
const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect;

const mockedTitleEscrowAddress = "0x2133";
const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000002";
const mockedOwnerOf = jest.fn();
mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress);

Expand Down
26 changes: 3 additions & 23 deletions src/implementations/title-escrow/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,8 @@
import {
TitleEscrow,
TitleEscrow__factory,
TradeTrustToken,
TradeTrustToken__factory,
} from "@govtechsg/token-registry/contracts";
import { Wallet, constants } from "ethers";
import { TitleEscrow } from "@govtechsg/token-registry/contracts";
import { constants } from "ethers";
import signale from "signale";
import { ConnectedSigner } from "../utils/wallet";

interface ConnectToTitleEscrowArgs {
tokenId: string;
address: string;
wallet: Wallet | ConnectedSigner;
}

export const connectToTitleEscrow = async ({
tokenId,
address,
wallet,
}: ConnectToTitleEscrowArgs): Promise<TitleEscrow> => {
const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet);
const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId);
return await TitleEscrow__factory.connect(titleEscrowAddress, wallet);
};
export { connectToTitleEscrow, connectToTitleEscrowAddress } from "../utils/connect";

interface validateEndorseChangeOwnerArgs {
newHolder: string;
Expand Down
6 changes: 3 additions & 3 deletions src/implementations/title-escrow/nominateBeneficiary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ jest.mock("@govtechsg/token-registry/contracts");

const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = {
newBeneficiary: "0fosui",
tokenId: "0xzyxw",
tokenRegistry: "0x1234",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
tokenRegistry: "0x0000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand All @@ -26,7 +26,7 @@ describe("title-escrow", () => {
const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect;
const mockedOwnerOf = jest.fn();
const mockNominateBeneficiary = jest.fn();
const mockedTitleEscrowAddress = "0x2133";
const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000002";
const mockedBeneficiary = "0xdssfs";
const mockedHolder = "0xdsfls";
const mockGetBeneficiary = jest.fn();
Expand Down
6 changes: 3 additions & 3 deletions src/implementations/title-escrow/rejectSurrendered.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { rejectSurrendered } from "./rejectSurrendered";
jest.mock("@govtechsg/token-registry/contracts");

const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = {
tokenRegistry: "0x1122",
tokenId: "0x12345",
tokenRegistry: "0x0000000000000000000000000000000000000001",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand Down Expand Up @@ -49,7 +49,7 @@ describe("title-escrow", () => {
wait: () => Promise.resolve({ transactionHash: "transactionHash" }),
});
mockTransferEvent.mockReturnValue({
address: "0x1122",
address: "0x0000000000000000000000000000000000000002",
topics: ["0x00000", null, null, "0x12345"],
});
mockQueryFilter.mockReturnValue([
Expand Down
5 changes: 3 additions & 2 deletions src/implementations/title-escrow/rejectSurrendered.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts";
import { TradeTrustToken } from "@govtechsg/token-registry/contracts";
import signale from "signale";
import { getLogger } from "../../logger";
import { getWalletOrSigner } from "../utils/wallet";
import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type";
import { dryRunMode } from "../utils/dryRun";
import { TransactionReceipt } from "@ethersproject/providers";
import { connectToTokenRegistry } from "../utils/connect";

const { trace } = getLogger("title-escrow:acceptSurrendered");

Expand All @@ -16,7 +17,7 @@ export const rejectSurrendered = async ({
...rest
}: TitleEscrowSurrenderDocumentCommand): Promise<TransactionReceipt> => {
const wallet = await getWalletOrSigner({ network, ...rest });
const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet);
const tokenRegistryInstance: TradeTrustToken = await connectToTokenRegistry(address, wallet);
if (dryRun) {
await dryRunMode({
estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId),
Expand Down
6 changes: 3 additions & 3 deletions src/implementations/title-escrow/surrenderDocument.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { surrenderDocument } from "./surrenderDocument";
jest.mock("@govtechsg/token-registry/contracts");

const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = {
tokenRegistry: "0x1122",
tokenId: "0x12345",
tokenRegistry: "0x0000000000000000000000000000000000000001",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand All @@ -26,7 +26,7 @@ describe("title-escrow", () => {
const mockedOwnerOf = jest.fn();
const mockSurrender = jest.fn();
const mockCallStaticSurrender = jest.fn().mockResolvedValue(undefined);
const mockedTitleEscrowAddress = "0x2133";
const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000002";

beforeEach(() => {
delete process.env.OA_PRIVATE_KEY;
Expand Down
6 changes: 3 additions & 3 deletions src/implementations/title-escrow/transferHolder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ jest.mock("@govtechsg/token-registry/contracts");

const transferHolderParams: TitleEscrowTransferHolderCommand = {
newHolder: "0xabcd",
tokenId: "0xzyxw",
tokenRegistry: "0x1234",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
tokenRegistry: "0x0000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand All @@ -28,7 +28,7 @@ describe("title-escrow", () => {
const mockedOwnerOf = jest.fn();
const mockTransferHolder = jest.fn();
const mockCallStaticTransferHolder = jest.fn().mockResolvedValue(undefined);
const mockedTitleEscrowAddress = "0x2133";
const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000002";
mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress);
mockTransferHolder.mockReturnValue({
hash: "hash",
Expand Down
6 changes: 3 additions & 3 deletions src/implementations/title-escrow/transferOwners.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ jest.mock("@govtechsg/token-registry/contracts");
const endorseChangeOwnersParams: TitleEscrowEndorseTransferOfOwnersCommand = {
newHolder: "0xabcd",
newOwner: "0fosui",
tokenId: "0xzyxw",
tokenRegistry: "0x1234",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
tokenRegistry: "0x0000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand All @@ -29,7 +29,7 @@ describe("title-escrow", () => {
const mockedOwnerOf = jest.fn();
const mockTransferOwners = jest.fn();
const mockCallStaticTransferOwners = jest.fn().mockResolvedValue(undefined);
const mockedTitleEscrowAddress = "0x2133";
const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000002";
const mockedBeneficiary = "0xdssfs";
const mockedHolder = "0xdsfls";
const mockGetBeneficiary = jest.fn();
Expand Down
4 changes: 2 additions & 2 deletions src/implementations/token-registry/issue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ jest.mock("@govtechsg/token-registry/contracts");
const deployParams: TokenRegistryIssueCommand = {
beneficiary: "0xabcd",
holder: "0xabce",
tokenId: "0xzyxw",
address: "0x1234",
tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001",
address: "0x0000000000000000000000000000000000000001",
network: "sepolia",
dryRun: false,
};
Expand Down
5 changes: 3 additions & 2 deletions src/implementations/token-registry/issue.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts";
import { TradeTrustToken } from "@govtechsg/token-registry/contracts";
import signale from "signale";
import { getLogger } from "../../logger";
import { getWalletOrSigner } from "../utils/wallet";
import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type";
import { dryRunMode } from "../utils/dryRun";
import { TransactionReceipt } from "@ethersproject/providers";
import { connectToTokenRegistry } from "../utils/connect";

const { trace } = getLogger("token-registry:issue");

Expand All @@ -18,7 +19,7 @@ export const issueToTokenRegistry = async ({
...rest
}: TokenRegistryIssueCommand): Promise<TransactionReceipt> => {
const wallet = await getWalletOrSigner({ network, ...rest });
const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet);
const tokenRegistry: TradeTrustToken = await connectToTokenRegistry(address, wallet);

if (dryRun) {
await dryRunMode({
Expand Down
54 changes: 54 additions & 0 deletions src/implementations/utils/connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
TradeTrustToken,
TradeTrustToken__factory,
TitleEscrow,
TitleEscrow__factory,
} from "@govtechsg/token-registry/contracts";
import { Wallet } from "ethers";
import { isAddress } from "ethers/lib/utils";
import { ConnectedSigner } from "../utils/wallet";

type UserWallet = Wallet | ConnectedSigner;

export const connectToTokenRegistry = async (address: string, wallet: UserWallet): Promise<TradeTrustToken> => {
const validAddress = isAddress(address);
if (!validAddress) throw new Error(`Invalid token registry address: ${address}`);
const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet);
return tokenRegistryInstance;
};

const addressCheck = (maybeAddress: string): void => {
if (!isAddress(maybeAddress)) throw new Error(`Invalid contract address: ${maybeAddress}`);
};

const tokenIdCheck = (maybeTokenId: string): void => {
const validHex = /^(0x|0X)?[a-fA-F0-9]+$/.test(maybeTokenId);
if (!validHex) throw new Error(`Invalid token id: ${maybeTokenId}`);
};

interface ConnectToTitleEscrowArgs {
tokenId: string;
address: string;
wallet: Wallet | ConnectedSigner;
}

export const connectToTitleEscrow = async ({
tokenId,
address,
wallet,
}: ConnectToTitleEscrowArgs): Promise<TitleEscrow> => {
const tokenRegistry: TradeTrustToken = await connectToTokenRegistry(address, wallet);
const titleEscrowAddress = await getTitleEscrowAddress(tokenRegistry, tokenId);
return await connectToTitleEscrowAddress(titleEscrowAddress, wallet);
};

export const connectToTitleEscrowAddress = async (address: string, wallet: UserWallet): Promise<TitleEscrow> => {
addressCheck(address);
const titleEscrow = TitleEscrow__factory.connect(address, wallet);
return titleEscrow;
};

const getTitleEscrowAddress = async (tokenRegistry: TradeTrustToken, tokenId: string): Promise<string> => {
tokenIdCheck(tokenId);
return await tokenRegistry.ownerOf(tokenId);
};