@moveindustries/ts-sdk 5.1.4 → 5.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -43
- package/dist/common/{accountAddress-DoqkxUqw.d.ts → accountAddress-CQEq9RVR.d.ts} +6 -2
- package/dist/common/chunk-56DGDNEY.js.map +1 -1
- package/dist/common/cli/index.d.ts +1 -1
- package/dist/common/cli/index.js.map +1 -1
- package/dist/common/index.d.ts +393 -55
- package/dist/common/index.js +32 -32
- package/dist/common/index.js.map +1 -1
- package/dist/esm/account/AbstractKeylessAccount.mjs +1 -1
- package/dist/esm/account/AbstractedAccount.mjs +1 -1
- package/dist/esm/account/Account.mjs +1 -1
- package/dist/esm/account/AccountUtils.mjs +1 -1
- package/dist/esm/account/DerivableAbstractedAccount.mjs +1 -1
- package/dist/esm/account/Ed25519Account.mjs +1 -1
- package/dist/esm/account/EphemeralKeyPair.mjs +1 -1
- package/dist/esm/account/FederatedKeylessAccount.mjs +1 -1
- package/dist/esm/account/KeylessAccount.mjs +1 -1
- package/dist/esm/account/MultiEd25519Account.mjs +1 -1
- package/dist/esm/account/MultiKeyAccount.mjs +1 -1
- package/dist/esm/account/SingleKeyAccount.mjs +1 -1
- package/dist/esm/account/index.mjs +1 -1
- package/dist/esm/account/utils.mjs +1 -1
- package/dist/esm/api/account/abstraction.mjs +1 -1
- package/dist/esm/api/account.mjs +1 -1
- package/dist/esm/api/coin.mjs +1 -1
- package/dist/esm/api/digitalAsset.mjs +1 -1
- package/dist/esm/api/faucet.mjs +1 -1
- package/dist/esm/api/fungibleAsset.mjs +1 -1
- package/dist/esm/api/general.mjs +1 -1
- package/dist/esm/api/index.d.mts +2 -2
- package/dist/esm/api/index.mjs +1 -1
- package/dist/esm/api/keyless.mjs +1 -1
- package/dist/esm/api/{ans.d.mts → mns.d.mts} +390 -52
- package/dist/esm/api/mns.mjs +2 -0
- package/dist/esm/api/movement.d.mts +4 -4
- package/dist/esm/api/movement.mjs +1 -1
- package/dist/esm/api/object.mjs +1 -1
- package/dist/esm/api/staking.mjs +1 -1
- package/dist/esm/api/table.mjs +1 -1
- package/dist/esm/api/transaction.mjs +1 -1
- package/dist/esm/api/transactionSubmission/build.mjs +1 -1
- package/dist/esm/api/transactionSubmission/management.mjs +1 -1
- package/dist/esm/api/transactionSubmission/sign.mjs +1 -1
- package/dist/esm/api/transactionSubmission/simulate.mjs +1 -1
- package/dist/esm/api/transactionSubmission/submit.mjs +1 -1
- package/dist/esm/api/utils.mjs +1 -1
- package/dist/esm/bcs/index.mjs +1 -1
- package/dist/esm/bcs/serializable/moveStructs.mjs +1 -1
- package/dist/esm/{chunk-SYXDZA4K.mjs → chunk-46MDTYYN.mjs} +2 -2
- package/dist/esm/chunk-4OOPIIBY.mjs +4 -0
- package/dist/esm/{chunk-47V7UGV5.mjs.map → chunk-4OOPIIBY.mjs.map} +1 -1
- package/dist/esm/{chunk-RUIFVDWM.mjs → chunk-5KMDJLYM.mjs} +2 -2
- package/dist/esm/{chunk-FJRPU2NH.mjs → chunk-7KIJGBLL.mjs} +2 -2
- package/dist/esm/{chunk-S4D2KBYN.mjs → chunk-7KOS7CFM.mjs} +2 -2
- package/dist/esm/{chunk-V3O2SBO4.mjs → chunk-ESZIZDLP.mjs} +2 -2
- package/dist/esm/{chunk-YFFYA5U3.mjs → chunk-HU7GK5PL.mjs} +2 -2
- package/dist/esm/chunk-P6MFR7W6.mjs +2 -0
- package/dist/esm/{chunk-PCESRJYO.mjs.map → chunk-P6MFR7W6.mjs.map} +1 -1
- package/dist/esm/{chunk-MEWW7VTQ.mjs → chunk-P7DJNENM.mjs} +2 -2
- package/dist/esm/{chunk-PHRRBT44.mjs → chunk-PG4MJ3CJ.mjs} +2 -2
- package/dist/esm/{chunk-NMFJJOGW.mjs → chunk-QT3RHJP2.mjs} +2 -2
- package/dist/esm/{chunk-CRCE7R4D.mjs → chunk-SZG3ZZGN.mjs} +2 -2
- package/dist/esm/{chunk-R2G23RIY.mjs → chunk-ZGBIH6MJ.mjs} +2 -2
- package/dist/esm/{chunk-NQUZ4UHR.mjs → chunk-ZZEJESMY.mjs} +2 -2
- package/dist/esm/client/core.mjs +1 -1
- package/dist/esm/client/get.mjs +1 -1
- package/dist/esm/client/index.mjs +1 -1
- package/dist/esm/client/post.mjs +1 -1
- package/dist/esm/core/crypto/abstraction.mjs +1 -1
- package/dist/esm/core/crypto/deserializationUtils.mjs +1 -1
- package/dist/esm/core/crypto/ed25519.mjs +1 -1
- package/dist/esm/core/crypto/ephemeral.mjs +1 -1
- package/dist/esm/core/crypto/federatedKeyless.mjs +1 -1
- package/dist/esm/core/crypto/index.mjs +1 -1
- package/dist/esm/core/crypto/keyless.mjs +1 -1
- package/dist/esm/core/crypto/multiEd25519.mjs +1 -1
- package/dist/esm/core/crypto/multiKey.mjs +1 -1
- package/dist/esm/core/crypto/proof.mjs +1 -1
- package/dist/esm/core/crypto/publicKey.mjs +1 -1
- package/dist/esm/core/crypto/secp256k1.mjs +1 -1
- package/dist/esm/core/crypto/secp256r1.mjs +1 -1
- package/dist/esm/core/crypto/signature.mjs +1 -1
- package/dist/esm/core/crypto/singleKey.mjs +1 -1
- package/dist/esm/core/crypto/utils.mjs +1 -1
- package/dist/esm/core/index.mjs +1 -1
- package/dist/esm/errors/index.mjs +1 -1
- package/dist/esm/index.d.mts +3 -3
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/internal/abstraction.mjs +1 -1
- package/dist/esm/internal/account.mjs +1 -1
- package/dist/esm/internal/coin.mjs +1 -1
- package/dist/esm/internal/digitalAsset.mjs +1 -1
- package/dist/esm/internal/faucet.mjs +1 -1
- package/dist/esm/internal/fungibleAsset.mjs +1 -1
- package/dist/esm/internal/general.mjs +1 -1
- package/dist/esm/internal/keyless.mjs +1 -1
- package/dist/esm/internal/{ans.d.mts → mns.d.mts} +237 -19
- package/dist/esm/internal/mns.mjs +2 -0
- package/dist/esm/internal/object.mjs +1 -1
- package/dist/esm/internal/staking.mjs +1 -1
- package/dist/esm/internal/table.mjs +1 -1
- package/dist/esm/internal/transaction.mjs +1 -1
- package/dist/esm/internal/transactionSubmission.mjs +1 -1
- package/dist/esm/internal/utils/index.mjs +1 -1
- package/dist/esm/internal/utils/utils.mjs +1 -1
- package/dist/esm/internal/view.mjs +1 -1
- package/dist/esm/transactions/authenticator/account.mjs +1 -1
- package/dist/esm/transactions/authenticator/index.mjs +1 -1
- package/dist/esm/transactions/authenticator/transaction.mjs +1 -1
- package/dist/esm/transactions/index.mjs +1 -1
- package/dist/esm/transactions/instances/index.mjs +1 -1
- package/dist/esm/transactions/instances/moduleId.mjs +1 -1
- package/dist/esm/transactions/instances/multiAgentTransaction.mjs +1 -1
- package/dist/esm/transactions/instances/rawTransaction.mjs +1 -1
- package/dist/esm/transactions/instances/rotationProofChallenge.mjs +1 -1
- package/dist/esm/transactions/instances/signedTransaction.mjs +1 -1
- package/dist/esm/transactions/instances/simpleTransaction.mjs +1 -1
- package/dist/esm/transactions/instances/transactionPayload.mjs +1 -1
- package/dist/esm/transactions/management/accountSequenceNumber.mjs +1 -1
- package/dist/esm/transactions/management/index.mjs +1 -1
- package/dist/esm/transactions/management/transactionWorker.mjs +1 -1
- package/dist/esm/transactions/transactionBuilder/helpers.mjs +1 -1
- package/dist/esm/transactions/transactionBuilder/index.mjs +1 -1
- package/dist/esm/transactions/transactionBuilder/remoteAbi.mjs +1 -1
- package/dist/esm/transactions/transactionBuilder/signingMessage.mjs +1 -1
- package/dist/esm/transactions/transactionBuilder/transactionBuilder.mjs +1 -1
- package/dist/esm/transactions/typeTag/index.mjs +1 -1
- package/dist/esm/transactions/typeTag/parser.mjs +1 -1
- package/dist/esm/types/index.d.mts +1 -1
- package/dist/esm/types/indexer.d.mts +6 -2
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/normalizeBundle.mjs +1 -1
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +19 -18
- package/src/api/{ans.ts → mns.ts} +437 -51
- package/src/api/movement.ts +5 -5
- package/src/internal/{ans.ts → mns.ts} +642 -84
- package/src/types/indexer.ts +6 -1
- package/src/version.ts +1 -1
- package/dist/esm/api/ans.mjs +0 -2
- package/dist/esm/chunk-47V7UGV5.mjs +0 -4
- package/dist/esm/chunk-PCESRJYO.mjs +0 -2
- package/dist/esm/internal/ans.mjs +0 -2
- /package/dist/esm/api/{ans.mjs.map → mns.mjs.map} +0 -0
- /package/dist/esm/{chunk-SYXDZA4K.mjs.map → chunk-46MDTYYN.mjs.map} +0 -0
- /package/dist/esm/{chunk-RUIFVDWM.mjs.map → chunk-5KMDJLYM.mjs.map} +0 -0
- /package/dist/esm/{chunk-FJRPU2NH.mjs.map → chunk-7KIJGBLL.mjs.map} +0 -0
- /package/dist/esm/{chunk-S4D2KBYN.mjs.map → chunk-7KOS7CFM.mjs.map} +0 -0
- /package/dist/esm/{chunk-V3O2SBO4.mjs.map → chunk-ESZIZDLP.mjs.map} +0 -0
- /package/dist/esm/{chunk-YFFYA5U3.mjs.map → chunk-HU7GK5PL.mjs.map} +0 -0
- /package/dist/esm/{chunk-MEWW7VTQ.mjs.map → chunk-P7DJNENM.mjs.map} +0 -0
- /package/dist/esm/{chunk-PHRRBT44.mjs.map → chunk-PG4MJ3CJ.mjs.map} +0 -0
- /package/dist/esm/{chunk-NMFJJOGW.mjs.map → chunk-QT3RHJP2.mjs.map} +0 -0
- /package/dist/esm/{chunk-CRCE7R4D.mjs.map → chunk-SZG3ZZGN.mjs.map} +0 -0
- /package/dist/esm/{chunk-R2G23RIY.mjs.map → chunk-ZGBIH6MJ.mjs.map} +0 -0
- /package/dist/esm/{chunk-NQUZ4UHR.mjs.map → chunk-ZZEJESMY.mjs.map} +0 -0
- /package/dist/esm/internal/{ans.mjs.map → mns.mjs.map} +0 -0
|
@@ -14,7 +14,7 @@ import { MovementConfig } from "../api/movementConfig";
|
|
|
14
14
|
import { AccountAddress, AccountAddressInput } from "../core";
|
|
15
15
|
import { SimpleTransaction } from "../transactions/instances/simpleTransaction";
|
|
16
16
|
import { InputGenerateTransactionOptions } from "../transactions/types";
|
|
17
|
-
import {
|
|
17
|
+
import { GetMNSNameResponse, MoveAddressType, OrderByArg, PaginationArgs, WhereArg } from "../types";
|
|
18
18
|
import { GetNamesQuery } from "../types/generated/operations";
|
|
19
19
|
import { GetNames } from "../types/generated/queries";
|
|
20
20
|
import { CurrentAptosNamesBoolExp } from "../types/generated/types";
|
|
@@ -30,14 +30,14 @@ export const VALIDATION_RULES_DESCRIPTION = [
|
|
|
30
30
|
].join(" ");
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Validate if a given fragment is a valid
|
|
34
|
-
* This function checks the length and character constraints of the fragment to ensure it meets the
|
|
33
|
+
* Validate if a given fragment is a valid MNS segment.
|
|
34
|
+
* This function checks the length and character constraints of the fragment to ensure it meets the MNS standards.
|
|
35
35
|
*
|
|
36
36
|
* @param fragment - A fragment of a name, either the domain or subdomain.
|
|
37
37
|
* @returns A boolean indicating if the fragment is a valid fragment.
|
|
38
38
|
* @group Implementation
|
|
39
39
|
*/
|
|
40
|
-
export function
|
|
40
|
+
export function isValidMNSSegment(fragment: string): boolean {
|
|
41
41
|
if (!fragment) return false;
|
|
42
42
|
if (fragment.length < 3) return false;
|
|
43
43
|
if (fragment.length > 63) return false;
|
|
@@ -47,23 +47,23 @@ export function isValidANSSegment(fragment: string): boolean {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Checks if an
|
|
50
|
+
* Checks if an MNS name is valid or not.
|
|
51
51
|
*
|
|
52
|
-
* @param name - A string of the domain name, which can include or exclude the .
|
|
52
|
+
* @param name - A string of the domain name, which can include or exclude the .move suffix.
|
|
53
53
|
* @group Implementation
|
|
54
54
|
*/
|
|
55
|
-
export function
|
|
56
|
-
const [first, second, ...rest] = name.replace(/\.
|
|
55
|
+
export function isValidMNSName(name: string): { domainName: string; subdomainName?: string } {
|
|
56
|
+
const [first, second, ...rest] = name.replace(/\.move$/, "").split(".");
|
|
57
57
|
|
|
58
58
|
if (rest.length > 0) {
|
|
59
59
|
throw new Error(`${name} is invalid. A name can only have two parts, a domain and a subdomain separated by a "."`);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
if (!
|
|
62
|
+
if (!isValidMNSSegment(first)) {
|
|
63
63
|
throw new Error(`${first} is not valid. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
if (second && !
|
|
66
|
+
if (second && !isValidMNSSegment(second)) {
|
|
67
67
|
throw new Error(`${second} is not valid. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -83,16 +83,16 @@ export enum SubdomainExpirationPolicy {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* Determine if a given
|
|
86
|
+
* Determine if a given MNS name is considered active based on its expiration dates.
|
|
87
87
|
* Domains are active if their expiration date is in the future, while subdomains may
|
|
88
88
|
* follow their parent's expiration policy (1) or expire independently (0).
|
|
89
89
|
* If the subdomain is expiring independently, it can expire before their parent, but not after.
|
|
90
90
|
*
|
|
91
|
-
* @param name - An
|
|
91
|
+
* @param name - An MNS name returned from one of the functions of the SDK.
|
|
92
92
|
* @returns A boolean indicating whether the contract considers the name active or not.
|
|
93
93
|
* @group Implementation
|
|
94
94
|
*/
|
|
95
|
-
export function
|
|
95
|
+
export function isActiveMNSName(name: GetMNSNameResponse[0]): boolean {
|
|
96
96
|
if (!name) return false;
|
|
97
97
|
|
|
98
98
|
const isTLDExpired = new Date(name.domain_expiration_timestamp).getTime() < Date.now();
|
|
@@ -110,16 +110,17 @@ export function isActiveANSName(name: GetANSNameResponse[0]): boolean {
|
|
|
110
110
|
return !isExpired;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export const
|
|
114
|
-
process.env.
|
|
113
|
+
export const LOCAL_MNS_ACCOUNT_PK =
|
|
114
|
+
process.env.MNS_TEST_ACCOUNT_PRIVATE_KEY ??
|
|
115
115
|
"ed25519-priv-0x37368b46ce665362562c6d1d4ec01a08c8644c488690df5a17e13ba163e20221";
|
|
116
|
-
export const
|
|
117
|
-
process.env.
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
[Network.TESTNET]: "
|
|
121
|
-
|
|
122
|
-
[Network.
|
|
116
|
+
export const LOCAL_MNS_ACCOUNT_ADDRESS =
|
|
117
|
+
process.env.MNS_TEST_ACCOUNT_ADDRESS ?? "0x585fc9f0f0c54183b039ffc770ca282ebd87307916c215a3e692f2f8e4305e82";
|
|
118
|
+
|
|
119
|
+
const NetworkToMnsContract: Record<Network, string | null> = {
|
|
120
|
+
[Network.TESTNET]: "0x67bf15b3eed0fc62deea9630bbbd1d48842550655140f913699a1ca7e6f727d8",
|
|
121
|
+
// TODO: Update mainnet address once Movement Name Service is deployed to mainnet
|
|
122
|
+
[Network.MAINNET]: null,
|
|
123
|
+
[Network.LOCAL]: LOCAL_MNS_ACCOUNT_ADDRESS,
|
|
123
124
|
[Network.CUSTOM]: null,
|
|
124
125
|
[Network.DEVNET]: null,
|
|
125
126
|
[Network.SHELBYNET]: null,
|
|
@@ -127,17 +128,17 @@ const NetworkToAnsContract: Record<Network, string | null> = {
|
|
|
127
128
|
};
|
|
128
129
|
|
|
129
130
|
/**
|
|
130
|
-
* Retrieves the address of the
|
|
131
|
+
* Retrieves the address of the MNS contract based on the specified Movement network configuration.
|
|
131
132
|
*
|
|
132
133
|
* @param movementConfig - The configuration object for the Movement network.
|
|
133
|
-
* @param movementConfig.network - The network for which to retrieve the
|
|
134
|
+
* @param movementConfig.network - The network for which to retrieve the MNS contract address.
|
|
134
135
|
*
|
|
135
|
-
* @throws Throws an error if the
|
|
136
|
+
* @throws Throws an error if the MNS contract is not deployed to the specified network.
|
|
136
137
|
* @group Implementation
|
|
137
138
|
*/
|
|
138
139
|
function getRouterAddress(movementConfig: MovementConfig): string {
|
|
139
|
-
const address =
|
|
140
|
-
if (!address) throw new Error(`The
|
|
140
|
+
const address = NetworkToMnsContract[movementConfig.network];
|
|
141
|
+
if (!address) throw new Error(`The MNS contract is not deployed to ${movementConfig.network}`);
|
|
141
142
|
return address;
|
|
142
143
|
}
|
|
143
144
|
|
|
@@ -164,7 +165,7 @@ export async function getOwnerAddress(args: {
|
|
|
164
165
|
}): Promise<AccountAddress | undefined> {
|
|
165
166
|
const { movementConfig, name } = args;
|
|
166
167
|
const routerAddress = getRouterAddress(movementConfig);
|
|
167
|
-
const { domainName, subdomainName } =
|
|
168
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
168
169
|
|
|
169
170
|
const res = await view({
|
|
170
171
|
movementConfig,
|
|
@@ -229,7 +230,7 @@ export interface RegisterNameParameters {
|
|
|
229
230
|
export async function registerName(args: RegisterNameParameters): Promise<SimpleTransaction> {
|
|
230
231
|
const { movementConfig, expiration, name, sender, targetAddress, toAddress, options, transferable } = args;
|
|
231
232
|
const routerAddress = getRouterAddress(movementConfig);
|
|
232
|
-
const { domainName, subdomainName } =
|
|
233
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
233
234
|
|
|
234
235
|
const hasSubdomainPolicy =
|
|
235
236
|
expiration.policy === "subdomain:independent" || expiration.policy === "subdomain:follow-domain";
|
|
@@ -271,37 +272,19 @@ export async function registerName(args: RegisterNameParameters): Promise<Simple
|
|
|
271
272
|
throw new Error(`${expiration.policy} requires a subdomain to be provided.`);
|
|
272
273
|
}
|
|
273
274
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
movementConfig,
|
|
288
|
-
sender: sender.accountAddress.toString(),
|
|
289
|
-
data: {
|
|
290
|
-
function: `${routerAddress}::router::register_subdomain`,
|
|
291
|
-
functionArguments: [
|
|
292
|
-
domainName,
|
|
293
|
-
subdomainName,
|
|
294
|
-
Math.round(expirationDateInMillisecondsSinceEpoch / 1000),
|
|
295
|
-
expiration.policy === "subdomain:follow-domain" ? 1 : 0,
|
|
296
|
-
!!transferable,
|
|
297
|
-
targetAddress,
|
|
298
|
-
toAddress,
|
|
299
|
-
],
|
|
300
|
-
},
|
|
301
|
-
options,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
return transaction;
|
|
275
|
+
// Movement's MNS contract uses a key staking mechanism for subdomains instead of
|
|
276
|
+
// a direct register_subdomain function. The router has stake_key_for_subdomain,
|
|
277
|
+
// unstake_key_for_subdomain, and buy_and_stake_key_for_subdomain functions.
|
|
278
|
+
// This is different from Aptos ANS which has register_subdomain.
|
|
279
|
+
//
|
|
280
|
+
// For now, subdomain registration is not supported via this SDK.
|
|
281
|
+
// Users who need subdomain functionality should interact with the contract directly
|
|
282
|
+
// using the key staking functions.
|
|
283
|
+
throw new Error(
|
|
284
|
+
"Subdomain registration is not currently supported on Movement. " +
|
|
285
|
+
"Movement's MNS contract uses a key staking mechanism for subdomains. " +
|
|
286
|
+
"See the router module's stake_key_for_subdomain and buy_and_stake_key_for_subdomain functions."
|
|
287
|
+
);
|
|
305
288
|
}
|
|
306
289
|
|
|
307
290
|
/**
|
|
@@ -316,7 +299,7 @@ export async function registerName(args: RegisterNameParameters): Promise<Simple
|
|
|
316
299
|
export async function getExpiration(args: { movementConfig: MovementConfig; name: string }): Promise<number | undefined> {
|
|
317
300
|
const { movementConfig, name } = args;
|
|
318
301
|
const routerAddress = getRouterAddress(movementConfig);
|
|
319
|
-
const { domainName, subdomainName } =
|
|
302
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
320
303
|
|
|
321
304
|
try {
|
|
322
305
|
const res = await view({
|
|
@@ -402,7 +385,7 @@ export async function setPrimaryName(args: {
|
|
|
402
385
|
return transaction;
|
|
403
386
|
}
|
|
404
387
|
|
|
405
|
-
const { domainName, subdomainName } =
|
|
388
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
406
389
|
|
|
407
390
|
const transaction = await generateTransaction({
|
|
408
391
|
movementConfig,
|
|
@@ -434,7 +417,7 @@ export async function getTargetAddress(args: {
|
|
|
434
417
|
}): Promise<AccountAddress | undefined> {
|
|
435
418
|
const { movementConfig, name } = args;
|
|
436
419
|
const routerAddress = getRouterAddress(movementConfig);
|
|
437
|
-
const { domainName, subdomainName } =
|
|
420
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
438
421
|
|
|
439
422
|
const res = await view({
|
|
440
423
|
movementConfig,
|
|
@@ -471,7 +454,7 @@ export async function setTargetAddress(args: {
|
|
|
471
454
|
}): Promise<SimpleTransaction> {
|
|
472
455
|
const { movementConfig, sender, name, address, options } = args;
|
|
473
456
|
const routerAddress = getRouterAddress(movementConfig);
|
|
474
|
-
const { domainName, subdomainName } =
|
|
457
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
475
458
|
|
|
476
459
|
const transaction = await generateTransaction({
|
|
477
460
|
movementConfig,
|
|
@@ -498,9 +481,9 @@ export async function setTargetAddress(args: {
|
|
|
498
481
|
export async function getName(args: {
|
|
499
482
|
movementConfig: MovementConfig;
|
|
500
483
|
name: string;
|
|
501
|
-
}): Promise<
|
|
484
|
+
}): Promise<GetMNSNameResponse[0] | undefined> {
|
|
502
485
|
const { movementConfig, name } = args;
|
|
503
|
-
const { domainName, subdomainName = "" } =
|
|
486
|
+
const { domainName, subdomainName = "" } = isValidMNSName(name);
|
|
504
487
|
|
|
505
488
|
const where: CurrentAptosNamesBoolExp = {
|
|
506
489
|
domain: { _eq: domainName },
|
|
@@ -522,10 +505,10 @@ export async function getName(args: {
|
|
|
522
505
|
// Convert the expiration_timestamp from an ISO string to milliseconds since epoch
|
|
523
506
|
let res = data.current_aptos_names[0];
|
|
524
507
|
if (res) {
|
|
525
|
-
res =
|
|
508
|
+
res = sanitizeMNSName(res);
|
|
526
509
|
}
|
|
527
510
|
|
|
528
|
-
return
|
|
511
|
+
return isActiveMNSName(res) ? res : undefined;
|
|
529
512
|
}
|
|
530
513
|
|
|
531
514
|
/**
|
|
@@ -535,7 +518,7 @@ export async function getName(args: {
|
|
|
535
518
|
* @group Implementation
|
|
536
519
|
*/
|
|
537
520
|
interface QueryNamesOptions {
|
|
538
|
-
options?: PaginationArgs & OrderByArg<
|
|
521
|
+
options?: PaginationArgs & OrderByArg<GetMNSNameResponse[0]> & WhereArg<CurrentAptosNamesBoolExp>;
|
|
539
522
|
}
|
|
540
523
|
|
|
541
524
|
/**
|
|
@@ -566,10 +549,10 @@ export interface GetAccountNamesArgs extends QueryNamesOptions {
|
|
|
566
549
|
*/
|
|
567
550
|
export async function getAccountNames(
|
|
568
551
|
args: { movementConfig: MovementConfig } & GetAccountNamesArgs,
|
|
569
|
-
): Promise<
|
|
552
|
+
): Promise<GetMNSNameResponse> {
|
|
570
553
|
const { movementConfig, options, accountAddress } = args;
|
|
571
554
|
|
|
572
|
-
const expirationDate = await
|
|
555
|
+
const expirationDate = await getMNSExpirationDate({ movementConfig });
|
|
573
556
|
|
|
574
557
|
const data = await queryIndexer<GetNamesQuery>({
|
|
575
558
|
movementConfig,
|
|
@@ -589,7 +572,7 @@ export async function getAccountNames(
|
|
|
589
572
|
},
|
|
590
573
|
});
|
|
591
574
|
|
|
592
|
-
return data.current_aptos_names.map(
|
|
575
|
+
return data.current_aptos_names.map(sanitizeMNSName);
|
|
593
576
|
}
|
|
594
577
|
|
|
595
578
|
/**
|
|
@@ -622,10 +605,10 @@ export interface GetAccountDomainsArgs extends QueryNamesOptions {
|
|
|
622
605
|
*/
|
|
623
606
|
export async function getAccountDomains(
|
|
624
607
|
args: { movementConfig: MovementConfig } & GetAccountDomainsArgs,
|
|
625
|
-
): Promise<
|
|
608
|
+
): Promise<GetMNSNameResponse> {
|
|
626
609
|
const { movementConfig, options, accountAddress } = args;
|
|
627
610
|
|
|
628
|
-
const expirationDate = await
|
|
611
|
+
const expirationDate = await getMNSExpirationDate({ movementConfig });
|
|
629
612
|
|
|
630
613
|
const data = await queryIndexer<GetNamesQuery>({
|
|
631
614
|
movementConfig,
|
|
@@ -646,7 +629,7 @@ export async function getAccountDomains(
|
|
|
646
629
|
},
|
|
647
630
|
});
|
|
648
631
|
|
|
649
|
-
return data.current_aptos_names.map(
|
|
632
|
+
return data.current_aptos_names.map(sanitizeMNSName);
|
|
650
633
|
}
|
|
651
634
|
|
|
652
635
|
/**
|
|
@@ -678,10 +661,10 @@ export interface GetAccountSubdomainsArgs extends QueryNamesOptions {
|
|
|
678
661
|
*/
|
|
679
662
|
export async function getAccountSubdomains(
|
|
680
663
|
args: { movementConfig: MovementConfig } & GetAccountSubdomainsArgs,
|
|
681
|
-
): Promise<
|
|
664
|
+
): Promise<GetMNSNameResponse> {
|
|
682
665
|
const { movementConfig, options, accountAddress } = args;
|
|
683
666
|
|
|
684
|
-
const expirationDate = await
|
|
667
|
+
const expirationDate = await getMNSExpirationDate({ movementConfig });
|
|
685
668
|
|
|
686
669
|
const data = await queryIndexer<GetNamesQuery>({
|
|
687
670
|
movementConfig,
|
|
@@ -702,7 +685,7 @@ export async function getAccountSubdomains(
|
|
|
702
685
|
},
|
|
703
686
|
});
|
|
704
687
|
|
|
705
|
-
return data.current_aptos_names.map(
|
|
688
|
+
return data.current_aptos_names.map(sanitizeMNSName);
|
|
706
689
|
}
|
|
707
690
|
|
|
708
691
|
/**
|
|
@@ -736,7 +719,7 @@ export interface GetDomainSubdomainsArgs extends QueryNamesOptions {
|
|
|
736
719
|
*/
|
|
737
720
|
export async function getDomainSubdomains(
|
|
738
721
|
args: { movementConfig: MovementConfig } & GetDomainSubdomainsArgs,
|
|
739
|
-
): Promise<
|
|
722
|
+
): Promise<GetMNSNameResponse> {
|
|
740
723
|
const { movementConfig, options, domain } = args;
|
|
741
724
|
|
|
742
725
|
const data = await queryIndexer<GetNamesQuery>({
|
|
@@ -757,7 +740,7 @@ export async function getDomainSubdomains(
|
|
|
757
740
|
},
|
|
758
741
|
});
|
|
759
742
|
|
|
760
|
-
return data.current_aptos_names.map(
|
|
743
|
+
return data.current_aptos_names.map(sanitizeMNSName).filter(isActiveMNSName);
|
|
761
744
|
}
|
|
762
745
|
|
|
763
746
|
/**
|
|
@@ -773,7 +756,7 @@ export async function getDomainSubdomains(
|
|
|
773
756
|
* @returns The expiration date in ISO 8601 format.
|
|
774
757
|
* @group Implementation
|
|
775
758
|
*/
|
|
776
|
-
async function
|
|
759
|
+
async function getMNSExpirationDate(args: { movementConfig: MovementConfig }): Promise<string> {
|
|
777
760
|
const { movementConfig } = args;
|
|
778
761
|
const routerAddress = getRouterAddress(movementConfig);
|
|
779
762
|
|
|
@@ -812,7 +795,7 @@ export async function renewDomain(args: {
|
|
|
812
795
|
const { movementConfig, sender, name, years = 1, options } = args;
|
|
813
796
|
const routerAddress = getRouterAddress(movementConfig);
|
|
814
797
|
const renewalDuration = years * 31536000;
|
|
815
|
-
const { domainName, subdomainName } =
|
|
798
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
816
799
|
|
|
817
800
|
if (subdomainName) {
|
|
818
801
|
throw new Error("Subdomains cannot be renewed");
|
|
@@ -841,13 +824,588 @@ export async function renewDomain(args: {
|
|
|
841
824
|
* milliseconds. In the future, if other properties need sanitization, this can
|
|
842
825
|
* be extended.
|
|
843
826
|
*
|
|
844
|
-
* @param name - The
|
|
827
|
+
* @param name - The MNS name response to sanitize.
|
|
845
828
|
* @param name.expiration_timestamp - The expiration timestamp in ISO string format.
|
|
846
829
|
* @group Implementation
|
|
847
830
|
*/
|
|
848
|
-
function
|
|
831
|
+
function sanitizeMNSName(name: GetMNSNameResponse[0]): GetMNSNameResponse[0] {
|
|
849
832
|
return {
|
|
850
833
|
...name,
|
|
851
834
|
expiration_timestamp: new Date(name.expiration_timestamp).getTime(),
|
|
852
835
|
};
|
|
853
836
|
}
|
|
837
|
+
|
|
838
|
+
// ============================================================================
|
|
839
|
+
// Subdomain Key Staking Functions
|
|
840
|
+
// ============================================================================
|
|
841
|
+
// Movement MNS uses a bonding curve mechanism for subdomains where users must
|
|
842
|
+
// buy and stake "keys" to own subdomains. These functions provide SDK support
|
|
843
|
+
// for this mechanism.
|
|
844
|
+
// ============================================================================
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Get the price to buy keys for a domain. Each domain has tradeable keys that
|
|
848
|
+
* follow a bonding curve - price increases as more keys are bought.
|
|
849
|
+
*
|
|
850
|
+
* @param args - The arguments for the function.
|
|
851
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
852
|
+
* @param args.domainName - The domain name to get the key price for.
|
|
853
|
+
* @param args.amount - The number of keys to get the price for (default: 1).
|
|
854
|
+
* @returns The price in octas to buy the specified number of keys.
|
|
855
|
+
* @group Implementation
|
|
856
|
+
*/
|
|
857
|
+
export async function getKeyBuyPrice(args: {
|
|
858
|
+
movementConfig: MovementConfig;
|
|
859
|
+
domainName: string;
|
|
860
|
+
amount?: number;
|
|
861
|
+
}): Promise<bigint> {
|
|
862
|
+
const { movementConfig, domainName, amount = 1 } = args;
|
|
863
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
864
|
+
const { domainName: validatedDomain, subdomainName } = isValidMNSName(domainName);
|
|
865
|
+
|
|
866
|
+
if (subdomainName) {
|
|
867
|
+
throw new Error("Can only get key price for domains, not subdomains");
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Get the key address for the domain
|
|
871
|
+
// Response format: [{ vec: [{ metadata: { inner: "0x..." }, name, supply, symbol }] }]
|
|
872
|
+
const keyInfo = await view({
|
|
873
|
+
movementConfig,
|
|
874
|
+
payload: {
|
|
875
|
+
function: `${routerAddress}::key_manager::get_key_info_by_domain_name`,
|
|
876
|
+
functionArguments: [validatedDomain],
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
const keyData = (keyInfo[0] as any)?.vec?.[0];
|
|
881
|
+
const keyAddress = keyData?.metadata?.inner;
|
|
882
|
+
if (!keyAddress) {
|
|
883
|
+
throw new Error(`No key found for domain ${validatedDomain}. Keys are created when the first subdomain is registered.`);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
const res = await view({
|
|
887
|
+
movementConfig,
|
|
888
|
+
payload: {
|
|
889
|
+
function: `${routerAddress}::key_manager::get_buy_price_after_fee`,
|
|
890
|
+
functionArguments: [keyAddress, amount],
|
|
891
|
+
},
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
return BigInt(res[0] as string);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* Get the price when selling keys for a domain.
|
|
899
|
+
*
|
|
900
|
+
* @param args - The arguments for the function.
|
|
901
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
902
|
+
* @param args.domainName - The domain name to get the sell price for.
|
|
903
|
+
* @param args.amount - The number of keys to get the price for (default: 1).
|
|
904
|
+
* @returns The price in octas received when selling the specified number of keys.
|
|
905
|
+
* @group Implementation
|
|
906
|
+
*/
|
|
907
|
+
export async function getKeySellPrice(args: {
|
|
908
|
+
movementConfig: MovementConfig;
|
|
909
|
+
domainName: string;
|
|
910
|
+
amount?: number;
|
|
911
|
+
}): Promise<bigint> {
|
|
912
|
+
const { movementConfig, domainName, amount = 1 } = args;
|
|
913
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
914
|
+
const { domainName: validatedDomain, subdomainName } = isValidMNSName(domainName);
|
|
915
|
+
|
|
916
|
+
if (subdomainName) {
|
|
917
|
+
throw new Error("Can only get key price for domains, not subdomains");
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Get the key address for the domain
|
|
921
|
+
// Response format: [{ vec: [{ metadata: { inner: "0x..." }, name, supply, symbol }] }]
|
|
922
|
+
const keyInfo = await view({
|
|
923
|
+
movementConfig,
|
|
924
|
+
payload: {
|
|
925
|
+
function: `${routerAddress}::key_manager::get_key_info_by_domain_name`,
|
|
926
|
+
functionArguments: [validatedDomain],
|
|
927
|
+
},
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
const keyData = (keyInfo[0] as any)?.vec?.[0];
|
|
931
|
+
const keyAddress = keyData?.metadata?.inner;
|
|
932
|
+
if (!keyAddress) {
|
|
933
|
+
throw new Error(`No key found for domain ${validatedDomain}. Keys are created when the first subdomain is registered.`);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
const res = await view({
|
|
937
|
+
movementConfig,
|
|
938
|
+
payload: {
|
|
939
|
+
function: `${routerAddress}::key_manager::get_sell_price_after_fee`,
|
|
940
|
+
functionArguments: [keyAddress, amount],
|
|
941
|
+
},
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
return BigInt(res[0] as string);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Parameters for subdomain key staking operations.
|
|
949
|
+
* @group Implementation
|
|
950
|
+
*/
|
|
951
|
+
export interface SubdomainKeyStakingParams {
|
|
952
|
+
movementConfig: MovementConfig;
|
|
953
|
+
sender: Account;
|
|
954
|
+
domainName: string;
|
|
955
|
+
subdomainName: string;
|
|
956
|
+
/** The address that this subdomain will resolve to (optional, defaults to sender) */
|
|
957
|
+
targetAddress?: AccountAddressInput;
|
|
958
|
+
/** The address that will own this subdomain (optional, defaults to sender) */
|
|
959
|
+
toAddress?: AccountAddressInput;
|
|
960
|
+
options?: InputGenerateTransactionOptions;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Buy a key for a domain and stake it to claim a subdomain in one transaction.
|
|
965
|
+
* This is the primary way to register a subdomain on Movement.
|
|
966
|
+
*
|
|
967
|
+
* The price follows a bonding curve - use getKeyBuyPrice() to check the current price.
|
|
968
|
+
*
|
|
969
|
+
* @param args - The arguments for the function.
|
|
970
|
+
* @returns A transaction object to be signed and submitted.
|
|
971
|
+
* @group Implementation
|
|
972
|
+
*/
|
|
973
|
+
export async function buyAndStakeKeyForSubdomain(
|
|
974
|
+
args: SubdomainKeyStakingParams & { referrer?: AccountAddressInput },
|
|
975
|
+
): Promise<SimpleTransaction> {
|
|
976
|
+
const { movementConfig, sender, domainName, subdomainName, targetAddress, toAddress, referrer, options } = args;
|
|
977
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
978
|
+
|
|
979
|
+
// Validate the names
|
|
980
|
+
const { domainName: validatedDomain } = isValidMNSName(domainName);
|
|
981
|
+
if (!isValidMNSSegment(subdomainName)) {
|
|
982
|
+
throw new Error(`Invalid subdomain name: ${subdomainName}. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// Optional addresses - pass null for empty options, the SDK will handle MoveOption conversion
|
|
986
|
+
const targetOpt = targetAddress ? AccountAddress.from(targetAddress).toString() : null;
|
|
987
|
+
const toOpt = toAddress ? AccountAddress.from(toAddress).toString() : null;
|
|
988
|
+
const referrerOpt = referrer ? AccountAddress.from(referrer).toString() : null;
|
|
989
|
+
|
|
990
|
+
const transaction = await generateTransaction({
|
|
991
|
+
movementConfig,
|
|
992
|
+
sender: sender.accountAddress.toString(),
|
|
993
|
+
data: {
|
|
994
|
+
function: `${routerAddress}::router::buy_and_stake_key_for_subdomain`,
|
|
995
|
+
functionArguments: [validatedDomain, subdomainName, targetOpt, toOpt, referrerOpt],
|
|
996
|
+
},
|
|
997
|
+
options,
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
return transaction;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Stake an existing key to claim a subdomain. You must already own a key for
|
|
1005
|
+
* the parent domain (obtained via buyAndStakeKeyForSubdomain or by buying keys directly).
|
|
1006
|
+
*
|
|
1007
|
+
* @param args - The arguments for the function.
|
|
1008
|
+
* @returns A transaction object to be signed and submitted.
|
|
1009
|
+
* @group Implementation
|
|
1010
|
+
*/
|
|
1011
|
+
export async function stakeKeyForSubdomain(args: SubdomainKeyStakingParams): Promise<SimpleTransaction> {
|
|
1012
|
+
const { movementConfig, sender, domainName, subdomainName, targetAddress, toAddress, options } = args;
|
|
1013
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1014
|
+
|
|
1015
|
+
// Validate the names
|
|
1016
|
+
const { domainName: validatedDomain } = isValidMNSName(domainName);
|
|
1017
|
+
if (!isValidMNSSegment(subdomainName)) {
|
|
1018
|
+
throw new Error(`Invalid subdomain name: ${subdomainName}. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// Optional addresses - pass null for empty options
|
|
1022
|
+
const targetOpt = targetAddress ? AccountAddress.from(targetAddress).toString() : null;
|
|
1023
|
+
const toOpt = toAddress ? AccountAddress.from(toAddress).toString() : null;
|
|
1024
|
+
|
|
1025
|
+
const transaction = await generateTransaction({
|
|
1026
|
+
movementConfig,
|
|
1027
|
+
sender: sender.accountAddress.toString(),
|
|
1028
|
+
data: {
|
|
1029
|
+
function: `${routerAddress}::router::stake_key_for_subdomain`,
|
|
1030
|
+
functionArguments: [validatedDomain, subdomainName, targetOpt, toOpt],
|
|
1031
|
+
},
|
|
1032
|
+
options,
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
return transaction;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Unstake a key from a subdomain, giving up ownership but keeping the key.
|
|
1040
|
+
* You can sell the key later or stake it for a different subdomain.
|
|
1041
|
+
*
|
|
1042
|
+
* @param args - The arguments for the function.
|
|
1043
|
+
* @returns A transaction object to be signed and submitted.
|
|
1044
|
+
* @group Implementation
|
|
1045
|
+
*/
|
|
1046
|
+
export async function unstakeKeyForSubdomain(args: {
|
|
1047
|
+
movementConfig: MovementConfig;
|
|
1048
|
+
sender: Account;
|
|
1049
|
+
domainName: string;
|
|
1050
|
+
subdomainName: string;
|
|
1051
|
+
options?: InputGenerateTransactionOptions;
|
|
1052
|
+
}): Promise<SimpleTransaction> {
|
|
1053
|
+
const { movementConfig, sender, domainName, subdomainName, options } = args;
|
|
1054
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1055
|
+
|
|
1056
|
+
// Validate the names
|
|
1057
|
+
const { domainName: validatedDomain } = isValidMNSName(domainName);
|
|
1058
|
+
if (!isValidMNSSegment(subdomainName)) {
|
|
1059
|
+
throw new Error(`Invalid subdomain name: ${subdomainName}. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const transaction = await generateTransaction({
|
|
1063
|
+
movementConfig,
|
|
1064
|
+
sender: sender.accountAddress.toString(),
|
|
1065
|
+
data: {
|
|
1066
|
+
function: `${routerAddress}::router::unstake_key_for_subdomain`,
|
|
1067
|
+
functionArguments: [validatedDomain, subdomainName],
|
|
1068
|
+
},
|
|
1069
|
+
options,
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
return transaction;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Unstake a key from a subdomain and sell it in one transaction.
|
|
1077
|
+
* This gives up the subdomain and converts the key back to MOVE tokens.
|
|
1078
|
+
*
|
|
1079
|
+
* @param args - The arguments for the function.
|
|
1080
|
+
* @returns A transaction object to be signed and submitted.
|
|
1081
|
+
* @group Implementation
|
|
1082
|
+
*/
|
|
1083
|
+
export async function unstakeAndSellKeyForSubdomain(args: {
|
|
1084
|
+
movementConfig: MovementConfig;
|
|
1085
|
+
sender: Account;
|
|
1086
|
+
domainName: string;
|
|
1087
|
+
subdomainName: string;
|
|
1088
|
+
referrer?: AccountAddressInput;
|
|
1089
|
+
options?: InputGenerateTransactionOptions;
|
|
1090
|
+
}): Promise<SimpleTransaction> {
|
|
1091
|
+
const { movementConfig, sender, domainName, subdomainName, referrer, options } = args;
|
|
1092
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1093
|
+
|
|
1094
|
+
// Validate the names
|
|
1095
|
+
const { domainName: validatedDomain } = isValidMNSName(domainName);
|
|
1096
|
+
if (!isValidMNSSegment(subdomainName)) {
|
|
1097
|
+
throw new Error(`Invalid subdomain name: ${subdomainName}. ${VALIDATION_RULES_DESCRIPTION}`);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
const referrerOpt = referrer ? AccountAddress.from(referrer).toString() : null;
|
|
1101
|
+
|
|
1102
|
+
const transaction = await generateTransaction({
|
|
1103
|
+
movementConfig,
|
|
1104
|
+
sender: sender.accountAddress.toString(),
|
|
1105
|
+
data: {
|
|
1106
|
+
function: `${routerAddress}::router::unstake_and_sell_key_for_subdomain`,
|
|
1107
|
+
functionArguments: [validatedDomain, subdomainName, referrerOpt],
|
|
1108
|
+
},
|
|
1109
|
+
options,
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
return transaction;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// ============================================================================
|
|
1116
|
+
// Additional Router Functions
|
|
1117
|
+
// ============================================================================
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Check if a name (domain or subdomain) is available for registration.
|
|
1121
|
+
*
|
|
1122
|
+
* @param args - The arguments for the function.
|
|
1123
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1124
|
+
* @param args.name - The name to check (e.g., "test" or "sub.test").
|
|
1125
|
+
* @param args.account - The account address that would register the name.
|
|
1126
|
+
* @returns True if the name can be registered by the account, false otherwise.
|
|
1127
|
+
* @group Implementation
|
|
1128
|
+
*/
|
|
1129
|
+
export async function canRegister(args: {
|
|
1130
|
+
movementConfig: MovementConfig;
|
|
1131
|
+
name: string;
|
|
1132
|
+
account: AccountAddressInput;
|
|
1133
|
+
}): Promise<boolean> {
|
|
1134
|
+
const { movementConfig, name, account } = args;
|
|
1135
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1136
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
1137
|
+
|
|
1138
|
+
const res = await view({
|
|
1139
|
+
movementConfig,
|
|
1140
|
+
payload: {
|
|
1141
|
+
function: `${routerAddress}::router::can_register`,
|
|
1142
|
+
functionArguments: [
|
|
1143
|
+
AccountAddress.from(account).toString(),
|
|
1144
|
+
domainName,
|
|
1145
|
+
subdomainName ?? null,
|
|
1146
|
+
],
|
|
1147
|
+
},
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
return res[0] as boolean;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Check if a specific address owns a name.
|
|
1155
|
+
*
|
|
1156
|
+
* @param args - The arguments for the function.
|
|
1157
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1158
|
+
* @param args.name - The name to check ownership of.
|
|
1159
|
+
* @param args.account - The account address to check.
|
|
1160
|
+
* @returns True if the account owns the name, false otherwise.
|
|
1161
|
+
* @group Implementation
|
|
1162
|
+
*/
|
|
1163
|
+
export async function isNameOwner(args: {
|
|
1164
|
+
movementConfig: MovementConfig;
|
|
1165
|
+
name: string;
|
|
1166
|
+
account: AccountAddressInput;
|
|
1167
|
+
}): Promise<boolean> {
|
|
1168
|
+
const { movementConfig, name, account } = args;
|
|
1169
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1170
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
1171
|
+
|
|
1172
|
+
const res = await view({
|
|
1173
|
+
movementConfig,
|
|
1174
|
+
payload: {
|
|
1175
|
+
function: `${routerAddress}::router::is_name_owner`,
|
|
1176
|
+
functionArguments: [
|
|
1177
|
+
AccountAddress.from(account).toString(),
|
|
1178
|
+
domainName,
|
|
1179
|
+
subdomainName ?? null,
|
|
1180
|
+
],
|
|
1181
|
+
},
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
return res[0] as boolean;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Get the NFT token address for a domain or subdomain.
|
|
1189
|
+
*
|
|
1190
|
+
* @param args - The arguments for the function.
|
|
1191
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1192
|
+
* @param args.name - The name to get the token address for.
|
|
1193
|
+
* @returns The token address, or undefined if the name doesn't exist.
|
|
1194
|
+
* @group Implementation
|
|
1195
|
+
*/
|
|
1196
|
+
export async function getTokenAddress(args: {
|
|
1197
|
+
movementConfig: MovementConfig;
|
|
1198
|
+
name: string;
|
|
1199
|
+
}): Promise<AccountAddress | undefined> {
|
|
1200
|
+
const { movementConfig, name } = args;
|
|
1201
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1202
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
1203
|
+
|
|
1204
|
+
try {
|
|
1205
|
+
const res = await view({
|
|
1206
|
+
movementConfig,
|
|
1207
|
+
payload: {
|
|
1208
|
+
function: `${routerAddress}::router::get_token_addr`,
|
|
1209
|
+
functionArguments: [domainName, subdomainName ?? null],
|
|
1210
|
+
},
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
// Response is directly the address, not wrapped in Option
|
|
1214
|
+
const tokenAddr = res[0] as MoveAddressType;
|
|
1215
|
+
return tokenAddr ? AccountAddress.from(tokenAddr) : undefined;
|
|
1216
|
+
} catch {
|
|
1217
|
+
// Contract throws if name doesn't exist
|
|
1218
|
+
return undefined;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Clear the target address for a domain or subdomain, stopping it from resolving.
|
|
1224
|
+
*
|
|
1225
|
+
* @param args - The arguments for the function.
|
|
1226
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1227
|
+
* @param args.sender - The account that owns the name.
|
|
1228
|
+
* @param args.name - The name to clear the target address for.
|
|
1229
|
+
* @param args.options - Optional transaction options.
|
|
1230
|
+
* @returns A transaction object to be signed and submitted.
|
|
1231
|
+
* @group Implementation
|
|
1232
|
+
*/
|
|
1233
|
+
export async function clearTargetAddress(args: {
|
|
1234
|
+
movementConfig: MovementConfig;
|
|
1235
|
+
sender: Account;
|
|
1236
|
+
name: string;
|
|
1237
|
+
options?: InputGenerateTransactionOptions;
|
|
1238
|
+
}): Promise<SimpleTransaction> {
|
|
1239
|
+
const { movementConfig, sender, name, options } = args;
|
|
1240
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1241
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
1242
|
+
|
|
1243
|
+
const transaction = await generateTransaction({
|
|
1244
|
+
movementConfig,
|
|
1245
|
+
sender: sender.accountAddress.toString(),
|
|
1246
|
+
data: {
|
|
1247
|
+
function: `${routerAddress}::router::clear_target_addr`,
|
|
1248
|
+
functionArguments: [domainName, subdomainName ?? null],
|
|
1249
|
+
},
|
|
1250
|
+
options,
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
return transaction;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Buy keys for a domain without staking them for a subdomain.
|
|
1258
|
+
* Keys can be held for speculation or staked later via stakeKeyForSubdomain.
|
|
1259
|
+
*
|
|
1260
|
+
* @param args - The arguments for the function.
|
|
1261
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1262
|
+
* @param args.sender - The account buying the keys.
|
|
1263
|
+
* @param args.domainName - The domain to buy keys for.
|
|
1264
|
+
* @param args.amount - The number of keys to buy.
|
|
1265
|
+
* @param args.referrer - Optional referrer address for fee sharing.
|
|
1266
|
+
* @param args.options - Optional transaction options.
|
|
1267
|
+
* @returns A transaction object to be signed and submitted.
|
|
1268
|
+
* @group Implementation
|
|
1269
|
+
*/
|
|
1270
|
+
export async function buyKeys(args: {
|
|
1271
|
+
movementConfig: MovementConfig;
|
|
1272
|
+
sender: Account;
|
|
1273
|
+
domainName: string;
|
|
1274
|
+
amount: number;
|
|
1275
|
+
referrer?: AccountAddressInput;
|
|
1276
|
+
options?: InputGenerateTransactionOptions;
|
|
1277
|
+
}): Promise<SimpleTransaction> {
|
|
1278
|
+
const { movementConfig, sender, domainName, amount, referrer, options } = args;
|
|
1279
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1280
|
+
const { domainName: validatedDomain, subdomainName } = isValidMNSName(domainName);
|
|
1281
|
+
|
|
1282
|
+
if (subdomainName) {
|
|
1283
|
+
throw new Error("Can only buy keys for domains, not subdomains");
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// Get the key address for the domain
|
|
1287
|
+
const keyInfo = await view({
|
|
1288
|
+
movementConfig,
|
|
1289
|
+
payload: {
|
|
1290
|
+
function: `${routerAddress}::key_manager::get_key_info_by_domain_name`,
|
|
1291
|
+
functionArguments: [validatedDomain],
|
|
1292
|
+
},
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
const keyData = (keyInfo[0] as any)?.vec?.[0];
|
|
1296
|
+
const keyAddress = keyData?.metadata?.inner;
|
|
1297
|
+
if (!keyAddress) {
|
|
1298
|
+
throw new Error(`No key found for domain ${validatedDomain}. Keys are created when the first subdomain is registered.`);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
const referrerOpt = referrer ? AccountAddress.from(referrer).toString() : null;
|
|
1302
|
+
|
|
1303
|
+
const transaction = await generateTransaction({
|
|
1304
|
+
movementConfig,
|
|
1305
|
+
sender: sender.accountAddress.toString(),
|
|
1306
|
+
data: {
|
|
1307
|
+
function: `${routerAddress}::router::buy_keys`,
|
|
1308
|
+
functionArguments: [keyAddress, amount, referrerOpt],
|
|
1309
|
+
},
|
|
1310
|
+
options,
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
return transaction;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Sell keys for a domain back to the bonding curve.
|
|
1318
|
+
*
|
|
1319
|
+
* @param args - The arguments for the function.
|
|
1320
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1321
|
+
* @param args.sender - The account selling the keys.
|
|
1322
|
+
* @param args.domainName - The domain to sell keys for.
|
|
1323
|
+
* @param args.amount - The number of keys to sell.
|
|
1324
|
+
* @param args.referrer - Optional referrer address for fee sharing.
|
|
1325
|
+
* @param args.options - Optional transaction options.
|
|
1326
|
+
* @returns A transaction object to be signed and submitted.
|
|
1327
|
+
* @group Implementation
|
|
1328
|
+
*/
|
|
1329
|
+
export async function sellKeys(args: {
|
|
1330
|
+
movementConfig: MovementConfig;
|
|
1331
|
+
sender: Account;
|
|
1332
|
+
domainName: string;
|
|
1333
|
+
amount: number;
|
|
1334
|
+
referrer?: AccountAddressInput;
|
|
1335
|
+
options?: InputGenerateTransactionOptions;
|
|
1336
|
+
}): Promise<SimpleTransaction> {
|
|
1337
|
+
const { movementConfig, sender, domainName, amount, referrer, options } = args;
|
|
1338
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1339
|
+
const { domainName: validatedDomain, subdomainName } = isValidMNSName(domainName);
|
|
1340
|
+
|
|
1341
|
+
if (subdomainName) {
|
|
1342
|
+
throw new Error("Can only sell keys for domains, not subdomains");
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// Get the key address for the domain
|
|
1346
|
+
const keyInfo = await view({
|
|
1347
|
+
movementConfig,
|
|
1348
|
+
payload: {
|
|
1349
|
+
function: `${routerAddress}::key_manager::get_key_info_by_domain_name`,
|
|
1350
|
+
functionArguments: [validatedDomain],
|
|
1351
|
+
},
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
const keyData = (keyInfo[0] as any)?.vec?.[0];
|
|
1355
|
+
const keyAddress = keyData?.metadata?.inner;
|
|
1356
|
+
if (!keyAddress) {
|
|
1357
|
+
throw new Error(`No key found for domain ${validatedDomain}.`);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
const referrerOpt = referrer ? AccountAddress.from(referrer).toString() : null;
|
|
1361
|
+
|
|
1362
|
+
const transaction = await generateTransaction({
|
|
1363
|
+
movementConfig,
|
|
1364
|
+
sender: sender.accountAddress.toString(),
|
|
1365
|
+
data: {
|
|
1366
|
+
function: `${routerAddress}::router::sell_keys`,
|
|
1367
|
+
functionArguments: [keyAddress, amount, referrerOpt],
|
|
1368
|
+
},
|
|
1369
|
+
options,
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1372
|
+
return transaction;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
/**
|
|
1376
|
+
* Get the registration price for a domain name.
|
|
1377
|
+
* Price varies based on domain length and registration duration.
|
|
1378
|
+
*
|
|
1379
|
+
* @param args - The arguments for the function.
|
|
1380
|
+
* @param args.movementConfig - The configuration object for Movement.
|
|
1381
|
+
* @param args.name - The domain name to get the price for.
|
|
1382
|
+
* @param args.years - Number of years to register (default: 1).
|
|
1383
|
+
* @returns The price in octas to register the domain.
|
|
1384
|
+
* @group Implementation
|
|
1385
|
+
*/
|
|
1386
|
+
export async function getDomainPrice(args: {
|
|
1387
|
+
movementConfig: MovementConfig;
|
|
1388
|
+
name: string;
|
|
1389
|
+
years?: number;
|
|
1390
|
+
}): Promise<bigint> {
|
|
1391
|
+
const { movementConfig, name, years = 1 } = args;
|
|
1392
|
+
const routerAddress = getRouterAddress(movementConfig);
|
|
1393
|
+
const { domainName, subdomainName } = isValidMNSName(name);
|
|
1394
|
+
|
|
1395
|
+
if (subdomainName) {
|
|
1396
|
+
throw new Error("Can only get price for domains, not subdomains. Subdomains use key staking.");
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
const secondsPerYear = 31536000;
|
|
1400
|
+
const registrationSeconds = years * secondsPerYear;
|
|
1401
|
+
|
|
1402
|
+
const res = await view({
|
|
1403
|
+
movementConfig,
|
|
1404
|
+
payload: {
|
|
1405
|
+
function: `${routerAddress}::price_model_v2::price_for_domain`,
|
|
1406
|
+
functionArguments: [domainName, registrationSeconds],
|
|
1407
|
+
},
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
return BigInt(res[0] as string);
|
|
1411
|
+
}
|