Skip to content

Commit

Permalink
User selectable network (#72)
Browse files Browse the repository at this point in the history
* Additional checks when transferring

* remove empty line

* Selecting network

* fix

* fixes

* working :)

* update contract metadata

* fully working

* change function signatures

* list all chains on share identity

* update identityKey format to contain info about network

* identityKey works, transfer doesnt

* fixes
  • Loading branch information
Szegoo authored Oct 24, 2023
1 parent 67af4bd commit 6c3b68a
Show file tree
Hide file tree
Showing 33 changed files with 829 additions and 479 deletions.
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
CONTRACT_IDENTITY="AddressOfIdentityContract"
CONTRACT_ADDRESS_BOOK="AddressOfAddressBookContract"
RELAY_CHAIN="kusama_or_polkadot"
CONTRACT_ADDRESS_BOOK="AddressOfAddressBookContract"
37 changes: 17 additions & 20 deletions __tests__/identityKey.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@ describe("IdentityKey", () => {
let identityKey = "";

const polkadotChainId = 0;
identityKey = IdentityKey.newCipher(identityKey, polkadotChainId);
identityKey = IdentityKey.newCipher(identityKey, polkadotChainId, "polkadot");

containsChainAndCipher(identityKey, polkadotChainId);

const moonbeamChainId = 1;
// Generate a new cipher for the Moonbeam chain.
identityKey = IdentityKey.newCipher(identityKey, moonbeamChainId);
identityKey = IdentityKey.newCipher(identityKey, moonbeamChainId, "polkadot");

// The identity Key should still have the Polkadot cipher.
containsChainAndCipher(identityKey, polkadotChainId);

containsChainAndCipher(identityKey, moonbeamChainId);

// Ciphers are randomly generated so the two ciphers cannot be the same.
const polkadotCipher = IdentityKey.getChainCipher(identityKey, polkadotChainId);
const moonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId);
const polkadotCipher = IdentityKey.getChainCipher(identityKey, polkadotChainId, "polkadot");
const moonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId, "polkadot");

expect(polkadotCipher).not.toBe(moonbeamCipher);

// Cannot create a new Cipher for the same chain twice.
expect(() => IdentityKey.newCipher(identityKey, moonbeamChainId))
expect(() => IdentityKey.newCipher(identityKey, moonbeamChainId, "polkadot"))
.toThrow("There already exists a cipher that is attached to the provided chainId");
});

Expand All @@ -37,49 +37,46 @@ describe("IdentityKey", () => {
const polkadotChainId = 0;
const moonbeamChainId = 1;

identityKey = IdentityKey.newCipher(identityKey, polkadotChainId);
identityKey = IdentityKey.newCipher(identityKey, moonbeamChainId);
identityKey = IdentityKey.newCipher(identityKey, polkadotChainId, "polkadot");
identityKey = IdentityKey.newCipher(identityKey, moonbeamChainId, "polkadot");

containsChainAndCipher(identityKey, polkadotChainId);
containsChainAndCipher(identityKey, moonbeamChainId);

const polkadotCipher = IdentityKey.getChainCipher(identityKey, polkadotChainId);
const moonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId);
const polkadotCipher = IdentityKey.getChainCipher(identityKey, polkadotChainId, "polkadot");
const moonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId, "polkadot");

identityKey = IdentityKey.updateCipher(identityKey, moonbeamChainId);
const newMoonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId);
identityKey = IdentityKey.updateCipher(identityKey, moonbeamChainId, "polkadot");
const newMoonbeamCipher = IdentityKey.getChainCipher(identityKey, moonbeamChainId, "polkadot");

// The moonbeam chain cipher should be updated.
expect(moonbeamCipher).not.toBe(newMoonbeamCipher);

// The polkadot cipher shouldn't be affected.
expect(IdentityKey.getChainCipher(identityKey, polkadotChainId)).toBe(polkadotCipher);

// Cannot update a cipher of a chain that does not exist.
expect(() => IdentityKey.updateCipher(identityKey, 42)).toThrow("Cannot find chainId");
expect(IdentityKey.getChainCipher(identityKey, polkadotChainId, "polkadot")).toBe(polkadotCipher);
});

test("Encryption and decryption works", () => {
let identityKey = "";

const polkadotChainId = 0;
identityKey = IdentityKey.newCipher(identityKey, polkadotChainId);
identityKey = IdentityKey.newCipher(identityKey, polkadotChainId, "polkadot");

containsChainAndCipher(identityKey, polkadotChainId);

const polkadotAddress = "126X27SbhrV19mBFawys3ovkyBS87SGfYwtwa8J2FjHrtbmA";
const encryptedAddress = IdentityKey.encryptAddress(identityKey, polkadotChainId, polkadotAddress);
const decryptedAddress = IdentityKey.decryptAddress(identityKey, polkadotChainId, encryptedAddress);
const encryptedAddress = IdentityKey.encryptAddress(identityKey, polkadotChainId, polkadotAddress, "polkadot");
const decryptedAddress = IdentityKey.decryptAddress(identityKey, polkadotChainId, encryptedAddress, "polkadot");

expect(polkadotAddress).toBe(decryptedAddress);
});
});

const containsChainAndCipher = (identityKey: string, chainId: number) => {
const containsChain = new RegExp(`\\b${chainId}:`, "g");
const containsChain = new RegExp(`\\bpolkadot${chainId}:`, "g");
expect(containsChain.test(identityKey)).toBe(true);

const chainCipher = IdentityKey.getChainCipher(identityKey, chainId);
const chainCipher = IdentityKey.getChainCipher(identityKey, chainId, "polkadot");
expect(cipherSize(chainCipher)).toBe(16);
}

Expand Down
40 changes: 26 additions & 14 deletions chaindata/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { RELAY_CHAIN } from "@/consts";
import { gql, request } from "graphql-request"

const graphqlUrl = "https://squid.subsquid.io/chaindata/v/v4/graphql"
Expand Down Expand Up @@ -71,37 +70,50 @@ query ChainByParaIdAndRelay($relayId: String!) {
`;

const tokensQuery = gql`
query tokens {
tokens(orderBy: id_ASC) {
query tokens($relayId: String!) {
tokens(orderBy: id_ASC, where: {squidImplementationDetailChain: {relay: {id_eq: $relayId}}}) {
data
}
}
`;

export class Chaindata {
private tokens: Array<Token> = [];

public async load(): Promise<void> {
const tokensResult: any = await request(graphqlUrl, tokensQuery);
this.tokens = tokensResult.tokens;
const relayTokensQuery = gql`
query tokens {
tokens(orderBy: id_ASC, where: {squidImplementationDetailChain: {relay_isNull: true}}) {
data
}
}
`;

public async getChain(chainId: number): Promise<Chain> {
export class Chaindata {
public async getChain(chainId: number, relay: string): Promise<Chain> {
if (chainId === 0) {
const result: any = await request(graphqlUrl, relayQuery, {
relayId: RELAY_CHAIN
relayId: relay
});
return result.chains[0];
} else {
const result: any = await request(graphqlUrl, chainQuery, {
paraId: chainId,
relayId: RELAY_CHAIN
relayId: relay
});
return result.chains[0];
}
}

public getTokens(): Array<Token> {
return this.tokens;
public async getTokens(relay: string | null): Promise<Array<Token>> {
if (relay === null) {
const tokensResult: any = await request(graphqlUrl, relayTokensQuery, {
relayId: relay
});

return tokensResult.tokens;
} else {
const tokensResult: any = await request(graphqlUrl, tokensQuery, {
relayId: relay
});

return tokensResult.tokens;
}
}
}
9 changes: 6 additions & 3 deletions src/components/Cards/AddressCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { clipAddress } from '@/utils';
import IdentityKey from '@/utils/identityKey';
import KeyStore from '@/utils/keyStore';

import { useRelay } from '@/contexts/RelayApi';
import { useToast } from '@/contexts/Toast';
import { useIdentity } from '@/contracts';
import { Address, ChainId } from '@/contracts/types';
Expand All @@ -37,6 +38,7 @@ export const AddressCard = ({ data, onEdit }: AddressCardProps) => {
const { api, activeAccount } = useInkathon();
const { toastSuccess, toastError } = useToast();
const { identityNo, chains, contract, fetchAddresses } = useIdentity();
const { relay } = useRelay();

const [working, setWorking] = useState(false);

Expand All @@ -57,7 +59,7 @@ export const AddressCard = ({ data, onEdit }: AddressCardProps) => {
contract,
'remove_address',
{},
[chainId]
[[chainId, relay]]
);

toastSuccess('Address is removed successfully.');
Expand All @@ -82,11 +84,12 @@ export const AddressCard = ({ data, onEdit }: AddressCardProps) => {
const identityKey = KeyStore.readIdentityKey(identityNo) || '';

let decryptedAddress = address;
if (IdentityKey.containsChainId(identityKey, chainId)) {
if (IdentityKey.containsChainId(identityKey, chainId, relay)) {
decryptedAddress = IdentityKey.decryptAddress(
identityKey,
chainId,
address
address,
relay,
);

return {
Expand Down
12 changes: 8 additions & 4 deletions src/components/Modals/AddAddress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import {
import { contractTx, useInkathon } from '@scio-labs/use-inkathon';
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { Network } from 'types/types-arguments/identity';

import { isValidAddress } from '@/utils';
import IdentityKey from '@/utils/identityKey';
import KeyStore from '@/utils/keyStore';

import { useRelay } from '@/contexts/RelayApi';
import { useToast } from '@/contexts/Toast';
import { useIdentity } from '@/contracts';
import { ChainId } from '@/contracts/types';
Expand All @@ -39,6 +41,7 @@ export const AddAddressModal = ({ open, onClose }: AddAddressModalProps) => {
const [chainId, setChainId] = useState<ChainId | undefined>();
const [chainAddress, setChainAddress] = useState<string | undefined>();
const [working, setWorking] = useState(false);
const { relay } = useRelay();

const onSubmit = async () => {
if (identityNo === null) {
Expand Down Expand Up @@ -69,15 +72,16 @@ export const AddAddressModal = ({ open, onClose }: AddAddressModalProps) => {

let identityKey = KeyStore.readIdentityKey(identityNo) || '';

if (!IdentityKey.containsChainId(identityKey, chainId)) {
identityKey = IdentityKey.newCipher(identityKey, chainId);
if (!IdentityKey.containsChainId(identityKey, chainId, relay)) {
identityKey = IdentityKey.newCipher(identityKey, chainId, relay);
KeyStore.updateIdentityKey(identityNo, identityKey);
}

const encryptedAddress = IdentityKey.encryptAddress(
identityKey,
chainId,
chainAddress
chainAddress,
relay
);

try {
Expand All @@ -87,7 +91,7 @@ export const AddAddressModal = ({ open, onClose }: AddAddressModalProps) => {
contract,
'add_address',
{},
[chainId, encryptedAddress]
[[chainId, relay === "polkadot" ? Network.polkadot : Network.kusama], encryptedAddress]
);

toastSuccess('Successfully added your address.');
Expand Down
29 changes: 8 additions & 21 deletions src/components/Modals/AddIdentity/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export const AddIdentityModal = ({ open, onClose }: AddIdentityModalProps) => {
const { contract, fetchIdentities } = useAddressBook();
const { toastError, toastSuccess } = useToast();

const [identityNo, setIdentityNo] = useState<number | undefined>();
const [identityKey, setIdentityKey] = useState<string | undefined>();
const [nickname, setNickname] = useState<string | undefined>();
const [working, setWorking] = useState(false);
Expand All @@ -40,8 +39,11 @@ export const AddIdentityModal = ({ open, onClose }: AddIdentityModalProps) => {
toastError('Please input identity key.');
return;
}
if (identityNo === undefined) {
toastError('Please input identity no.');
const firstColonIndex = identityKey.indexOf(':');
const firstSemicolonIndex = identityKey.indexOf(';');
const identityNo = Number(identityKey.substring(firstColonIndex + 1, firstSemicolonIndex));
if (Number.isNaN(identityNo)) {
toastError("Invalid identity key.");
return;
}
if (identityNo === myIdentity) {
Expand Down Expand Up @@ -75,10 +77,9 @@ export const AddIdentityModal = ({ open, onClose }: AddIdentityModalProps) => {
onClose();
} catch (e: any) {
toastError(
`Failed to add identity. Error: ${
e.errorMessage === 'Error'
? 'Please check your balance.'
: e.errorMessage
`Failed to add identity. Error: ${e.errorMessage === 'Error'
? 'Please check your balance.'
: e.errorMessage
}`
);
setWorking(false);
Expand All @@ -89,7 +90,6 @@ export const AddIdentityModal = ({ open, onClose }: AddIdentityModalProps) => {
setNickname(undefined);
setWorking(false);
setIdentityKey(undefined);
setIdentityNo(undefined);
}, [open]);

return (
Expand Down Expand Up @@ -121,19 +121,6 @@ export const AddIdentityModal = ({ open, onClose }: AddIdentityModalProps) => {
<span>{`${(nickname || '').length}/16`}</span>
</FormHelperText>
</FormControl>
<FormControl className='form-item'>
<FormLabel>Identity No</FormLabel>
<TextField
placeholder='Enter identity no'
type='number'
required
value={identityNo}
onChange={(e) => {
const value = Number(e.target.value);
value >= 0 && setIdentityNo(value);
}}
/>
</FormControl>
<FormControl className='form-item'>
<FormLabel>Identity Key</FormLabel>
<TextField
Expand Down
14 changes: 9 additions & 5 deletions src/components/Modals/EditAddress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import {
} from '@mui/material';
import { contractTx, useInkathon } from '@scio-labs/use-inkathon';
import { useEffect, useState } from 'react';
import { Network } from 'types/types-arguments/identity';

import { isValidAddress } from '@/utils';
import IdentityKey from '@/utils/identityKey';
import KeyStore from '@/utils/keyStore';

import { useRelay } from '@/contexts/RelayApi';
import { useToast } from '@/contexts/Toast';
import { useIdentity } from '@/contracts';
import { ChainId } from '@/contracts/types';
Expand All @@ -39,6 +41,7 @@ export const EditAddressModal = ({
const [newAddress, setNewAddress] = useState<string>('');
const [working, setWorking] = useState(false);
const [regenerate, setRegenerate] = useState(false);
const { relay } = useRelay();

const onSave = async () => {
if (identityNo === null) {
Expand Down Expand Up @@ -69,18 +72,19 @@ export const EditAddressModal = ({

let identityKey = KeyStore.readIdentityKey(identityNo) || '';

if (!IdentityKey.containsChainId(identityKey, chainId)) {
identityKey = IdentityKey.newCipher(identityKey, chainId);
if (!IdentityKey.containsChainId(identityKey, chainId, relay)) {
identityKey = IdentityKey.newCipher(identityKey, chainId, relay);
KeyStore.updateIdentityKey(identityNo, identityKey);
}

if (regenerate)
identityKey = IdentityKey.updateCipher(identityKey, chainId);
identityKey = IdentityKey.updateCipher(identityKey, chainId, relay);

const encryptedAddress = IdentityKey.encryptAddress(
identityKey,
chainId,
newAddress
newAddress,
relay
);

try {
Expand All @@ -90,7 +94,7 @@ export const EditAddressModal = ({
contract,
'update_address',
{},
[chainId, encryptedAddress]
[[chainId, relay === "polkadot" ? Network.polkadot : Network.kusama], encryptedAddress]
);
// Update the identity key when the user has updated his on-chain data
KeyStore.updateIdentityKey(identityNo, identityKey);
Expand Down
Loading

0 comments on commit 6c3b68a

Please sign in to comment.