Building Transactions
SuinsTransaction is the client you use similar to Transaction, and helps in building a transaction.
You need to instantiate it once in every programmable transaction block (PTB) that you are building.
Pyth price feeds
SuiNS names are priced in USDC. Paying in SUI or NS needs a live exchange rate, which the contracts read from the Pyth oracle, so those transactions must include a price info object.
Pyth serves its price updates from Hermes, which requires an access token. Create a free Pyth account and copy the key from View your API key. Keep it out of browser code, so the fetch always happens on a server.
You can get a price info object into your transaction in two ways.
Fetch and build on a server
Initialize the SuinsClient with the token and call getPriceInfoObject. It fetches the update and adds the update calls to the transaction you pass it, so this approach builds the whole PTB server-side.
const suinsClient = new SuinsClient({
client,
network: 'testnet',
pythAccessToken: process.env.PYTH_ACCESS_TOKEN,
});
const priceInfoObjectId = (await suinsClient.getPriceInfoObject(transaction, coinConfig.feed))[0];
Fetch on a server, build on the client
To keep building the PTB in the browser, split the work across @pythnetwork/pyth-sui-js. Fetch the update bytes on your backend:
const connection = new SuiPriceServiceConnection('https://pyth.dourolabs.app/hermes', {
accessToken: process.env.PYTH_ACCESS_TOKEN,
});
const updates = await connection.getPriceFeedsUpdateData([coinConfig.feed]);
Then add the update to the transaction on the client:
const pythClient = new SuiPythClient(
suinsClient.client,
suinsClient.config.pyth.pythStateId,
suinsClient.config.pyth.wormholeStateId,
);
const [priceInfoObjectId] = await pythClient.updatePriceFeeds(transaction, updates, [coinConfig.feed]);
Either way, pass the resulting priceInfoObjectId to the register and renew commands described in the following section.
Available functions
This is a list of all the available PTB commands supported through the SDK.
Register a name
const register = async (name: string, years: number) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// Specify the coin type used for the transaction, can be SUI/NS/USDC
const coinConfig = suinsClient.config.coins.USDC;
// priceInfoObjectId is required for SUI/NS
const priceInfoObjectId = (await suinsClient.getPriceInfoObject(transaction, coinConfig.feed))[0];
// Build the transaction to register the name, specifying a year from 1 to 5.
const nft = suinsTransaction.register({
domain: 'myname.sui',
years: 3,
coinConfig,
priceInfoObjectId, // Only required for SUI/NS
});
// Transfer the name's NFT
transaction.transferObjects([nft], transaction.pure.address('0xMyAddress'));
// ... sign and execute the transaction
}
Renew a name
const renew = async (nftId: string, name: string, years: number) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// Specify the coin type used for the transaction, can be SUI/NS/USDC
const coinConfig = suinsClient.config.coins.USDC;
// priceInfoObjectId is required for SUI/NS
const priceInfoObjectId = (await suinsClient.getPriceInfoObject(transaction, coinConfig.feed))[0];
// Build the transaction to renew the name, specifying a year from 1 to 5.
suinsTransaction.renew({
nft: '0xMyNftObject',
years: 3,
coinConfig,
priceInfoObjectId, // Only required for SUI/NS
});
// ... sign and execute the transaction
}
Set a name's target address
This works the same for names and subnames.
const setTargetAddress = async (nftId: string, address: string) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// We build the transaction to set the target address.
suinsTransaction.setTargetAddress({
nft: nftId,
address,
isSubname: false,
});
// ... sign and execute the transaction
}
Set a name as default
This works the same for names and subnames.
const setDefault = async (name: string) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// We build the transaction to set that name as default for the sender.
// Important: This is only possible if the address signing/executing
// the transaction is the same as the target address of that name.
suinsTransaction.setDefault(name);
// ... sign and execute the transaction
}
For subname operations (create, edit, extend, and remove subnames), see Subname Transactions.
Set a name's metadata
Currently supports AVATAR and IPFS hash.
const setUserData = async (nft: string, avatar: string, contentHash: string) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// Build the transaction to set the metadata.
// Set the avatar to the supplied value.
suinsTransaction.setUserData({
nft,
key: ALLOWED_METADATA.avatar,
value: avatar,
isSubname: false,
});
// Set the contentHash to the supplied value.
suinsTransaction.setUserData({
nft,
key: ALLOWED_METADATA.contentHash,
value: contentHash,
isSubname: false,
});
// Set the walrusSiteId to the supplied value.
suinsTransaction.setUserData({
nft,
key: ALLOWED_METADATA.walrusSiteId,
value: walrusSiteId,
isSubname: false,
});
// ... sign and execute the transaction
}
Burn an expired name
Allows burning an expired name to get back storage rebates.
const burnExpired = async (nftId: string) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// Build the transaction to burn the expired name.
suinsTransaction.burnExpired({
nft: nftId,
isSubname: false,
});
// ... sign and execute the transaction
}
Combined example
The following code snippet registers a SuiNS name using NS, sets its target address, and sets it as the default name for the target address in a single PTB. You could also add transaction commands to do even more in the same PTB if you wanted to, like create subnames and so on, but that is beyond the scope of this example.
// Years must be between 1-5.
const composedExample = async (name: string, years: number) => {
// Create a transaction block as usual in your PTBs.
const transaction = new Transaction();
// Pass in the transaction block & the app's global SuinsClient.
const suinsTransaction = new SuinsTransaction(suinsClient, transaction);
// Specify the coin type used for the transaction, can be SUI/NS/USDC
const coinConfig = suinsClient.config.coins.NS;
// priceInfoObjectId is required for SUI/NS
const priceInfoObjectId = (await suinsClient.getPriceInfoObject(transaction, coinConfig.feed))[0];
// Build the transaction to register the name, specifying a year from 1 to 5.
const nft = suinsTransaction.register({
domain: 'myname.sui',
years,
coinConfig,
coin: '0xMyCoinObject', // Only required for NS/USDC
priceInfoObjectId, // Only required for SUI/NS
});
// You can now use this NFT, for instance to set its target address.
suinsTransaction.setTargetAddress({
nft,
address,
isSubname: false,
});
// And you could also set this name as the default name for `0xMyAddress`.
// This is only possible if the address signs and executes the transaction.
suinsTransaction.setDefault(name);
// Transfer the name's NFT to the address.
transaction.transferObjects([nft], transaction.pure.address('0xMyAddress'));
// ... sign and execute the transaction
}