ordinalsbot
Version:
Node.js library for OrdinalsBot API
450 lines (416 loc) • 16.3 kB
text/typescript
import { MarketPlaceClient } from "./marketplaceClient";
import { ClientOptions, InscriptionEnv, InscriptionEnvNetwork } from "./types";
import {
MarketplaceConfirmPaddingOutputsRequest,
MarketplaceConfirmPaddingOutputsResponse,
MarketplaceCreateListingRequest,
MarketplaceCreateListingResponse,
MarketplaceCreateOfferRequest,
MarketplaceCreateOfferResponse,
MarketplaceSetupPaddingOutputsRequest,
MarketplaceSetupPaddingOutputsResponse,
MarketplaceCreateRequest,
MarketplaceCreateResponse,
MarketplaceGetListingResponse,
MarketplaceSubmitOfferRequest,
MarketplaceSubmitOfferResponse,
MarketplaceGetListingRequest,
MarketplaceSaveListingRequest,
MarketplaceSaveListingResponse,
MarketplaceTransferRequest,
MarketplaceTransferAPIResponse,
WALLET_PROVIDER,
MarketplaceConfirmListingRequest,
MarketplaceConfirmListingResponse,
MarketplaceReListingRequest,
MarketplaceReListingResponse,
MarketplaceConfirmReListResponse,
MarketplaceConfirmReListRequest,
MarketplaceDeListRequest,
MarketplaceDeListAPIResponse,
MarketplaceConfirmDeListRequest,
MarketplaceConfirmDeListResponse
} from "./types/marketplace_types";
import * as bitcoin from 'bitcoinjs-lib';
import { BitcoinNetworkType, SignTransactionResponse, signTransaction } from 'sats-connect';
export class MarketPlace {
private network: BitcoinNetworkType;
private marketplaceInstance!: MarketPlaceClient;
/**
* Creates an instance of MarketPlace.
* @param {string} key - The API key for authentication.
* @param {InscriptionEnv} [environment='mainnet'] - The environment (e.g., "testnet" , "mainnet", "signet") (optional, defaults to mainnet).
* @param {ClientOptions} [options] - Options for enabling L402 support.
*/
constructor(key: string = "", environment: InscriptionEnv = InscriptionEnvNetwork.mainnet, options?: ClientOptions) {
if (this.marketplaceInstance !== undefined) {
console.error("marketplace constructore was called multiple times");
return;
}
environment = InscriptionEnvNetwork[environment]??InscriptionEnvNetwork.mainnet;
switch (environment) {
case InscriptionEnvNetwork.mainnet:
this.network = BitcoinNetworkType.Mainnet;
break;
case InscriptionEnvNetwork.testnet:
this.network = BitcoinNetworkType.Testnet;
break;
case InscriptionEnvNetwork.signet:
// @ts-ignore
this.network = BitcoinNetworkType.Signet;
break;
default:
this.network = BitcoinNetworkType.Mainnet
break;
}
this.marketplaceInstance = new MarketPlaceClient(key, environment, options);
}
createMarketplace(
createMarketplaceRequest: MarketplaceCreateRequest
): Promise<MarketplaceCreateResponse> {
return this.marketplaceInstance.createMarketPlace(createMarketplaceRequest);
}
/**
* Create a new listing on the marketplace.
* @param {MarketplaceCreateListingRequest} createListingRequest The request object containing information about the listing.
* @returns {Promise<MarketplaceCreateListingResponse | MarketplaceConfirmListingResponse>} A promise that resolves to either a create listing response or a confirm listing response.
*/
async createListing(
createListingRequest: MarketplaceCreateListingRequest
): Promise<MarketplaceCreateListingResponse | MarketplaceConfirmListingResponse> {
try {
if (!createListingRequest.walletProvider) {
return await this.marketplaceInstance.createListing(createListingRequest);
} else if (createListingRequest.walletProvider === WALLET_PROVIDER.xverse) {
const { psbt } = await this.marketplaceInstance.createListing(createListingRequest);
// Create the payload for signing the seller transaction
if (!createListingRequest.sellerOrdinalAddress) {
throw new Error('No seller address provided');
}
const inputIndices = createListingRequest.sellerOrdinals.map((item, index) => index);
const sellerInput = {
address: createListingRequest.sellerOrdinalAddress,
signingIndexes: inputIndices,
sigHash:
bitcoin.Transaction.SIGHASH_SINGLE |
bitcoin.Transaction.SIGHASH_ANYONECANPAY,
};
const payload = {
network: { type: this.network },
message: 'Sign Seller Transaction',
psbtBase64: psbt,
broadcast: false,
inputsToSign: [sellerInput],
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response) => {
try {
// ordinal ids to confirm the listing
const sellerOrdinalIds = createListingRequest.sellerOrdinals.map((item, index) => item.id)
const confirmListingPayload: MarketplaceConfirmListingRequest = {
sellerOrdinals: sellerOrdinalIds as string[],
signedListingPSBT: response.psbtBase64,
}
resolve(this.confirmListing(confirmListingPayload));
} catch (error) {
console.error('Error confirm listing:', error);
reject(error);
}
},
onCancel: () => {
console.log('Transaction canceled');
}
});
});
} else {
throw new Error("Wallet not supported");
}
} catch (error) {
console.error('Error in createListing:', error);
throw error;
}
}
/**
* Updated price for a exisiting listing on the marketplace.
* @param {MarketplaceReListingRequest} reListingRequest The request object containing information about the listing.
* @returns {Promise<MarketplaceReListingResponse | MarketplaceConfirmReListResponse>} A promise that resolves to either a create listing response or a confirm listing response.
*/
async reListing(
reListingRequest: MarketplaceReListingRequest
): Promise<MarketplaceReListingResponse | MarketplaceConfirmReListResponse> {
try {
if (!reListingRequest.walletProvider) {
return await this.marketplaceInstance.reListing(reListingRequest);
} else if (reListingRequest.walletProvider === WALLET_PROVIDER.xverse) {
const { psbt } = await this.marketplaceInstance.reListing(reListingRequest);
// Create the payload for signing the seller transaction
if (!reListingRequest.sellerOrdinalAddress) {
throw new Error('No seller address provided');
}
const sellerInput = {
address: reListingRequest.sellerOrdinalAddress,
signingIndexes: [0],
sigHash:
bitcoin.Transaction.SIGHASH_SINGLE |
bitcoin.Transaction.SIGHASH_ANYONECANPAY,
};
const payload = {
network: { type: this.network },
message: 'Sign Seller Transaction',
psbtBase64: psbt,
broadcast: false,
inputsToSign: [sellerInput],
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response) => {
try {
const confirmReListingPayload = {
ordinalId: reListingRequest.ordinalId,
signedListingPSBT: response.psbtBase64,
}
resolve(this.confirmReListing(confirmReListingPayload));
} catch (error) {
console.error('Error confirm relisting:', error);
reject(error);
}
},
onCancel: () => {
console.log('Transaction canceled');
}
});
});
} else {
throw new Error("Wallet not supported");
}
} catch (error) {
console.error('Error in reListing:', error);
throw error;
}
}
async createOffer(
createOfferRequest: MarketplaceCreateOfferRequest
): Promise<MarketplaceCreateOfferResponse | string> {
if (!createOfferRequest.walletProvider) {
return this.marketplaceInstance.createOffer(createOfferRequest);
} else if (createOfferRequest.walletProvider === WALLET_PROVIDER.xverse) {
const offer: MarketplaceCreateOfferResponse = await this.marketplaceInstance.createOffer(createOfferRequest);
const sellerInput = {
address: createOfferRequest.buyerPaymentAddress,
signingIndexes: offer.buyerInputIndices,
};
const payload = {
network: {
type: this.network,
},
message: 'Sign Buyer Transaction',
psbtBase64: offer.psbt,
broadcast: false,
inputsToSign: [sellerInput],
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response) => {
return resolve(response.psbtBase64)
},
onCancel: () => {
console.log('Transaction canceled');
}
});
});
} else {
throw new Error("Wallet not supported");
}
}
submitOffer(
submitOfferRequest: MarketplaceSubmitOfferRequest
): Promise<MarketplaceSubmitOfferResponse> {
return this.marketplaceInstance.submitOffer(submitOfferRequest);
}
confirmPaddingOutputs(
confirmPaddingOutputsRequest: MarketplaceConfirmPaddingOutputsRequest
): Promise<MarketplaceConfirmPaddingOutputsResponse> {
return this.marketplaceInstance.confirmPaddingOutputs(
confirmPaddingOutputsRequest
);
}
async setupPaddingOutputs(
setupPaddingOutputsRequest: MarketplaceSetupPaddingOutputsRequest
): Promise<MarketplaceSetupPaddingOutputsResponse> {
if (!setupPaddingOutputsRequest.walletProvider) {
return this.marketplaceInstance.setupPaddingOutputs(setupPaddingOutputsRequest);
} else if (setupPaddingOutputsRequest.walletProvider === WALLET_PROVIDER.xverse) {
const paddingOutputResponse: MarketplaceSetupPaddingOutputsResponse = await this.marketplaceInstance.setupPaddingOutputs(setupPaddingOutputsRequest);
const buyerInputs = {
address: setupPaddingOutputsRequest.address,
signingIndexes: paddingOutputResponse.buyerInputIndices
};
const payload = {
network: {
type: this.network,
},
message: 'Sign Padding Outputs Transaction',
psbtBase64: paddingOutputResponse.psbt,
broadcast: true,
inputsToSign: [buyerInputs],
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response) => response,
onCancel: () => {
console.log('Transaction canceled');
}
});
});
} else {
throw new Error("Wallet not supported");
}
}
getListing(
getListingRequest: MarketplaceGetListingRequest
): Promise<MarketplaceGetListingResponse> {
return this.marketplaceInstance.getListing(getListingRequest);
}
saveListing(
saveListingRequest: MarketplaceSaveListingRequest
): Promise<MarketplaceSaveListingResponse> {
return this.marketplaceInstance.saveListing(saveListingRequest);
}
/**
* Confirms a listing in the marketplace.
* @param {MarketplaceConfirmListingRequest} confirmListingRequest - The request object for confirming the listing.
* @returns {Promise<MarketplaceConfirmListingResponse>} A promise that resolves with the response from confirming the listing.
*/
confirmListing(
confirmListingRequest: MarketplaceConfirmListingRequest
): Promise<MarketplaceConfirmListingResponse> {
return this.marketplaceInstance.confirmListing(confirmListingRequest)
}
/**
* Confirms relisting in the marketplace.
* @param {MarketplaceConfirmReListRequest} confirmReListingRequest - The request object for confirming the listing.
* @returns {Promise<MarketplaceConfirmReListResponse>} A promise that resolves with the response from confirming the listing.
*/
confirmReListing(
confirmReListingRequest: MarketplaceConfirmReListRequest
): Promise<MarketplaceConfirmReListResponse> {
return this.marketplaceInstance.confirmReListing(confirmReListingRequest)
}
async transfer(
transferRequest: MarketplaceTransferRequest
): Promise<SignTransactionResponse | MarketplaceTransferAPIResponse> {
if (!transferRequest.walletProvider) {
return this.marketplaceInstance.transfer(
transferRequest
);
}
const transferResponse: MarketplaceTransferAPIResponse = await this.marketplaceInstance.transfer(transferRequest);
const inputsToSign = [
{
address: transferRequest.senderOrdinalAddress,
signingIndexes: transferResponse.senderOrdinalInputs,
sigHash: bitcoin.Transaction.SIGHASH_ALL,
},
{
address: transferRequest.senderPaymentAddress,
signingIndexes: transferResponse.senderPaymentInputs,
sigHash: bitcoin.Transaction.SIGHASH_ALL,
},
];
// Create the payload for signing the seller transaction
const payload = {
network: { type: this.network },
message: 'Sign Transfer Transaction',
psbtBase64: transferResponse.psbtBase64,
broadcast: true,
inputsToSign,
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response: any) => {
return resolve(response)
},
onCancel: () => {
console.log('Transaction canceled');
}
});
});
}
/**
* DeLists the listed ordinal from marketplace
* @param {MarketplaceDeListRequest} deListingRequest - The request object for confirming the listing.
* @returns {Promise<MarketplaceDeListAPIResponse>} A promise that resolves with the response from confirming the listing.
*/
async deList(
deListingRequest: MarketplaceDeListRequest
): Promise<MarketplaceDeListAPIResponse | MarketplaceConfirmDeListResponse> {
if (!deListingRequest.walletProvider) {
return this.marketplaceInstance.deList(
deListingRequest
);
}
const transferResponse: MarketplaceDeListAPIResponse = await this.marketplaceInstance.deList(deListingRequest);
const inputsToSign = [
{
address: deListingRequest.senderOrdinalAddress,
signingIndexes: transferResponse.senderOrdinalInputs,
sigHash: bitcoin.Transaction.SIGHASH_ALL,
},
{
address: deListingRequest.senderPaymentAddress,
signingIndexes: transferResponse.senderPaymentInputs,
sigHash: bitcoin.Transaction.SIGHASH_ALL,
},
];
// Create the payload for signing the seller transaction
const payload = {
network: { type: this.network },
message: 'Sign Transfer Transaction',
psbtBase64: transferResponse.psbtBase64,
broadcast: true,
inputsToSign,
};
return new Promise((resolve, reject) => {
signTransaction({
payload,
onFinish: async (response) => {
try {
const confirmDeListingPayload = {
ordinalId: deListingRequest.ordinalId,
sellerPaymentAddress: deListingRequest.senderPaymentAddress,
};
const confirmDeListResponse = await this.confirmDeListing(
confirmDeListingPayload
);
resolve({
...confirmDeListResponse,
txId: response?.txId,
});
} catch (error) {
console.error("Error delisting ordinal:", error);
reject(error);
}
},
onCancel: () => {
console.log("Transaction canceled");
},
});
});
}
/**
* Confirms delisting in the marketplace.
* @param {MarketplaceConfirmDeListRequest} confirmDeListingRequest - The request object for confirming the listing.
* @returns {Promise<MarketplaceConfirmDeListResponse>} A promise that resolves with the response from confirming the listing.
*/
confirmDeListing(
confirmDeListingRequest: MarketplaceConfirmDeListRequest
): Promise<MarketplaceConfirmDeListResponse> {
return this.marketplaceInstance.confirmDeListing(confirmDeListingRequest)
}
}