@btc-vision/cli 1.0.9 → 1.0.11
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/build/commands/AcceptCommand.js +2 -2
- package/build/commands/DeprecateCommand.js +2 -2
- package/build/commands/DomainCommand.js +50 -18
- package/build/commands/PublishCommand.js +2 -2
- package/build/commands/ScopeRegisterCommand.js +1 -1
- package/build/commands/TransferCommand.js +4 -4
- package/build/commands/UndeprecateCommand.js +2 -2
- package/build/commands/WebsiteDeployCommand.js +3 -3
- package/build/commands/WebsitePublishCommand.js +2 -2
- package/build/lib/BtcResolver.abi.js +22 -0
- package/build/lib/config.js +1 -1
- package/build/lib/ipfs.d.ts +4 -1
- package/build/lib/ipfs.js +257 -56
- package/build/lib/resolver.js +2 -2
- package/build/types/BtcResolver.d.ts +25 -2
- package/build/types/BtcResolver.js +158 -2
- package/package.json +1 -1
|
@@ -75,7 +75,7 @@ export class AcceptCommand extends BaseCommand {
|
|
|
75
75
|
process.exit(1);
|
|
76
76
|
}
|
|
77
77
|
if (acceptResult.estimatedGas) {
|
|
78
|
-
this.logger.info(`Estimated gas: ${acceptResult.estimatedGas}
|
|
78
|
+
this.logger.info(`Estimated gas: ${acceptResult.estimatedGas} gas`);
|
|
79
79
|
}
|
|
80
80
|
const receipt = await acceptResult.sendTransaction(txParams);
|
|
81
81
|
this.logger.log('');
|
|
@@ -132,7 +132,7 @@ export class AcceptCommand extends BaseCommand {
|
|
|
132
132
|
process.exit(1);
|
|
133
133
|
}
|
|
134
134
|
if (acceptResult.estimatedGas) {
|
|
135
|
-
this.logger.info(`Estimated gas: ${acceptResult.estimatedGas}
|
|
135
|
+
this.logger.info(`Estimated gas: ${acceptResult.estimatedGas} gas`);
|
|
136
136
|
}
|
|
137
137
|
const receipt = await acceptResult.sendTransaction(txParams);
|
|
138
138
|
this.logger.log('');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { confirm, input } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { getPackage, getRegistryContract, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
3
|
+
import { getPackage, getRegistryContract, getVersion, isVersionImmutable, } from '../lib/registry.js';
|
|
4
4
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
import { buildTransactionParams, checkBalance, formatSats, getWalletAddress, } from '../lib/transaction.js';
|
|
@@ -107,7 +107,7 @@ export class DeprecateCommand extends BaseCommand {
|
|
|
107
107
|
process.exit(1);
|
|
108
108
|
}
|
|
109
109
|
if (deprecateResult.estimatedGas) {
|
|
110
|
-
this.logger.info(`Estimated gas: ${deprecateResult.estimatedGas}
|
|
110
|
+
this.logger.info(`Estimated gas: ${deprecateResult.estimatedGas} gas`);
|
|
111
111
|
}
|
|
112
112
|
const receipt = await deprecateResult.sendTransaction(txParams);
|
|
113
113
|
this.logger.log('');
|
|
@@ -3,10 +3,50 @@ import { confirm } from '@inquirer/prompts';
|
|
|
3
3
|
import { Logger } from '@btc-vision/logger';
|
|
4
4
|
import { CLIWallet } from '../lib/wallet.js';
|
|
5
5
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getContenthash, getContenthashTypeName, getDomain, getDomainPrice, getResolverContract, getTreasuryAddress, parseDomainName, validateDomainName, } from '../lib/resolver.js';
|
|
7
|
+
import { DEFAULT_DOMAIN_PRICE_SATS, PREMIUM_TIER_0_PRICE_SATS, PREMIUM_TIER_1_PRICE_SATS, PREMIUM_TIER_2_PRICE_SATS, PREMIUM_TIER_3_PRICE_SATS, PREMIUM_TIER_4_PRICE_SATS, PREMIUM_TIER_5_PRICE_SATS, PREMIUM_TIER_6_PRICE_SATS, } from '../types/BtcResolver.js';
|
|
7
8
|
import { buildTransactionParams, checkBalance, DEFAULT_FEE_RATE, DEFAULT_MAX_SAT_TO_SPEND, formatSats, getWalletAddress, waitForTransactionConfirmation, } from '../lib/transaction.js';
|
|
8
9
|
import { TransactionOutputFlags } from 'opnet';
|
|
9
10
|
const logger = new Logger();
|
|
11
|
+
function getPricingTierName(price) {
|
|
12
|
+
if (price >= PREMIUM_TIER_0_PRICE_SATS) {
|
|
13
|
+
return {
|
|
14
|
+
tier: 'Ultra Legendary (Tier 0)',
|
|
15
|
+
description: '10 BTC - Iconic crypto/tech names',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (price >= PREMIUM_TIER_1_PRICE_SATS) {
|
|
19
|
+
return {
|
|
20
|
+
tier: 'Legendary (Tier 1)',
|
|
21
|
+
description: '1 BTC - Single character or top keywords',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (price >= PREMIUM_TIER_2_PRICE_SATS) {
|
|
25
|
+
return {
|
|
26
|
+
tier: 'Premium (Tier 2)',
|
|
27
|
+
description: '0.25 BTC - Two character or major protocols',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (price >= PREMIUM_TIER_3_PRICE_SATS) {
|
|
31
|
+
return {
|
|
32
|
+
tier: 'High Value (Tier 3)',
|
|
33
|
+
description: '0.1 BTC - Three character or valuable keywords',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (price >= PREMIUM_TIER_4_PRICE_SATS) {
|
|
37
|
+
return {
|
|
38
|
+
tier: 'Valuable (Tier 4)',
|
|
39
|
+
description: '0.05 BTC - Four character or common keywords',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (price >= PREMIUM_TIER_5_PRICE_SATS) {
|
|
43
|
+
return { tier: 'Common Premium (Tier 5)', description: '0.01 BTC - Five character domain' };
|
|
44
|
+
}
|
|
45
|
+
if (price >= PREMIUM_TIER_6_PRICE_SATS) {
|
|
46
|
+
return { tier: 'Notable (Tier 6)', description: '0.005 BTC - Notable keyword' };
|
|
47
|
+
}
|
|
48
|
+
return { tier: 'Standard', description: '0.001 BTC - Standard domain (6+ chars)' };
|
|
49
|
+
}
|
|
10
50
|
async function registerDomain(domain, options) {
|
|
11
51
|
try {
|
|
12
52
|
const network = (options.network || 'mainnet');
|
|
@@ -33,12 +73,11 @@ async function registerDomain(domain, options) {
|
|
|
33
73
|
logger.success(`Domain ${displayName} is available`);
|
|
34
74
|
const price = await getDomainPrice(name, network);
|
|
35
75
|
const treasuryAddr = await getTreasuryAddress(network);
|
|
76
|
+
const pricingTier = getPricingTierName(price);
|
|
36
77
|
logger.info(`Registration price: ${formatSats(price)}`);
|
|
37
|
-
if (
|
|
38
|
-
logger.warn(
|
|
39
|
-
|
|
40
|
-
else if (name.length === 4) {
|
|
41
|
-
logger.warn('Premium pricing applied (4-character domain)');
|
|
78
|
+
if (price > DEFAULT_DOMAIN_PRICE_SATS) {
|
|
79
|
+
logger.warn(`Premium pricing: ${pricingTier.tier}`);
|
|
80
|
+
logger.info(` ${pricingTier.description}`);
|
|
42
81
|
}
|
|
43
82
|
logger.info('Loading wallet...');
|
|
44
83
|
const credentials = loadCredentials();
|
|
@@ -109,7 +148,7 @@ async function registerDomain(domain, options) {
|
|
|
109
148
|
process.exit(1);
|
|
110
149
|
}
|
|
111
150
|
if (registerResult.estimatedGas) {
|
|
112
|
-
logger.info(`Estimated gas: ${registerResult.estimatedGas}
|
|
151
|
+
logger.info(`Estimated gas: ${registerResult.estimatedGas} gas`);
|
|
113
152
|
}
|
|
114
153
|
const txParams = buildTransactionParams(wallet, network, DEFAULT_MAX_SAT_TO_SPEND + price, DEFAULT_FEE_RATE, extraUtxo);
|
|
115
154
|
const receipt = await registerResult.sendTransaction(txParams);
|
|
@@ -160,21 +199,15 @@ async function domainInfo(domain, options) {
|
|
|
160
199
|
if (!domainData) {
|
|
161
200
|
logger.warn(`Domain ${displayName} is not registered`);
|
|
162
201
|
const price = await getDomainPrice(name, network);
|
|
202
|
+
const pricingTier = getPricingTierName(price);
|
|
163
203
|
logger.log('');
|
|
164
204
|
logger.info('Registration Info');
|
|
165
205
|
logger.log('-'.repeat(50));
|
|
166
206
|
logger.log(`Domain: ${displayName}`);
|
|
167
207
|
logger.log(`Status: Available`);
|
|
168
208
|
logger.log(`Price: ${formatSats(price)}`);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
else if (name.length === 4) {
|
|
173
|
-
logger.log(`Pricing tier: Premium (4-character)`);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
logger.log(`Pricing tier: Standard`);
|
|
177
|
-
}
|
|
209
|
+
logger.log(`Pricing tier: ${pricingTier.tier}`);
|
|
210
|
+
logger.log(` ${pricingTier.description}`);
|
|
178
211
|
logger.log('');
|
|
179
212
|
logger.info('Register with:');
|
|
180
213
|
logger.log(` opnet domain register ${name} -n ${network}`);
|
|
@@ -222,8 +255,7 @@ async function domainInfo(domain, options) {
|
|
|
222
255
|
process.exit(1);
|
|
223
256
|
}
|
|
224
257
|
}
|
|
225
|
-
const domainCommand = new Command('domain')
|
|
226
|
-
.description('Manage .btc domains');
|
|
258
|
+
const domainCommand = new Command('domain').description('Manage .btc domains');
|
|
227
259
|
domainCommand
|
|
228
260
|
.command('register')
|
|
229
261
|
.description('Register a new .btc domain')
|
|
@@ -160,7 +160,7 @@ export class PublishCommand extends BaseCommand {
|
|
|
160
160
|
process.exit(1);
|
|
161
161
|
}
|
|
162
162
|
if (registerResult.estimatedGas) {
|
|
163
|
-
this.logger.info(`Estimated gas: ${registerResult.estimatedGas}
|
|
163
|
+
this.logger.info(`Estimated gas: ${registerResult.estimatedGas} gas`);
|
|
164
164
|
}
|
|
165
165
|
const registerReceipt = await registerResult.sendTransaction(txParams);
|
|
166
166
|
this.logger.success('Package registration transaction sent');
|
|
@@ -191,7 +191,7 @@ export class PublishCommand extends BaseCommand {
|
|
|
191
191
|
process.exit(1);
|
|
192
192
|
}
|
|
193
193
|
if (publishResult.estimatedGas) {
|
|
194
|
-
this.logger.info(`Estimated gas: ${publishResult.estimatedGas}
|
|
194
|
+
this.logger.info(`Estimated gas: ${publishResult.estimatedGas} gas`);
|
|
195
195
|
}
|
|
196
196
|
const publishReceipt = await publishResult.sendTransaction(txParams);
|
|
197
197
|
this.logger.log('');
|
|
@@ -88,7 +88,7 @@ export class ScopeRegisterCommand extends BaseCommand {
|
|
|
88
88
|
process.exit(1);
|
|
89
89
|
}
|
|
90
90
|
if (registerResult.estimatedGas) {
|
|
91
|
-
this.logger.info(`Estimated gas: ${registerResult.estimatedGas}
|
|
91
|
+
this.logger.info(`Estimated gas: ${registerResult.estimatedGas} gas`);
|
|
92
92
|
}
|
|
93
93
|
const receipt = await registerResult.sendTransaction(txParams);
|
|
94
94
|
this.logger.log('');
|
|
@@ -111,7 +111,7 @@ export class TransferCommand extends BaseCommand {
|
|
|
111
111
|
process.exit(1);
|
|
112
112
|
}
|
|
113
113
|
if (transferResult.estimatedGas) {
|
|
114
|
-
this.logger.info(`Estimated gas: ${transferResult.estimatedGas}
|
|
114
|
+
this.logger.info(`Estimated gas: ${transferResult.estimatedGas} gas`);
|
|
115
115
|
}
|
|
116
116
|
const receipt = await transferResult.sendTransaction(txParams);
|
|
117
117
|
this.logger.log('');
|
|
@@ -132,7 +132,7 @@ export class TransferCommand extends BaseCommand {
|
|
|
132
132
|
process.exit(1);
|
|
133
133
|
}
|
|
134
134
|
if (transferResult.estimatedGas) {
|
|
135
|
-
this.logger.info(`Estimated gas: ${transferResult.estimatedGas}
|
|
135
|
+
this.logger.info(`Estimated gas: ${transferResult.estimatedGas} gas`);
|
|
136
136
|
}
|
|
137
137
|
const receipt = await transferResult.sendTransaction(txParams);
|
|
138
138
|
this.logger.log('');
|
|
@@ -203,7 +203,7 @@ export class TransferCommand extends BaseCommand {
|
|
|
203
203
|
process.exit(1);
|
|
204
204
|
}
|
|
205
205
|
if (cancelResult.estimatedGas) {
|
|
206
|
-
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas}
|
|
206
|
+
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas} gas`);
|
|
207
207
|
}
|
|
208
208
|
const receipt = await cancelResult.sendTransaction(txParams);
|
|
209
209
|
this.logger.log('');
|
|
@@ -251,7 +251,7 @@ export class TransferCommand extends BaseCommand {
|
|
|
251
251
|
process.exit(1);
|
|
252
252
|
}
|
|
253
253
|
if (cancelResult.estimatedGas) {
|
|
254
|
-
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas}
|
|
254
|
+
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas} gas`);
|
|
255
255
|
}
|
|
256
256
|
const receipt = await cancelResult.sendTransaction(txParams);
|
|
257
257
|
this.logger.log('');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { getPackage, getRegistryContract, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
3
|
+
import { getPackage, getRegistryContract, getVersion, isVersionImmutable, } from '../lib/registry.js';
|
|
4
4
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
import { buildTransactionParams, checkBalance, formatSats, getWalletAddress, } from '../lib/transaction.js';
|
|
@@ -91,7 +91,7 @@ export class UndeprecateCommand extends BaseCommand {
|
|
|
91
91
|
process.exit(1);
|
|
92
92
|
}
|
|
93
93
|
if (undeprecateResult.estimatedGas) {
|
|
94
|
-
this.logger.info(`Estimated gas: ${undeprecateResult.estimatedGas}
|
|
94
|
+
this.logger.info(`Estimated gas: ${undeprecateResult.estimatedGas} gas`);
|
|
95
95
|
}
|
|
96
96
|
const receipt = await undeprecateResult.sendTransaction(txParams);
|
|
97
97
|
this.logger.log('');
|
|
@@ -6,7 +6,7 @@ import { CLIWallet } from '../lib/wallet.js';
|
|
|
6
6
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
7
7
|
import { uploadDirectory, uploadFile } from '../lib/ipfs.js';
|
|
8
8
|
import { formatFileSize } from '../lib/binary.js';
|
|
9
|
-
import {
|
|
9
|
+
import { getContenthash, getContenthashTypeName, getDomain, getResolverContract, getSubdomain, isSubdomain, parseDomainName, } from '../lib/resolver.js';
|
|
10
10
|
import { buildTransactionParams, checkBalance, DEFAULT_FEE_RATE, DEFAULT_MAX_SAT_TO_SPEND, formatSats, getWalletAddress, waitForTransactionConfirmation, } from '../lib/transaction.js';
|
|
11
11
|
export class WebsiteDeployCommand extends BaseCommand {
|
|
12
12
|
constructor() {
|
|
@@ -17,7 +17,7 @@ export class WebsiteDeployCommand extends BaseCommand {
|
|
|
17
17
|
.argument('<domain>', 'Domain name (e.g., mysite or mysite.btc)')
|
|
18
18
|
.argument('<path>', 'Path to website directory or HTML file')
|
|
19
19
|
.option('-n, --network <network>', 'Network to use', 'mainnet')
|
|
20
|
-
.option('--dry-run',
|
|
20
|
+
.option('--dry-run', "Upload to IPFS but don't update on-chain")
|
|
21
21
|
.option('-y, --yes', 'Skip confirmation prompts')
|
|
22
22
|
.action((domain, websitePath, options) => this.execute(domain, websitePath, options || { network: 'mainnet' }));
|
|
23
23
|
}
|
|
@@ -144,7 +144,7 @@ export class WebsiteDeployCommand extends BaseCommand {
|
|
|
144
144
|
process.exit(1);
|
|
145
145
|
}
|
|
146
146
|
if (result.estimatedGas) {
|
|
147
|
-
this.logger.info(`Estimated gas: ${result.estimatedGas}
|
|
147
|
+
this.logger.info(`Estimated gas: ${result.estimatedGas} gas`);
|
|
148
148
|
}
|
|
149
149
|
const receipt = await result.sendTransaction(txParams);
|
|
150
150
|
this.logger.log('');
|
|
@@ -2,7 +2,7 @@ import { confirm } from '@inquirer/prompts';
|
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
3
|
import { CLIWallet } from '../lib/wallet.js';
|
|
4
4
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
|
-
import {
|
|
5
|
+
import { detectContenthashType, getContenthash, getContenthashTypeName, getDomain, getResolverContract, getSubdomain, isSubdomain, parseDomainName, validateCIDv0, validateCIDv1, validateIPNS, } from '../lib/resolver.js';
|
|
6
6
|
import { buildTransactionParams, checkBalance, DEFAULT_FEE_RATE, DEFAULT_MAX_SAT_TO_SPEND, formatSats, getWalletAddress, waitForTransactionConfirmation, } from '../lib/transaction.js';
|
|
7
7
|
import { CONTENTHASH_TYPE_CIDv0, CONTENTHASH_TYPE_CIDv1, CONTENTHASH_TYPE_IPNS, CONTENTHASH_TYPE_SHA256, } from '../types/BtcResolver.js';
|
|
8
8
|
export class WebsitePublishCommand extends BaseCommand {
|
|
@@ -188,7 +188,7 @@ export class WebsitePublishCommand extends BaseCommand {
|
|
|
188
188
|
process.exit(1);
|
|
189
189
|
}
|
|
190
190
|
if (result.estimatedGas) {
|
|
191
|
-
this.logger.info(`Estimated gas: ${result.estimatedGas}
|
|
191
|
+
this.logger.info(`Estimated gas: ${result.estimatedGas} gas`);
|
|
192
192
|
}
|
|
193
193
|
const receipt = await result.sendTransaction(txParams);
|
|
194
194
|
this.logger.log('');
|
|
@@ -40,6 +40,28 @@ export const BTC_RESOLVER_ABI = [
|
|
|
40
40
|
inputs: [{ name: 'domainName', type: ABIDataTypes.STRING }],
|
|
41
41
|
outputs: [],
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
name: 'transferDomain',
|
|
45
|
+
type: BitcoinAbiTypes.Function,
|
|
46
|
+
inputs: [
|
|
47
|
+
{ name: 'domainName', type: ABIDataTypes.STRING },
|
|
48
|
+
{ name: 'newOwner', type: ABIDataTypes.ADDRESS },
|
|
49
|
+
],
|
|
50
|
+
outputs: [],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'transferDomainBySignature',
|
|
54
|
+
type: BitcoinAbiTypes.Function,
|
|
55
|
+
inputs: [
|
|
56
|
+
{ name: 'ownerAddress', type: ABIDataTypes.BYTES32 },
|
|
57
|
+
{ name: 'ownerTweakedPublicKey', type: ABIDataTypes.BYTES32 },
|
|
58
|
+
{ name: 'domainName', type: ABIDataTypes.STRING },
|
|
59
|
+
{ name: 'newOwner', type: ABIDataTypes.ADDRESS },
|
|
60
|
+
{ name: 'deadline', type: ABIDataTypes.UINT64 },
|
|
61
|
+
{ name: 'signature', type: ABIDataTypes.BYTES },
|
|
62
|
+
],
|
|
63
|
+
outputs: [],
|
|
64
|
+
},
|
|
43
65
|
{
|
|
44
66
|
name: 'createSubdomain',
|
|
45
67
|
type: BitcoinAbiTypes.Function,
|
package/build/lib/config.js
CHANGED
|
@@ -24,7 +24,7 @@ export const DEFAULT_CONFIG = {
|
|
|
24
24
|
resolverAddresses: {
|
|
25
25
|
mainnet: '',
|
|
26
26
|
testnet: '',
|
|
27
|
-
regtest: '
|
|
27
|
+
regtest: '0x84da2929ee0e5f4ac84d6910150b9ede78f912847496f8689ffad16c6e44cbbe',
|
|
28
28
|
},
|
|
29
29
|
defaultMldsaLevel: 44,
|
|
30
30
|
indexerUrl: 'https://indexer.opnet.org',
|
package/build/lib/ipfs.d.ts
CHANGED
|
@@ -10,6 +10,9 @@ export declare function pinToIPFS(data: Buffer, name?: string): Promise<PinResul
|
|
|
10
10
|
export declare function fetchFromIPFS(cid: string): Promise<FetchResult>;
|
|
11
11
|
export declare function buildGatewayUrl(gateway: string, cid: string): string;
|
|
12
12
|
export declare function isValidCid(cid: string): boolean;
|
|
13
|
+
export declare function isCIDv0(cid: string): boolean;
|
|
14
|
+
export declare function isCIDv1(cid: string): boolean;
|
|
15
|
+
export declare function cidV0toV1(cidv0: string): string;
|
|
13
16
|
export declare function downloadPlugin(cid: string, outputPath: string): Promise<number>;
|
|
14
17
|
export declare function uploadPlugin(filePath: string): Promise<PinResult>;
|
|
15
18
|
export interface DirectoryPinResult {
|
|
@@ -17,5 +20,5 @@ export interface DirectoryPinResult {
|
|
|
17
20
|
files: number;
|
|
18
21
|
totalSize: number;
|
|
19
22
|
}
|
|
20
|
-
export declare function uploadDirectory(dirPath: string,
|
|
23
|
+
export declare function uploadDirectory(dirPath: string, _wrapWithDirectory?: boolean): Promise<DirectoryPinResult>;
|
|
21
24
|
export declare function uploadFile(filePath: string): Promise<PinResult>;
|
package/build/lib/ipfs.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as https from 'https';
|
|
2
2
|
import * as http from 'http';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
|
+
import ora from 'ora';
|
|
4
5
|
import { loadConfig } from './config.js';
|
|
5
6
|
const DEFAULT_MAX_REDIRECTS = 10;
|
|
6
7
|
async function httpRequest(url, options, redirectCount = 0) {
|
|
@@ -68,9 +69,37 @@ async function httpRequest(url, options, redirectCount = 0) {
|
|
|
68
69
|
reject(new Error('Request timeout'));
|
|
69
70
|
});
|
|
70
71
|
if (options.body) {
|
|
71
|
-
|
|
72
|
+
const bodyBuffer = Buffer.isBuffer(options.body) ? options.body : Buffer.from(options.body);
|
|
73
|
+
const totalBytes = bodyBuffer.length;
|
|
74
|
+
const chunkSize = 64 * 1024;
|
|
75
|
+
let bytesSent = 0;
|
|
76
|
+
const writeChunk = () => {
|
|
77
|
+
while (bytesSent < totalBytes) {
|
|
78
|
+
const end = Math.min(bytesSent + chunkSize, totalBytes);
|
|
79
|
+
const chunk = bodyBuffer.subarray(bytesSent, end);
|
|
80
|
+
const canContinue = req.write(chunk);
|
|
81
|
+
bytesSent += chunk.length;
|
|
82
|
+
if (options.onProgress) {
|
|
83
|
+
options.onProgress(bytesSent, totalBytes);
|
|
84
|
+
}
|
|
85
|
+
if (!canContinue) {
|
|
86
|
+
req.once('drain', writeChunk);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (options.onUploadComplete) {
|
|
91
|
+
options.onUploadComplete();
|
|
92
|
+
}
|
|
93
|
+
req.end();
|
|
94
|
+
};
|
|
95
|
+
writeChunk();
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
if (options.onUploadComplete) {
|
|
99
|
+
options.onUploadComplete();
|
|
100
|
+
}
|
|
101
|
+
req.end();
|
|
72
102
|
}
|
|
73
|
-
req.end();
|
|
74
103
|
});
|
|
75
104
|
}
|
|
76
105
|
export async function pinToIPFS(data, name) {
|
|
@@ -156,6 +185,9 @@ export async function pinToIPFS(data, name) {
|
|
|
156
185
|
if (!cid) {
|
|
157
186
|
throw new Error(`Failed to extract CID from pinning response: ${JSON.stringify(result)}`);
|
|
158
187
|
}
|
|
188
|
+
if (isCIDv0(cid)) {
|
|
189
|
+
cid = cidV0toV1(cid);
|
|
190
|
+
}
|
|
159
191
|
return {
|
|
160
192
|
cid,
|
|
161
193
|
size: data.length,
|
|
@@ -219,6 +251,73 @@ export function isValidCid(cid) {
|
|
|
219
251
|
}
|
|
220
252
|
return false;
|
|
221
253
|
}
|
|
254
|
+
export function isCIDv0(cid) {
|
|
255
|
+
return cid.startsWith('Qm') && cid.length === 46;
|
|
256
|
+
}
|
|
257
|
+
export function isCIDv1(cid) {
|
|
258
|
+
return cid.startsWith('baf') && cid.length >= 50;
|
|
259
|
+
}
|
|
260
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
261
|
+
const BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
262
|
+
function decodeBase58(str) {
|
|
263
|
+
const bytes = [];
|
|
264
|
+
for (const char of str) {
|
|
265
|
+
const value = BASE58_ALPHABET.indexOf(char);
|
|
266
|
+
if (value === -1) {
|
|
267
|
+
throw new Error(`Invalid base58 character: ${char}`);
|
|
268
|
+
}
|
|
269
|
+
let carry = value;
|
|
270
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
271
|
+
carry += bytes[i] * 58;
|
|
272
|
+
bytes[i] = carry & 0xff;
|
|
273
|
+
carry >>= 8;
|
|
274
|
+
}
|
|
275
|
+
while (carry > 0) {
|
|
276
|
+
bytes.push(carry & 0xff);
|
|
277
|
+
carry >>= 8;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const char of str) {
|
|
281
|
+
if (char === '1') {
|
|
282
|
+
bytes.push(0);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return new Uint8Array(bytes.reverse());
|
|
289
|
+
}
|
|
290
|
+
function encodeBase32(bytes) {
|
|
291
|
+
let result = '';
|
|
292
|
+
let bits = 0;
|
|
293
|
+
let value = 0;
|
|
294
|
+
for (const byte of bytes) {
|
|
295
|
+
value = (value << 8) | byte;
|
|
296
|
+
bits += 8;
|
|
297
|
+
while (bits >= 5) {
|
|
298
|
+
bits -= 5;
|
|
299
|
+
result += BASE32_ALPHABET[(value >> bits) & 0x1f];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (bits > 0) {
|
|
303
|
+
result += BASE32_ALPHABET[(value << (5 - bits)) & 0x1f];
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
export function cidV0toV1(cidv0) {
|
|
308
|
+
if (!isCIDv0(cidv0)) {
|
|
309
|
+
return cidv0;
|
|
310
|
+
}
|
|
311
|
+
const multihash = decodeBase58(cidv0);
|
|
312
|
+
if (multihash[0] !== 0x12 || multihash[1] !== 0x20 || multihash.length !== 34) {
|
|
313
|
+
throw new Error('Invalid CIDv0: not a valid sha2-256 multihash');
|
|
314
|
+
}
|
|
315
|
+
const cidv1Bytes = new Uint8Array(2 + multihash.length);
|
|
316
|
+
cidv1Bytes[0] = 0x01;
|
|
317
|
+
cidv1Bytes[1] = 0x70;
|
|
318
|
+
cidv1Bytes.set(multihash, 2);
|
|
319
|
+
return 'b' + encodeBase32(cidv1Bytes);
|
|
320
|
+
}
|
|
222
321
|
export async function downloadPlugin(cid, outputPath) {
|
|
223
322
|
const result = await fetchFromIPFS(cid);
|
|
224
323
|
fs.writeFileSync(outputPath, result.data);
|
|
@@ -272,74 +371,176 @@ function getMimeType(filePath) {
|
|
|
272
371
|
};
|
|
273
372
|
return mimeTypes[ext] || 'application/octet-stream';
|
|
274
373
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
374
|
+
function generateSessionId() {
|
|
375
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
376
|
+
const r = (Math.random() * 16) | 0;
|
|
377
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
378
|
+
return v.toString(16);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function sleep(ms) {
|
|
382
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
383
|
+
}
|
|
384
|
+
async function mfsCall(endpoint, apiPath, params, body, headers, maxRetries = 3) {
|
|
385
|
+
const url = new URL(endpoint);
|
|
386
|
+
url.pathname = apiPath;
|
|
387
|
+
for (const [key, value] of Object.entries(params)) {
|
|
388
|
+
url.searchParams.set(key, value);
|
|
389
|
+
}
|
|
390
|
+
const reqHeaders = {
|
|
391
|
+
...headers,
|
|
392
|
+
};
|
|
393
|
+
let formBody;
|
|
394
|
+
if (body) {
|
|
286
395
|
const boundary = '----FormBoundary' + Math.random().toString(36).substring(2);
|
|
287
396
|
const formParts = [];
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
const url = new URL(endpoint);
|
|
309
|
-
if (wrapWithDirectory) {
|
|
310
|
-
url.searchParams.set('wrap-with-directory', 'true');
|
|
397
|
+
formParts.push(Buffer.from(`--${boundary}\r\n` +
|
|
398
|
+
`Content-Disposition: form-data; name="file"\r\n` +
|
|
399
|
+
`Content-Type: application/octet-stream\r\n\r\n`));
|
|
400
|
+
formParts.push(body);
|
|
401
|
+
formParts.push(Buffer.from(`\r\n--${boundary}--\r\n`));
|
|
402
|
+
formBody = Buffer.concat(formParts);
|
|
403
|
+
reqHeaders['Content-Type'] = `multipart/form-data; boundary=${boundary}`;
|
|
404
|
+
reqHeaders['Content-Length'] = formBody.length.toString();
|
|
405
|
+
}
|
|
406
|
+
let lastError;
|
|
407
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
408
|
+
try {
|
|
409
|
+
return await httpRequest(url.toString(), {
|
|
410
|
+
method: 'POST',
|
|
411
|
+
headers: reqHeaders,
|
|
412
|
+
body: formBody,
|
|
413
|
+
timeout: body ? 120000 : 60000,
|
|
414
|
+
followRedirect: true,
|
|
415
|
+
});
|
|
311
416
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
timeout: 300000,
|
|
318
|
-
followRedirect: true,
|
|
319
|
-
});
|
|
320
|
-
const lines = response.toString().trim().split('\n');
|
|
321
|
-
let rootCid;
|
|
322
|
-
for (const line of lines) {
|
|
323
|
-
if (!line.trim())
|
|
417
|
+
catch (e) {
|
|
418
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
419
|
+
if (lastError.message.includes('429')) {
|
|
420
|
+
const backoffMs = Math.pow(2, attempt) * 1000;
|
|
421
|
+
await sleep(backoffMs);
|
|
324
422
|
continue;
|
|
325
|
-
const result = JSON.parse(line);
|
|
326
|
-
if (result.Hash && (result.Name === '' || !result.Name)) {
|
|
327
|
-
rootCid = result.Hash;
|
|
328
423
|
}
|
|
329
|
-
|
|
330
|
-
|
|
424
|
+
throw lastError;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
throw lastError || new Error('Max retries exceeded');
|
|
428
|
+
}
|
|
429
|
+
export async function uploadDirectory(dirPath, _wrapWithDirectory = true) {
|
|
430
|
+
const config = loadConfig();
|
|
431
|
+
const endpoint = config.ipfsPinningEndpoint;
|
|
432
|
+
if (!endpoint) {
|
|
433
|
+
throw new Error('IPFS pinning endpoint not configured. Run `opnet config set ipfsPinningEndpoint <url>`');
|
|
434
|
+
}
|
|
435
|
+
const baseUrl = endpoint.replace(/\/api\/v0\/add\/?$/, '');
|
|
436
|
+
const files = getAllFiles(dirPath);
|
|
437
|
+
if (files.length === 0) {
|
|
438
|
+
throw new Error('Directory is empty');
|
|
439
|
+
}
|
|
440
|
+
let totalSize = 0;
|
|
441
|
+
for (const file of files) {
|
|
442
|
+
const stat = fs.statSync(file.fullPath);
|
|
443
|
+
totalSize += stat.size;
|
|
444
|
+
}
|
|
445
|
+
const sessionId = generateSessionId();
|
|
446
|
+
const mfsPath = `/uploads/${sessionId}`;
|
|
447
|
+
const headers = {};
|
|
448
|
+
if (config.ipfsPinningApiKey) {
|
|
449
|
+
headers['Authorization'] = `Bearer ${config.ipfsPinningApiKey}`;
|
|
450
|
+
}
|
|
451
|
+
const formatBytes = (bytes) => {
|
|
452
|
+
if (bytes < 1024)
|
|
453
|
+
return `${bytes} B`;
|
|
454
|
+
if (bytes < 1024 * 1024)
|
|
455
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
456
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
457
|
+
};
|
|
458
|
+
let uploadedBytes = 0;
|
|
459
|
+
let spinner = null;
|
|
460
|
+
try {
|
|
461
|
+
await mfsCall(baseUrl, '/api/v0/files/mkdir', {
|
|
462
|
+
arg: mfsPath,
|
|
463
|
+
parents: 'true',
|
|
464
|
+
}, undefined, headers);
|
|
465
|
+
for (let i = 0; i < files.length; i++) {
|
|
466
|
+
const file = files[i];
|
|
467
|
+
const data = fs.readFileSync(file.fullPath);
|
|
468
|
+
const fileMfsPath = `${mfsPath}/${file.path}`;
|
|
469
|
+
const parentDir = fileMfsPath.substring(0, fileMfsPath.lastIndexOf('/'));
|
|
470
|
+
if (parentDir !== mfsPath) {
|
|
471
|
+
await mfsCall(baseUrl, '/api/v0/files/mkdir', {
|
|
472
|
+
arg: parentDir,
|
|
473
|
+
parents: 'true',
|
|
474
|
+
}, undefined, headers);
|
|
331
475
|
}
|
|
476
|
+
await mfsCall(baseUrl, '/api/v0/files/write', {
|
|
477
|
+
arg: fileMfsPath,
|
|
478
|
+
create: 'true',
|
|
479
|
+
parents: 'true',
|
|
480
|
+
truncate: 'true',
|
|
481
|
+
}, data, headers);
|
|
482
|
+
uploadedBytes += data.length;
|
|
483
|
+
const percent = Math.round((uploadedBytes / totalSize) * 100);
|
|
484
|
+
const barWidth = 30;
|
|
485
|
+
const filled = Math.round((percent / 100) * barWidth);
|
|
486
|
+
const empty = barWidth - filled;
|
|
487
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
488
|
+
process.stdout.write(`\r Uploading: [${bar}] ${percent}% - ${i + 1}/${files.length} files (${formatBytes(uploadedBytes)}/${formatBytes(totalSize)})`);
|
|
332
489
|
}
|
|
333
|
-
|
|
334
|
-
|
|
490
|
+
process.stdout.write('\n');
|
|
491
|
+
spinner = ora({
|
|
492
|
+
text: 'Getting directory CID...',
|
|
493
|
+
spinner: 'dots',
|
|
494
|
+
}).start();
|
|
495
|
+
const statResponse = await mfsCall(baseUrl, '/api/v0/files/stat', {
|
|
496
|
+
arg: mfsPath,
|
|
497
|
+
hash: 'true',
|
|
498
|
+
'cid-base': 'base32',
|
|
499
|
+
}, undefined, headers);
|
|
500
|
+
const statResult = JSON.parse(statResponse.toString());
|
|
501
|
+
let cid = statResult.Hash;
|
|
502
|
+
if (!cid) {
|
|
503
|
+
spinner.fail('Failed to get directory CID');
|
|
504
|
+
throw new Error('MFS stat did not return a Hash');
|
|
505
|
+
}
|
|
506
|
+
if (isCIDv0(cid)) {
|
|
507
|
+
cid = cidV0toV1(cid);
|
|
508
|
+
}
|
|
509
|
+
spinner.text = 'Pinning content...';
|
|
510
|
+
try {
|
|
511
|
+
await mfsCall(baseUrl, '/api/v0/pin/add', {
|
|
512
|
+
arg: cid,
|
|
513
|
+
}, undefined, headers);
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
}
|
|
517
|
+
spinner.succeed(`Upload complete: ${cid}`);
|
|
518
|
+
try {
|
|
519
|
+
await mfsCall(baseUrl, '/api/v0/files/rm', {
|
|
520
|
+
arg: mfsPath,
|
|
521
|
+
recursive: 'true',
|
|
522
|
+
}, undefined, headers);
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
335
525
|
}
|
|
336
526
|
return {
|
|
337
|
-
cid
|
|
527
|
+
cid,
|
|
338
528
|
files: files.length,
|
|
339
529
|
totalSize,
|
|
340
530
|
};
|
|
341
531
|
}
|
|
342
532
|
catch (e) {
|
|
533
|
+
if (spinner) {
|
|
534
|
+
spinner.fail('Upload failed');
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
await mfsCall(baseUrl, '/api/v0/files/rm', {
|
|
538
|
+
arg: mfsPath,
|
|
539
|
+
recursive: 'true',
|
|
540
|
+
}, undefined, headers);
|
|
541
|
+
}
|
|
542
|
+
catch {
|
|
543
|
+
}
|
|
343
544
|
throw new Error(`IPFS directory upload failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
344
545
|
}
|
|
345
546
|
}
|
package/build/lib/resolver.js
CHANGED
|
@@ -139,8 +139,8 @@ export function detectContenthashType(content) {
|
|
|
139
139
|
return null;
|
|
140
140
|
}
|
|
141
141
|
export function validateDomainName(domain) {
|
|
142
|
-
if (domain.length <
|
|
143
|
-
return 'Domain must be at least
|
|
142
|
+
if (domain.length < 1) {
|
|
143
|
+
return 'Domain must be at least 1 character';
|
|
144
144
|
}
|
|
145
145
|
if (domain.length > 63) {
|
|
146
146
|
return 'Domain must be at most 63 characters';
|
|
@@ -6,8 +6,27 @@ export declare const CONTENTHASH_TYPE_IPNS = 3;
|
|
|
6
6
|
export declare const CONTENTHASH_TYPE_SHA256 = 4;
|
|
7
7
|
export type ContenthashType = typeof CONTENTHASH_TYPE_CIDv0 | typeof CONTENTHASH_TYPE_CIDv1 | typeof CONTENTHASH_TYPE_IPNS | typeof CONTENTHASH_TYPE_SHA256;
|
|
8
8
|
export declare const DEFAULT_DOMAIN_PRICE_SATS = 100000n;
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
9
|
+
export declare const PREMIUM_TIER_0_PRICE_SATS = 1000000000n;
|
|
10
|
+
export declare const PREMIUM_TIER_1_PRICE_SATS = 100000000n;
|
|
11
|
+
export declare const PREMIUM_TIER_2_PRICE_SATS = 25000000n;
|
|
12
|
+
export declare const PREMIUM_TIER_3_PRICE_SATS = 10000000n;
|
|
13
|
+
export declare const PREMIUM_TIER_4_PRICE_SATS = 5000000n;
|
|
14
|
+
export declare const PREMIUM_TIER_5_PRICE_SATS = 1000000n;
|
|
15
|
+
export declare const PREMIUM_TIER_6_PRICE_SATS = 500000n;
|
|
16
|
+
export declare const PREMIUM_TIER_0_DOMAINS: string[];
|
|
17
|
+
export declare const PREMIUM_TIER_1_DOMAINS: string[];
|
|
18
|
+
export declare const PREMIUM_TIER_2_DOMAINS: string[];
|
|
19
|
+
export declare const PREMIUM_TIER_3_DOMAINS: string[];
|
|
20
|
+
export declare const PREMIUM_TIER_4_DOMAINS: string[];
|
|
21
|
+
export declare const PREMIUM_TIER_5_DOMAINS: string[];
|
|
22
|
+
export declare const PREMIUM_TIER_6_DOMAINS: string[];
|
|
23
|
+
export interface PricingTier {
|
|
24
|
+
tier: number;
|
|
25
|
+
name: string;
|
|
26
|
+
price: bigint;
|
|
27
|
+
description: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function getPricingTier(domainName: string): PricingTier;
|
|
11
30
|
export type DomainRegisteredEvent = {
|
|
12
31
|
readonly domainHash: bigint;
|
|
13
32
|
readonly owner: Address;
|
|
@@ -72,6 +91,8 @@ export type RegisterDomain = CallResult<{}, OPNetEvent<DomainRegisteredEvent>[]>
|
|
|
72
91
|
export type InitiateTransfer = CallResult<{}, OPNetEvent<DomainTransferInitiatedEvent>[]>;
|
|
73
92
|
export type AcceptTransfer = CallResult<{}, OPNetEvent<DomainTransferCompletedEvent>[]>;
|
|
74
93
|
export type CancelTransfer = CallResult<{}, OPNetEvent<DomainTransferCancelledEvent>[]>;
|
|
94
|
+
export type TransferDomain = CallResult<{}, OPNetEvent<DomainTransferCompletedEvent>[]>;
|
|
95
|
+
export type TransferDomainBySignature = CallResult<{}, OPNetEvent<DomainTransferCompletedEvent>[]>;
|
|
75
96
|
export type CreateSubdomain = CallResult<{}, OPNetEvent<SubdomainCreatedEvent>[]>;
|
|
76
97
|
export type DeleteSubdomain = CallResult<{}, OPNetEvent<SubdomainDeletedEvent>[]>;
|
|
77
98
|
export type SetContenthashCIDv0 = CallResult<{}, OPNetEvent<ContenthashChangedEvent>[]>;
|
|
@@ -120,6 +141,8 @@ export interface IBtcResolver extends IOP_NETContract {
|
|
|
120
141
|
initiateTransfer(domainName: string, newOwner: Address): Promise<InitiateTransfer>;
|
|
121
142
|
acceptTransfer(domainName: string): Promise<AcceptTransfer>;
|
|
122
143
|
cancelTransfer(domainName: string): Promise<CancelTransfer>;
|
|
144
|
+
transferDomain(domainName: string, newOwner: Address): Promise<TransferDomain>;
|
|
145
|
+
transferDomainBySignature(ownerAddress: Uint8Array, ownerTweakedPublicKey: Uint8Array, domainName: string, newOwner: Address, deadline: bigint, signature: Uint8Array): Promise<TransferDomainBySignature>;
|
|
123
146
|
createSubdomain(parentDomain: string, subdomainLabel: string, subdomainOwner: Address): Promise<CreateSubdomain>;
|
|
124
147
|
deleteSubdomain(parentDomain: string, subdomainLabel: string): Promise<DeleteSubdomain>;
|
|
125
148
|
setContenthashCIDv0(name: string, cid: string): Promise<SetContenthashCIDv0>;
|
|
@@ -3,5 +3,161 @@ export const CONTENTHASH_TYPE_CIDv1 = 2;
|
|
|
3
3
|
export const CONTENTHASH_TYPE_IPNS = 3;
|
|
4
4
|
export const CONTENTHASH_TYPE_SHA256 = 4;
|
|
5
5
|
export const DEFAULT_DOMAIN_PRICE_SATS = 100000n;
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
6
|
+
export const PREMIUM_TIER_0_PRICE_SATS = 1000000000n;
|
|
7
|
+
export const PREMIUM_TIER_1_PRICE_SATS = 100000000n;
|
|
8
|
+
export const PREMIUM_TIER_2_PRICE_SATS = 25000000n;
|
|
9
|
+
export const PREMIUM_TIER_3_PRICE_SATS = 10000000n;
|
|
10
|
+
export const PREMIUM_TIER_4_PRICE_SATS = 5000000n;
|
|
11
|
+
export const PREMIUM_TIER_5_PRICE_SATS = 1000000n;
|
|
12
|
+
export const PREMIUM_TIER_6_PRICE_SATS = 500000n;
|
|
13
|
+
export const PREMIUM_TIER_0_DOMAINS = [
|
|
14
|
+
'satoshi', 'nakamoto', 'vitalik', 'cz', 'sbf', 'gavin', 'hal', 'finney',
|
|
15
|
+
'bitcoin', 'btc', 'ethereum', 'eth', 'crypto', 'blockchain', 'defi', 'web3',
|
|
16
|
+
'nft', 'dao', 'dex', 'cex', 'token', 'coin', 'wallet', 'exchange',
|
|
17
|
+
'binance', 'coinbase', 'kraken', 'gemini', 'ftx', 'bitfinex', 'bitstamp',
|
|
18
|
+
'huobi', 'okx', 'okex', 'kucoin', 'bybit', 'bitget', 'mexc', 'gateio',
|
|
19
|
+
'uniswap', 'aave', 'compound', 'maker', 'curve', 'sushi', 'pancakeswap',
|
|
20
|
+
'opensea', 'blur', 'looksrare', 'rarible', 'foundation',
|
|
21
|
+
'pepe', 'doge', 'shiba', 'shib', 'floki', 'bonk', 'wojak', 'meme',
|
|
22
|
+
'dogecoin', 'shibarium', 'babydoge',
|
|
23
|
+
'apple', 'google', 'amazon', 'microsoft', 'meta', 'facebook', 'twitter',
|
|
24
|
+
'tesla', 'nvidia', 'intel', 'amd', 'oracle', 'ibm', 'samsung',
|
|
25
|
+
'money', 'gold', 'bank', 'pay', 'cash', 'trade', 'invest', 'rich',
|
|
26
|
+
'moon', 'lambo', 'whale', 'alpha', 'sigma', 'chad', 'based',
|
|
27
|
+
'king', 'queen', 'god', 'lord', 'master', 'legend', 'epic', 'rare',
|
|
28
|
+
];
|
|
29
|
+
export const PREMIUM_TIER_1_DOMAINS = [
|
|
30
|
+
'swap', 'stake', 'yield', 'farm', 'pool', 'vault', 'bridge', 'layer',
|
|
31
|
+
'chain', 'block', 'hash', 'node', 'miner', 'validator', 'staker',
|
|
32
|
+
'solana', 'sol', 'cardano', 'ada', 'polkadot', 'dot', 'avalanche', 'avax',
|
|
33
|
+
'polygon', 'matic', 'arbitrum', 'arb', 'optimism', 'base', 'zksync',
|
|
34
|
+
];
|
|
35
|
+
export const PREMIUM_TIER_2_DOMAINS = [
|
|
36
|
+
'link', 'atom', 'near', 'algo', 'ftm', 'sand', 'mana', 'axs', 'ape',
|
|
37
|
+
'lido', 'rocket', 'eigen', 'blur', 'magic', 'looks', 'x2y2',
|
|
38
|
+
'safe', 'gnosis', 'ens', 'lens', 'punk', 'bayc', 'mayc', 'azuki',
|
|
39
|
+
];
|
|
40
|
+
export const PREMIUM_TIER_3_DOMAINS = [
|
|
41
|
+
'game', 'games', 'play', 'bet', 'casino', 'poker', 'dice', 'slots',
|
|
42
|
+
'news', 'media', 'blog', 'forum', 'chat', 'social', 'network',
|
|
43
|
+
'shop', 'store', 'market', 'buy', 'sell', 'auction', 'bid',
|
|
44
|
+
];
|
|
45
|
+
export const PREMIUM_TIER_4_DOMAINS = [
|
|
46
|
+
'john', 'james', 'david', 'michael', 'robert', 'william', 'richard',
|
|
47
|
+
'mary', 'jennifer', 'linda', 'elizabeth', 'barbara', 'susan', 'jessica',
|
|
48
|
+
'smith', 'johnson', 'williams', 'brown', 'jones', 'garcia', 'miller',
|
|
49
|
+
];
|
|
50
|
+
export const PREMIUM_TIER_5_DOMAINS = [
|
|
51
|
+
'hello', 'world', 'test', 'demo', 'example', 'sample', 'default',
|
|
52
|
+
'admin', 'user', 'guest', 'member', 'account', 'profile', 'settings',
|
|
53
|
+
];
|
|
54
|
+
export const PREMIUM_TIER_6_DOMAINS = [
|
|
55
|
+
'about', 'contact', 'help', 'support', 'faq', 'terms', 'privacy',
|
|
56
|
+
'home', 'index', 'main', 'start', 'begin', 'intro', 'welcome',
|
|
57
|
+
];
|
|
58
|
+
export function getPricingTier(domainName) {
|
|
59
|
+
const name = domainName.toLowerCase();
|
|
60
|
+
const len = name.length;
|
|
61
|
+
if (PREMIUM_TIER_0_DOMAINS.includes(name)) {
|
|
62
|
+
return {
|
|
63
|
+
tier: 0,
|
|
64
|
+
name: 'Ultra Legendary',
|
|
65
|
+
price: PREMIUM_TIER_0_PRICE_SATS,
|
|
66
|
+
description: '10 BTC - Iconic crypto/tech names',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (len === 1) {
|
|
70
|
+
return {
|
|
71
|
+
tier: 1,
|
|
72
|
+
name: 'Legendary',
|
|
73
|
+
price: PREMIUM_TIER_1_PRICE_SATS,
|
|
74
|
+
description: '1 BTC - Single character domain',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (len === 2) {
|
|
78
|
+
return {
|
|
79
|
+
tier: 2,
|
|
80
|
+
name: 'Premium',
|
|
81
|
+
price: PREMIUM_TIER_2_PRICE_SATS,
|
|
82
|
+
description: '0.25 BTC - Two character domain',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (PREMIUM_TIER_1_DOMAINS.includes(name)) {
|
|
86
|
+
return {
|
|
87
|
+
tier: 1,
|
|
88
|
+
name: 'Legendary',
|
|
89
|
+
price: PREMIUM_TIER_1_PRICE_SATS,
|
|
90
|
+
description: '1 BTC - Top crypto keyword',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (PREMIUM_TIER_2_DOMAINS.includes(name)) {
|
|
94
|
+
return {
|
|
95
|
+
tier: 2,
|
|
96
|
+
name: 'Premium',
|
|
97
|
+
price: PREMIUM_TIER_2_PRICE_SATS,
|
|
98
|
+
description: '0.25 BTC - Major protocol/project',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (PREMIUM_TIER_3_DOMAINS.includes(name)) {
|
|
102
|
+
return {
|
|
103
|
+
tier: 3,
|
|
104
|
+
name: 'High Value',
|
|
105
|
+
price: PREMIUM_TIER_3_PRICE_SATS,
|
|
106
|
+
description: '0.1 BTC - High-value keyword',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (PREMIUM_TIER_4_DOMAINS.includes(name)) {
|
|
110
|
+
return {
|
|
111
|
+
tier: 4,
|
|
112
|
+
name: 'Valuable',
|
|
113
|
+
price: PREMIUM_TIER_4_PRICE_SATS,
|
|
114
|
+
description: '0.05 BTC - Valuable keyword',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (PREMIUM_TIER_5_DOMAINS.includes(name)) {
|
|
118
|
+
return {
|
|
119
|
+
tier: 5,
|
|
120
|
+
name: 'Common Premium',
|
|
121
|
+
price: PREMIUM_TIER_5_PRICE_SATS,
|
|
122
|
+
description: '0.01 BTC - Common keyword',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (PREMIUM_TIER_6_DOMAINS.includes(name)) {
|
|
126
|
+
return {
|
|
127
|
+
tier: 6,
|
|
128
|
+
name: 'Notable',
|
|
129
|
+
price: PREMIUM_TIER_6_PRICE_SATS,
|
|
130
|
+
description: '0.005 BTC - Notable keyword',
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (len === 3) {
|
|
134
|
+
return {
|
|
135
|
+
tier: 3,
|
|
136
|
+
name: 'High Value',
|
|
137
|
+
price: PREMIUM_TIER_3_PRICE_SATS,
|
|
138
|
+
description: '0.1 BTC - Three character domain',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (len === 4) {
|
|
142
|
+
return {
|
|
143
|
+
tier: 4,
|
|
144
|
+
name: 'Valuable',
|
|
145
|
+
price: PREMIUM_TIER_4_PRICE_SATS,
|
|
146
|
+
description: '0.05 BTC - Four character domain',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (len === 5) {
|
|
150
|
+
return {
|
|
151
|
+
tier: 5,
|
|
152
|
+
name: 'Common Premium',
|
|
153
|
+
price: PREMIUM_TIER_5_PRICE_SATS,
|
|
154
|
+
description: '0.01 BTC - Five character domain',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
tier: 7,
|
|
159
|
+
name: 'Standard',
|
|
160
|
+
price: DEFAULT_DOMAIN_PRICE_SATS,
|
|
161
|
+
description: '0.001 BTC - Standard domain',
|
|
162
|
+
};
|
|
163
|
+
}
|