Skip to content

Commit

Permalink
Merge pull request #119 from blockful-io/87-add-more-address-types
Browse files Browse the repository at this point in the history
feat: add more address types
  • Loading branch information
lgahdl authored Aug 8, 2024
2 parents a376b02 + db3e6af commit 76cf4b4
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 263 deletions.
102 changes: 97 additions & 5 deletions components/02-molecules/edit/FieldsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isAddress } from "viem";
import _ from "lodash";
import { ResolvedEnsData, TextRecords } from "@/lib/utils/ensData";
import { DecodedAddr } from "@ensdomains/ensjs/dist/types/types";
import validateBitcoinAddress from "bitcoin-address-validation";

interface FieldsContextType {
profileFields: Field[];
Expand Down Expand Up @@ -185,14 +186,59 @@ const FieldsProvider: React.FC<FieldsProviderProps> = ({ children }) => {
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);

return fieldIsEmpty || isValidAddress;
},
} as Field,
{
label: "btc",
placeholder: "bc1000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> =
typeof fieldValue === "string" && !!isAddress(fieldValue);
!!validateBitcoinAddress(fieldValue);

return fieldIsEmpty || isValidAddress;
},
} as Field,
{
label: "arb1",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
{
label: "opt",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
{
label: "matic",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
]);

// INITIAL ADDRESS STATE
Expand All @@ -206,12 +252,56 @@ const FieldsProvider: React.FC<FieldsProviderProps> = ({ children }) => {
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: boolean = fieldValue === "";
const isAddressValid: boolean =
typeof fieldValue === "string" && !!isAddress(fieldValue);
const isAddressValid: boolean = !!isAddress(fieldValue);

return fieldIsEmpty || isAddressValid;
},
} as Field,
},
{
label: "btc",
placeholder: "bc1000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> =
!!validateBitcoinAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
{
label: "arb1",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
{
label: "opt",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
{
label: "matic",
placeholder: "0x0000000000000000000000000000000000000000",
fieldType: FieldType.Address,
value: "",
validationFunction: (fieldValue: string) => {
const fieldIsEmpty: Readonly<boolean> = fieldValue === "";
const isValidAddress: Readonly<boolean> = !!isAddress(fieldValue);
return fieldIsEmpty || isValidAddress;
},
},
]);

const updateFieldsWithEnsData = (ensData: ResolvedEnsData | null) => {
Expand Down Expand Up @@ -239,7 +329,9 @@ const FieldsProvider: React.FC<FieldsProviderProps> = ({ children }) => {
if (coinNames.includes(field.label)) {
return {
...field,
value: (ensData.coins as DecodedAddr[]).find((coin)=>coin.name===field.label)?.value as string,
value: (ensData.coins as DecodedAddr[]).find(
(coin) => coin.name === field.label
)?.value as string,
};
}
return field;
Expand Down
92 changes: 22 additions & 70 deletions lib/utils/blockchain-txs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ import {
BaseError,
RawContractError,
Hash,
Hex,
Address,
toHex,
http,
fromBytes,
} from "viem";
import { isTestnet, SupportedNetwork } from "../wallet/chains";
import { sepolia, mainnet } from "viem/chains";
Expand All @@ -36,13 +33,14 @@ import {
import { getNameRegistrationSecret } from "@/lib/name-registration/localStorage";
import { parseAccount } from "viem/utils";
import DomainResolverABI from "../abi/resolver.json";
import { normalize, packetToBytes } from "viem/ens";
import { normalize } from "viem/ens";
import { cryptocurrencies, cryptocurrenciesToCoinType } from "./ensData";
import { getCoderByCoinName } from "@ensdomains/address-encoder";
import {
DomainAddressesSupportedCryptocurrencies,
cryptocurrencyToCoinType,
} from "./ensData";
import { useEnsResolver } from "wagmi";
import { universalResolverResolveAbi } from "viem/_types/constants/abis";
CcipRequestParameters,
DomainData,
MessageData,
} from "./types";

const walletConnectProjectId =
process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID;
Expand All @@ -51,44 +49,6 @@ if (!walletConnectProjectId) {
throw new Error("No wallet connect project ID informed");
}

/**
* @notice Struct used to define the domain of the typed data signature, defined in EIP-712.
* @param name The user friendly name of the contract that the signature corresponds to.
* @param version The version of domain object being used.
* @param chainId The ID of the chain that the signature corresponds to (ie Ethereum mainnet: 1, Goerli testnet: 5, ...).
* @param verifyingContract The address of the contract that the signature pertains to.
*/
export type DomainData = {
name: string;
version: string;
chainId: number;
verifyingContract: `0x${string}`;
};

/**
* @notice Struct used to define a parameter for off-chain Database Handler deferral.
* @param name The variable name of the parameter.
* @param value The string encoded value representation of the parameter.
*/
export type Parameter = {
name: string;
value: string;
};

/**
* @notice Struct used to define the message context used to construct a typed data signature, defined in EIP-712,
* to authorize and define the deferred mutation being performed.
* @param functionSelector The function selector of the corresponding mutation.
* @param sender The address of the user performing the mutation (msg.sender).
* @param parameter[] A list of <key, value> pairs defining the inputs used to perform the deferred mutation.
*/
export type MessageData = {
functionSelector: `0x${string}`;
sender: `0x${string}`;
parameters: Parameter[];
expirationTimestamp: bigint;
};

const createCustomWalletClient = (account: `0x${string}`): WalletClient => {
return createWalletClient({
account,
Expand Down Expand Up @@ -149,17 +109,6 @@ export async function makeCommitment({
});
}

export type TypedSignature = {
signature: `0x${string}`;
domain: DomainData;
message: MessageData;
};

export type CcipRequestParameters = {
body: { data: Hex; signature: TypedSignature; sender: Address };
url: string;
};

export async function ccipRequest({
body,
url,
Expand Down Expand Up @@ -421,21 +370,24 @@ export const setDomainRecords = async ({
}

for (let i = 0; i < Object.keys(addresses).length; i++) {
const value = Object.values(addresses)[i];

const [cryptocurrencyName, address] = Object.entries(addresses)[i];
if (
!Object.keys(cryptocurrencies).includes(
cryptocurrencyName.toUpperCase()
)
) {
console.error(`cryptocurrency ${cryptocurrencyName} not supported`);
continue;
}
const coinType =
cryptocurrenciesToCoinType[cryptocurrencyName.toUpperCase()];
const coder = getCoderByCoinName(cryptocurrencyName.toLocaleLowerCase());
const addressEncoded = fromBytes(coder.decode(address), "hex");
const callData = encodeFunctionData({
functionName: "setAddr",
abi: DomainResolverABI,
// To be replaced when multiple coin types are supported
args: [
namehash(publicAddress),
cryptocurrencyToCoinType[
DomainAddressesSupportedCryptocurrencies.ETH
],
value,
],
args: [namehash(publicAddress), coinType, addressEncoded],
});

calls.push(callData);
}

Expand Down
62 changes: 36 additions & 26 deletions lib/utils/ensData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import { getSubgraphRecords } from "@ensdomains/ensjs/subgraph";
import { DecodedAddr } from "@ensdomains/ensjs/dist/types/types";

import { normalize } from "viem/ens";
import assert from "assert";
import { formatsByCoinType } from "@ensdomains/address-encoder";

// ENS Domain Data query
const ensSubgraphApiKey = process.env.NEXT_PUBLIC_ENS_SUBGRAPH_KEY;
Expand Down Expand Up @@ -44,32 +42,40 @@ export interface ResolvedEnsData {
owner?: string;
}

// ENS Domain Coins utils
export enum DomainAddressesSupportedCryptocurrencies {
BTC = "BTC",
LTC = "LTC",
DOGE = "DOGE",
ETH = "ETH",
BNB = "BNB",
}
export const cryptocurrencies: { [k: string]: string } = {
BTC: "BTC",
LTC: "LTC",
DOGE: "DOGE",
ETH: "ETH",
BNB: "BNB",
ARB1: "ARB1",
OP: "OP",
MATIC: "MATIC",
};

export const cryptocurrencyToCoinType = {
[DomainAddressesSupportedCryptocurrencies.BTC]: "0",
[DomainAddressesSupportedCryptocurrencies.LTC]: "2",
[DomainAddressesSupportedCryptocurrencies.DOGE]: "3",
[DomainAddressesSupportedCryptocurrencies.ETH]: "60",
[DomainAddressesSupportedCryptocurrencies.BNB]: "714",
export const cryptocurrenciesToCoinType: { [k: string]: string } = {
[cryptocurrencies.BTC]: "0",
[cryptocurrencies.LTC]: "2",
[cryptocurrencies.DOGE]: "3",
[cryptocurrencies.ETH]: "60",
[cryptocurrencies.BNB]: "714",
[cryptocurrencies.ARB1]: "2147525809",
[cryptocurrencies.OP]: "2147483658",
[cryptocurrencies.MATIC]: "2147483658",
};

export const cryptocurrenciesToSymbol = {
[DomainAddressesSupportedCryptocurrencies.BTC]: "₿",
[DomainAddressesSupportedCryptocurrencies.LTC]: "Ł",
[DomainAddressesSupportedCryptocurrencies.DOGE]: "Ð",
[DomainAddressesSupportedCryptocurrencies.ETH]: "Ξ",
[DomainAddressesSupportedCryptocurrencies.BNB]: "₿",
export const cryptocurrenciesToSymbol: { [k: string]: string } = {
[cryptocurrencies.BTC]: "₿",
[cryptocurrencies.LTC]: "Ł",
[cryptocurrencies.DOGE]: "Ð",
[cryptocurrencies.ETH]: "Ξ",
[cryptocurrencies.BNB]: "₿",
[cryptocurrencies.ARB1]: "ARB",
[cryptocurrencies.OP]: "OP",
[cryptocurrencies.MATIC]: "MATIC",
};

// // ENS Data network requests
// ENS Data network requests
// const fetchEnsDataRequest = async (domain: string) => {
// const res = await fetch(ENS_SUBGRAPH_ENDPOINT, {
// method: "POST",
Expand Down Expand Up @@ -219,14 +225,19 @@ export async function getENSDomainData(
texts: availableTextRecords?.length
? availableTextRecords
: defaultTextRecords,
coins: ["ETH"],
coins: [
cryptocurrencies.ETH,
cryptocurrencies.BTC,
cryptocurrencies.ARB1,
cryptocurrencies.OP,
cryptocurrencies.MATIC,
],
contentHash: true,
}),
getOwner.batch({ name: domain }),
getExpiry.batch({ name: domain })
),
]);

const textRecords = batchResults[0];
const owner = batchResults[1];
const expiry = batchResults[2];
Expand Down Expand Up @@ -263,6 +274,5 @@ export async function getENSDomainData(
owner: ownerName?.name ?? owner?.owner,
expiry: expiry?.expiry?.date?.getTime(),
};

return updatedTextRecords;
}
Loading

0 comments on commit 76cf4b4

Please sign in to comment.