Skip to content

Commit

Permalink
fix: bns-v2-sdk patch
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarkhanzadian committed Nov 11, 2024
1 parent 4937d9b commit 9b342af
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 86 deletions.
2 changes: 1 addition & 1 deletion packages/query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@
"@scure/btc-signer": "1.4.0",
"@stacks/common": "6.13.0",
"@stacks/connect": "7.4.0",
"@stacks/network": "6.13.0",
"@stacks/rpc-client": "1.0.3",
"@stacks/stacks-blockchain-api-types": "7.8.2",
"@stacks/transactions": "6.17.0",
"@tanstack/react-query": "5.59.16",
"alex-sdk": "2.1.4",
"axios": "1.7.7",
"bignumber.js": "9.1.2",
"bns-v2-sdk": "1.3.1",
"lodash.get": "4.4.2",
"p-queue": "8.0.1",
"url-join": "5.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Get some specific parts of bns-v2-sdk package until it gets fixed.
119 changes: 119 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/callers-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { StacksMainnet, StacksTestnet } from '@stacks/network';
import { ClarityValue, callReadOnlyFunction } from '@stacks/transactions';

import { BnsContractName, NetworkType, getBnsContractAddress } from './config';
import { debug } from './debug';
import { BnsReadOnlyOptions } from './interfaces';
import { getFallbackUrl, getNetwork } from './network';

async function executeReadOnlyCall(
options: BnsReadOnlyOptions,
contractAddress: string,
contractName: string,
network: StacksMainnet | StacksTestnet,
isZonefile: boolean = false
): Promise<ClarityValue> {
const networkType = network instanceof StacksMainnet ? 'mainnet' : 'testnet';
const fallbackUrl = getFallbackUrl(networkType);

debug.log('executeReadOnlyCall initiated:', {
networkType,
contractAddress,
contractName,
functionName: options.functionName,
coreApiUrl: network.coreApiUrl,
fallbackUrl,
isZonefile,
});

async function attemptCall(url: string): Promise<ClarityValue> {
const currentNetwork =
networkType === 'mainnet' ? new StacksMainnet({ url }) : new StacksTestnet({ url });

debug.log('Attempting call with:', {
url,
networkType: networkType,
currentNetworkType: currentNetwork instanceof StacksMainnet ? 'mainnet' : 'testnet',
});

try {
const response = await callReadOnlyFunction({
contractAddress,
contractName,
functionName: options.functionName,
functionArgs: options.functionArgs,
senderAddress: options.senderAddress,
network: currentNetwork,
});

if ((response as any).error) {
debug.error('Response contains error:', (response as any).error);
throw new Error((response as any).error);
}

debug.log('Call successful');
return response;
} catch (error: any) {
debug.error('Call failed:', {
error: error.message,
url,
networkType,
});
throw error;
}
}

// For zonefile calls, always use fallback URL if available
if (isZonefile && fallbackUrl) {
debug.log('Using fallback URL for zonefile call:', fallbackUrl);
try {
return await attemptCall(fallbackUrl);
} catch (error) {
debug.error('Fallback attempt failed for zonefile:', error);
throw error;
}
}

// For non-zonefile calls or if no fallback URL, try primary first then fallback
try {
return await attemptCall(network.coreApiUrl);
} catch (error) {
debug.log('Primary URL failed, checking fallback availability:', {
hasFallback: !!fallbackUrl,
fallbackUrl,
isSameAsPrimary: fallbackUrl === network.coreApiUrl,
});

if (fallbackUrl && fallbackUrl !== network.coreApiUrl) {
try {
return await attemptCall(fallbackUrl);
} catch (fallbackError) {
debug.error('Fallback attempt failed:', fallbackError);
throw fallbackError;
}
} else {
throw error;
}
}
}

export async function bnsV2ReadOnlyCall(
options: Omit<BnsReadOnlyOptions, 'network'> & { network: NetworkType }
): Promise<ClarityValue> {
debug.log('bnsV2ReadOnlyCall initiated:', {
network: options.network,
functionName: options.functionName,
});

const network = getNetwork(options.network);
const contractAddress = getBnsContractAddress(options.network);

debug.log('Network configuration:', {
networkType: options.network,
contractAddress,
isMainnet: network instanceof StacksMainnet,
apiUrl: network.coreApiUrl,
});

return executeReadOnlyCall(options, contractAddress, BnsContractName, network, false);
}
12 changes: 12 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const BnsContractName = 'BNS-V2';

enum BnsContractAddress {
Mainnet = 'SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF',
Testnet = 'ST2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D9SZJQ0M',
}

export function getBnsContractAddress(network: NetworkType): string {
return network === 'mainnet' ? BnsContractAddress.Mainnet : BnsContractAddress.Testnet;
}

export type NetworkType = 'mainnet' | 'testnet';
22 changes: 22 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
let isDebugEnabled = false;

export const debug = {
enable: () => {
isDebugEnabled = true;
},
disable: () => {
isDebugEnabled = false;
},
log: (...args: any[]) => {
if (isDebugEnabled) {
// eslint-disable-next-line no-console
console.log('[BNS-V2-SDK]:', ...args);
}
},
error: (...args: any[]) => {
if (isDebugEnabled) {
// eslint-disable-next-line no-console
console.error('[BNS-V2-SDK]:', ...args);
}
},
};
1 change: 1 addition & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getPrimaryName } from './read-only-calls';
14 changes: 14 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ClarityValue } from '@stacks/transactions';

import { NetworkType } from './config';

export interface BnsReadOnlyOptions {
functionName: string;
functionArgs: ClarityValue[];
senderAddress: string;
network: NetworkType;
}
export interface GetPrimaryNameOptions {
address: string;
network: NetworkType;
}
44 changes: 44 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { StacksMainnet, StacksTestnet } from '@stacks/network';

import { NetworkType } from './config';
import { debug } from './debug';

export function getNetwork(networkType: NetworkType) {
debug.log('Getting network for type:', networkType);

if (networkType === 'mainnet') {
const network = new StacksMainnet();
debug.log('Created mainnet network:', {
apiUrl: network.coreApiUrl,
});
return network;
} else {
const network = new StacksTestnet();
debug.log('Created testnet network:', {
apiUrl: network.coreApiUrl,
});
return network;
}
}

export function getFallbackUrl(networkType?: NetworkType): string {
debug.log('Getting fallback URL for network type:', networkType);

if (networkType === 'testnet') {
const testnetFallbackUrl = process.env.NEXT_PUBLIC_BNS_FALLBACK_URL_TESTNET;
debug.log('Testnet fallback URL:', testnetFallbackUrl);
if (!testnetFallbackUrl) {
debug.log('No testnet fallback URL configured');
return '';
}
return testnetFallbackUrl;
}

const mainnetFallbackUrl = process.env.NEXT_PUBLIC_BNS_FALLBACK_URL;
debug.log('Mainnet fallback URL:', mainnetFallbackUrl);
if (!mainnetFallbackUrl) {
debug.log('No mainnet fallback URL configured');
return '';
}
return mainnetFallbackUrl;
}
55 changes: 55 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/read-only-calls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
BufferCV,
ClarityType,
ClarityValue,
cvToString,
getCVTypeString,
standardPrincipalCV,
} from '@stacks/transactions';

import { bnsV2ReadOnlyCall } from './callers-helper';
import { GetPrimaryNameOptions } from './interfaces';
import { generateRandomAddress } from './utils';

export async function getPrimaryName({
address,
network,
}: GetPrimaryNameOptions): Promise<{ name: string; namespace: string } | null> {
const bnsFunctionName = 'get-primary';
const randomAddress = generateRandomAddress();
return bnsV2ReadOnlyCall({
functionName: bnsFunctionName,
senderAddress: randomAddress,
functionArgs: [standardPrincipalCV(address)],
network,
}).then((responseCV: ClarityValue) => {
if (responseCV.type === ClarityType.ResponseOk) {
if (responseCV.value.type === ClarityType.Tuple) {
const nameCV = responseCV.value.data['name'] as BufferCV;
const namespaceCV = responseCV.value.data['namespace'] as BufferCV;
return {
name: Buffer.from(nameCV.buffer).toString(),
namespace: Buffer.from(namespaceCV.buffer).toString(),
};
} else if (responseCV.value.type === ClarityType.OptionalSome) {
const innerValue = responseCV.value.value;
if (innerValue.type === ClarityType.Tuple) {
const nameCV = innerValue.data['name'] as BufferCV;
const namespaceCV = innerValue.data['namespace'] as BufferCV;
return {
name: Buffer.from(nameCV.buffer).toString(),
namespace: Buffer.from(namespaceCV.buffer).toString(),
};
}
}
throw new Error('Unexpected response structure');
} else if (responseCV.type === ClarityType.ResponseErr) {
if (cvToString(responseCV.value) === 'u131') {
return null;
}
throw new Error(cvToString(responseCV.value));
} else {
throw new Error(`Unexpected Clarity Value type: ${getCVTypeString(responseCV)}`);
}
});
}
13 changes: 13 additions & 0 deletions packages/query/src/stacks/bns/bns-v2-sdk/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
getAddressFromPrivateKey,
makeRandomPrivKey,
privateKeyToString,
} from '@stacks/transactions';

export function generateRandomAddress() {
const randomPrivateKey = makeRandomPrivKey();
const privateKeyString = privateKeyToString(randomPrivateKey);
const randomAddress = getAddressFromPrivateKey(privateKeyString);

return randomAddress;
}
4 changes: 2 additions & 2 deletions packages/query/src/stacks/bns/bns.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import axios from 'axios';
import { getPrimaryName } from 'bns-v2-sdk';
import { describe, expect, it, vi } from 'vitest';

import { getPrimaryName } from './bns-v2-sdk';
import { fetchNamesForAddress } from './bns.utils';

vi.mock('axios');
vi.mock('bns-v2-sdk');
vi.mock('./bns-v2-sdk');

describe('bns.utils', () => {
describe('fetchNamesForAddress', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/query/src/stacks/bns/bns.utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { parseZoneFile } from '@fungible-systems/zone-file';
import { BnsNamesOwnByAddressResponse } from '@stacks/stacks-blockchain-api-types';
import axios from 'axios';
import { getPrimaryName } from 'bns-v2-sdk';
import { z } from 'zod';

import { BNS_V2_API_BASE_URL, NetworkModes } from '@leather.io/models';
import { isString, isUndefined } from '@leather.io/utils';

import { StacksClient } from '../stacks-client';
import { getPrimaryName } from './bns-v2-sdk';
import { bnsV2NamesByAddressSchema } from './bns.schemas';

/**
Expand Down
Loading

0 comments on commit 9b342af

Please sign in to comment.