diff --git a/README.md b/README.md index 02538fd..5aeaed5 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,88 @@ ![Namespace Ninja](https://namespace.fra1.cdn.digitaloceanspaces.com/brand/logo_small.png) # Namespace-SDK -A Typescript library used to interact with Namespace contracts and APIs. -It uses Viem under the hood and can be used to: -* Find names listed on the Namespace platform -* Check the availability of subnames -* Mint subnames +A TypeScript SDK for interacting with Namespace - a platform for managing ENS names and subnames. Built on top of [Viem](https://viem.sh), this SDK enables you to: +* List and manage ENS subnames +* Check subname availability across multiple chains +* Mint ENS subnames with custom records +* Interact with Namespace smart contracts -This is the initial version, expect many more functionalities in the future! +> **Note**: This project is in early stages and is under active development. # Installation -Use a package manager to install the library into your project +Install using your preferred package manager: -Yarn -```bash -yarn add namespace-sdk -``` -Npm ```bash +# pnpm +pnpm add namespace-sdk + +# npm npm install namespace-sdk + +# yarn +yarn add namespace-sdk ``` +**Note**: We recommend using [pnpm](https://pnpm.io/) due to its better performance and smaller bundle size. + +# Usage + +## Prerequisites -# Getting started +### Listing an ENS Name -First, we can create a simple NamespaceClient and specify the chainID. The chain id specifies a chain on which read/write blockchain operations happen. If we list our name on a Mainnet and subnames are minted on Mainnet, we'll have to specify a chainID 1. We will use a sepolia testnet as an example. +Before minting subnames, you need to list your ENS name on the [Namespace platform](https://app.namespace.tech). -The chainID is required since the library supports minting subnames on both Layer 1 and its testnet (Sepolia) but also on Layer 2 (currently, only Base chain is supported). +You can find the required steps by following the [Manager Guide](https://docs.namespace.tech/namespace-platform/manager/listing-an-ens-name#listing-an-ens-name) + +## Using the SDK + +### Initialize the Client + +Create a NamespaceClient instance by specifying the chain you want to interact with. ```typescript import { createNamespaceClient } from "namespace-sdk"; import { sepolia } from "viem/chains"; +// Initialize the Namespace SDK client const namespaceClient = createNamespaceClient({ chainId: sepolia.id }); ``` -# Minting a subname - -Minting ENS subnames requires a couple of steps. -## 1. Listing an ENS name +Currently, we support the following chains: +- Ethereum Mainnet +- Sepolia Testnet +- Base +- Base Sepolia Testnet +- Optimism +- Arbitrum -First, we would need to have an ENS name that is listed on the Namespace platform. To do so, visit our [Platform](https://app.namespace.tech) and check -[Manager](https://docs.namespace.tech/namespace-platform/manager) +**Note**: We are actively working on adding support for more chains. -For testing purposes, you can use "namespace-sdk.eth" on the Sepolia chain. -## 2. Generate minting parameters - -After we list the ENS name, our platform allows minting subnames under it. We can use a library to check for subname availability and to generate mint transaction parameters. +### Minting ENS Subnames +The minting process consists of two main steps: +1. Check subname availability and generate the required transaction parameters: ```typescript -import { createNamespaceClient, SetRecordsRequest, MintTransactionParameters } from "namespace-sdk"; +// Import the Namespace SDK and Viem chains +import { createNamespaceClient, MintTransactionParameters } from "namespace-sdk"; import { sepolia } from "viem/chains"; +// Initialize the Namespace SDK client const namespaceClient = createNamespaceClient({ chainId: sepolia.id, }); +// Define the listed name from the [Namespace Platform](https://docs.namespace.tech/namespace-platform/manager/listing-an-ens-name#listing-an-ens-name) in the previous step const LISTED_NAME = "namespace-sdk.eth" -const ETH_COIN_TYPE = 60; + +// Define the subname to be minted +const SUBNAME_LABEL = "subname" + +// Define the minter address +const MINTER_ADDRESS = "0xbe02d5ceAB7296A4E8b516eee578Be75983674e9" const generateMintingParameters = async (): Promise => { @@ -69,76 +92,142 @@ const generateMintingParameters = async (): Promise = sepolia.id ); - const subnameLabel = "myfunnylabel"; - const minterAddress = "0x6CaBE5E77F90d58600A3C13127Acf6320Bee0aA7" - // Check for name availability const isNotTaken = await namespaceClient.isSubnameAvailable( listedName, - subnameLabel + SUBNAME_LABEL ); - + if (!isNotTaken) { throw Error("Subname is already taken!"); } // Generate mint transcation parameters const mintDetails = await namespaceClient.getMintTransactionParameters(listedName, { - minterAddress: minterAddress, - subnameLabel: subnameLabel, - subnameOwner: minterAddress, - // Optionaly, we can also set resolver records with the mint transaction - records: { - addresses: [ - { - address: minterAddress, - coinType: ETH_COIN_TYPE - } - ], - texts: [ - { - key: "name", - value: "namespace" - } - ] - } + minterAddress: MINTER_ADDRESS, + subnameLabel: SUBNAME_LABEL, + subnameOwner: MINTER_ADDRESS, }); return mintDetails; }; ``` -## 3. Send Transaction -Sending a transaction is the last step. Since the library uses Viem under the hood, we will use WalletClient to send a transaction. +2. Execute the Mint Transaction + +Use Viem's WalletClient to send the transaction: + +```typescript +// Import your wallet and create a Viem Wallet Client +const wallet = privateKeyToAccount("0xYOUR_PRIVATE_KEY_HERE"); +const walletClient = createWalletClient({ + transport: http(), + chain: sepolia, + account: wallet, +}) + +// Generate minting parameters +const mintParams = await generateMintingParameters(); + +// Send transaction +const transactionHash = await walletClient.writeContract({ + abi: mintParams.abi, + address: mintParams.contractAddress, + functionName: mintParams.functionName, + args: mintParams.args, + value: mintParams.value, +}) + +console.log(transactionHash); +``` + +Full example: ```typescript +// Import the Namespace SDK and Viem chains +import { createNamespaceClient, MintTransactionParameters } from "namespace-sdk"; import { sepolia } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; import { createWalletClient, http } from "viem"; -import { generateMintingParameters } from "./minting"; - -const sendMintTransaction = async () => { - - // Import your wallet and create a Viem Wallet Client - const wallet = privateKeyToAccount("0xYourWallet"); - const walletClient = createWalletClient({ - transport: http(), - chain: sepolia, - account: wallet - }) - - // Generate minting parameters - const mintParams = await generateMintingParameters(); - - // Send transaction - const transactionHash = await walletClient.writeContract({ - abi: mintParams.abi, - address: mintParams.contractAddress, - functionName: mintParams.functionName, - args: mintParams.args, - value: mintParams.value - }) - - console.log(transactionHash); -} + +// Initialize the Namespace SDK client +const namespaceClient = createNamespaceClient({ + chainId: sepolia.id, +}); + +// Define the listed name from the [Namespace Platform](https://docs.namespace.tech/namespace-platform/manager/listing-an-ens-name#listing-an-ens-name) in the previous step +const LISTED_NAME = "namespace-sdk.eth" + +// Define the subname to be minted +const SUBNAME_LABEL = "subname" + +// Define the minter address +const MINTER_ADDRESS = "0xbe02d5ceAB7296A4E8b516eee578Be75983674e9" + +const generateMintingParameters = async (): Promise => { + + // Get listed name from namespace api + const listedName = await namespaceClient.getListedName( + LISTED_NAME, + sepolia.id + ); + + // Check for name availability + const isNotTaken = await namespaceClient.isSubnameAvailable( + listedName, + SUBNAME_LABEL + ); + + if (!isNotTaken) { + throw Error("Subname is already taken!"); + } + + // Generate mint transcation parameters + const mintDetails = await namespaceClient.getMintTransactionParameters(listedName, { + minterAddress: MINTER_ADDRESS, + subnameLabel: SUBNAME_LABEL, + subnameOwner: MINTER_ADDRESS, + }); + return mintDetails; +}; + +// Import your wallet and create a Viem Wallet Client +const wallet = privateKeyToAccount("0xYOUR_PRIVATE_KEY_HERE"); +const walletClient = createWalletClient({ + transport: http(), + chain: sepolia, + account: wallet, +}) + +// Generate minting parameters +const mintParams = await generateMintingParameters(); + +// Send transaction +const transactionHash = await walletClient.writeContract({ + abi: mintParams.abi, + address: mintParams.contractAddress, + functionName: mintParams.functionName, + args: mintParams.args, + value: mintParams.value, +}) + +console.log(transactionHash); ``` +**Note**: We recommend setting a custom RPC URL for the chain you are interacting with. You can do so by adding an argument to the http() function: +```typescript +const walletClient = createWalletClient({ + transport: http('https://eth-sepolia.g.alchemy.com/v2/ALCHEMY_API_KEY'), + chain: sepolia, + account: wallet, +}) +``` + + +## Contributing + +Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting PRs. + +## License + +MIT License - see the [LICENSE](LICENSE) file for details. + ## Authors -[artii.eth](https://github.com/nenadmitt) +- [artii.eth](https://github.com/nenadmitt) diff --git a/src/clients/types/auth.ts b/src/clients/types/auth.ts index 0fed073..8975f20 100644 --- a/src/clients/types/auth.ts +++ b/src/clients/types/auth.ts @@ -16,16 +16,16 @@ const Types = { }; export interface AuthTokenMessage { - app: string - issued: number, - message: string, - nonce: string, - principal: Address, + app: string + issued: number, + message: string, + nonce: string, + principal: Address, } export interface AuthTokenResponse { - accessToken: string - refreshToken: string + accessToken: string + refreshToken: string } export interface AuthTokenRequest { @@ -34,6 +34,6 @@ export interface AuthTokenRequest { } export const AuthTypedData = { - Domain, - Types + Domain, + Types, } diff --git a/src/clients/types/listings.ts b/src/clients/types/listings.ts index daa68bb..5bf7cf5 100644 --- a/src/clients/types/listings.ts +++ b/src/clients/types/listings.ts @@ -2,22 +2,21 @@ import { L2Chain, MainChain } from "." import { Address } from "viem" export interface ListingRequest { - listingType?: ListingType - network: MainChain - tokenNetwork?: L2Chain - owner?: Address - page?: number - size?: number + listingType?: ListingType + network: MainChain + tokenNetwork?: L2Chain + owner?: Address + page?: number + size?: number } export interface Listing { - label: string; - fullName: string; - node: string; - network: MainChain; - listingType?: ListingType - registryNetwork?: L2Chain + label: string; + fullName: string; + node: string; + network: MainChain; + listingType?: ListingType + registryNetwork?: L2Chain } - -export type ListingType = "sellUnruggable" | "l2" \ No newline at end of file +export type ListingType = "sellUnruggable" | "l2"