Skip to content

Commit

Permalink
Add smart rollup address support (#2036)
Browse files Browse the repository at this point in the history
  • Loading branch information
OKendigelyan authored Nov 13, 2024
1 parent 134081c commit d98b956
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 6 deletions.
3 changes: 2 additions & 1 deletion apps/desktop/src/components/AddressPill/AddressPill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const AddressPill = memo(
showIcons,
addressKind,
addressAlias,
address,
onClick,
elementRef,
isMouseHover,
Expand Down Expand Up @@ -109,7 +110,7 @@ export const AddressPill = memo(
</PopoverBody>
</PopoverContent>
</Popover>
{showIcons && (
{showIcons && address.type !== "smart_rollup" && (
<RightIcon
marginRight="4px"
stroke={colors.gray[300]}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/Operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ export const toLambda = (operation: Operation): MichelsonV1Expression[] => {
operation.recipient.pkh,
Number(operation.amount)
);
default:
throw new Error(`${operation.recipient.type} is not supported yet`);
}
// eslint-disable-next-line no-fallthrough
case "fa1.2":
Expand Down
106 changes: 106 additions & 0 deletions packages/tezos/src/Address.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
isAddressValid,
isValidContractPkh,
isValidImplicitPkh,
isValidSmartRollupPkh,
parseContractPkh,
parseImplicitPkh,
parsePkh,
parseSmartRollupPkh,
} from "./Address";
import { mockContractAddress, mockImplicitAddress, mockSmartRollupAddress } from "./testUtils";

describe("Address", () => {
const addresses = {
contract: mockContractAddress(0),
implicit: mockImplicitAddress(0),
smart_rollup: mockSmartRollupAddress(0),
};

describe("parsePkh", () => {
it.each(Object.entries(addresses))("parses %s address", (_, address) => {
expect(parsePkh(address.pkh)).toEqual(address);
});

it("throws error for invalid address", () => {
expect(() => parsePkh("invalid")).toThrow("Cannot parse address type: invalid");
});
});

describe("isAddressValid", () => {
it.each(Object.entries(addresses))("returns true for valid %s address", (_, address) => {
expect(isAddressValid(address.pkh)).toBe(true);
});

it("returns false for invalid address", () => {
expect(isAddressValid("invalid")).toBe(false);
});
});

describe("isValidContractPkh", () => {
it.each([
[true, addresses.contract.pkh],
[false, addresses.implicit.pkh],
[false, addresses.smart_rollup.pkh],
[false, "invalid"],
])("returns %s for %s address", (expected, pkh) => {
expect(isValidContractPkh(pkh)).toBe(expected);
});
});

describe("isValidImplicitPkh", () => {
it.each([
[false, addresses.contract.pkh],
[true, addresses.implicit.pkh],
[false, addresses.smart_rollup.pkh],
[false, "invalid"],
])("returns %s for %s address", (expected, pkh) => {
expect(isValidImplicitPkh(pkh)).toBe(expected);
});
});

describe("isValidSmartRollupPkh", () => {
it.each([
[false, addresses.contract.pkh],
[false, addresses.implicit.pkh],
[true, addresses.smart_rollup.pkh],
[false, "invalid"],
])("returns %s for %s address", (expected, pkh) => {
expect(isValidSmartRollupPkh(pkh)).toBe(expected);
});
});

describe("parse functions", () => {
const parseFunctions = {
parseContractPkh: {
fn: parseContractPkh,
validAddress: addresses.contract,
errorMessage: "Invalid contract address",
},
parseImplicitPkh: {
fn: parseImplicitPkh,
validAddress: addresses.implicit,
errorMessage: "Invalid implicit address",
},
parseSmartRollupPkh: {
fn: parseSmartRollupPkh,
validAddress: addresses.smart_rollup,
errorMessage: "Invalid smart rollup address",
},
};

it.each(Object.entries(parseFunctions))(
"%s parses valid address",
(_, { fn, validAddress }) => {
expect(fn(validAddress.pkh)).toEqual(validAddress);
}
);

it.each(Object.entries(parseFunctions))(
"%s throws error for invalid address",
(_, { fn, errorMessage }) => {
expect(() => fn("invalid")).toThrow(`${errorMessage}: invalid`);
}
);
});
});
24 changes: 21 additions & 3 deletions packages/tezos/src/Address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { ValidationResult, validateAddress } from "@taquito/utils";

import { type Address, type ContractAddress, type ImplicitAddress } from "./types";
import {
type Address,
type ContractAddress,
type ImplicitAddress,
type SmartRollupAddress,
} from "./types";

export const parsePkh = (pkh: string): Address => {
if (isValidContractPkh(pkh)) {
Expand All @@ -9,14 +14,20 @@ export const parsePkh = (pkh: string): Address => {
if (isValidImplicitPkh(pkh)) {
return parseImplicitPkh(pkh);
}
if (isValidSmartRollupPkh(pkh)) {
return parseSmartRollupPkh(pkh);
}
throw new Error(`Cannot parse address type: ${pkh}`);
};

export const isAddressValid = (pkh: string) => validateAddress(pkh) === ValidationResult.VALID;

export const isValidContractPkh = (pkh: string) => isAddressValid(pkh) && pkh.match(/^KT1\w+/);
export const isValidContractPkh = (pkh: string) => isAddressValid(pkh) && !!pkh.match(/^KT1\w+/);

export const isValidImplicitPkh = (pkh: string) =>
isAddressValid(pkh) && !!pkh.match(/^tz[1234]\w+/);

export const isValidImplicitPkh = (pkh: string) => isAddressValid(pkh) && pkh.match(/^tz[1234]\w+/);
export const isValidSmartRollupPkh = (pkh: string) => isAddressValid(pkh) && !!pkh.match(/^sr1\w+/);

export const parseContractPkh = (pkh: string): ContractAddress => {
if (isValidContractPkh(pkh)) {
Expand All @@ -31,3 +42,10 @@ export const parseImplicitPkh = (pkh: string): ImplicitAddress => {
}
throw new Error(`Invalid implicit address: ${pkh}`);
};

export const parseSmartRollupPkh = (pkh: string): SmartRollupAddress => {
if (isValidSmartRollupPkh(pkh)) {
return { type: "smart_rollup", pkh };
}
throw new Error(`Invalid smart rollup address: ${pkh}`);
};
9 changes: 8 additions & 1 deletion packages/tezos/src/testUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { type ContractAddress, type ImplicitAddress } from "./types";
import { type ContractAddress, type ImplicitAddress, type SmartRollupAddress } from "./types";

const validSmartRollupAddresses = ["sr1Ghq66tYK9y3r8CC1Tf8i8m5nxh8nTvZEf"];

export const mockSmartRollupAddress = (index: number): SmartRollupAddress => ({
type: "smart_rollup",
pkh: validSmartRollupAddresses[index],
});

const validContractAddresses = [
"KT1QuofAgnsWffHzLA7D78rxytJruGHDe7XG",
Expand Down
7 changes: 6 additions & 1 deletion packages/tezos/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ export type ImplicitAddress = {
pkh: RawPkh;
};

export type Address = ContractAddress | ImplicitAddress;
export type SmartRollupAddress = {
type: "smart_rollup";
pkh: RawPkh;
};

export type Address = ContractAddress | ImplicitAddress | SmartRollupAddress;

export type Estimation = {
storageLimit: number;
Expand Down

1 comment on commit d98b956

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title Lines Statements Branches Functions
apps/desktop Coverage: 84%
83.88% (1764/2103) 79.35% (838/1056) 78.45% (448/571)
apps/web Coverage: 84%
83.88% (1764/2103) 79.35% (838/1056) 78.45% (448/571)
packages/components Coverage: 97%
97.84% (182/186) 96.51% (83/86) 87.03% (47/54)
packages/core Coverage: 81%
81.91% (222/271) 71.22% (99/139) 81.96% (50/61)
packages/crypto Coverage: 100%
100% (43/43) 90.9% (10/11) 100% (7/7)
packages/data-polling Coverage: 97%
95.27% (141/148) 87.5% (21/24) 92.85% (39/42)
packages/multisig Coverage: 98%
98.47% (129/131) 85.71% (18/21) 100% (36/36)
packages/social-auth Coverage: 100%
100% (21/21) 100% (11/11) 100% (3/3)
packages/state Coverage: 85%
84.73% (805/950) 80.63% (179/222) 78.89% (299/379)
packages/tezos Coverage: 89%
88.72% (118/133) 94.59% (35/37) 86.84% (33/38)
packages/tzkt Coverage: 89%
87.32% (62/71) 87.5% (14/16) 80.48% (33/41)

Please sign in to comment.