UNPKG

@tatumio/tatum-v1

Version:

Tatum API client allows browsers and Node.js clients to interact with Tatum API.

354 lines 34 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sendAuctionSettle = exports.sendAuctionCancel = exports.sendAuctionBid = exports.sendAuctionCreate = exports.sendAuctionApproveErc20Transfer = exports.sendAuctionApproveNftTransfer = exports.sendAuctionUpdateFeeRecipient = exports.sendAuctionUpdateFee = exports.prepareAuctionSettle = exports.prepareAuctionCancel = exports.prepareAuctionBid = exports.existsAuction = exports.prepareAuctionCreate = exports.prepareAuctionApproveErc20Transfer = exports.prepareAuctionApproveNftTransfer = exports.prepareAuctionUpdateFeeRecipient = exports.prepareAuctionUpdateFee = exports.prepareDeployAuction = exports.deployAuction = exports.getAuctionFeeRecipient = exports.getAuction = exports.getAuctionFee = void 0; const bignumber_js_1 = __importDefault(require("bignumber.js")); const tatum_1 = require("../../connector/tatum"); const erc1155_abi_1 = __importDefault(require("../../contracts/erc1155/erc1155_abi")); const erc721_abi_1 = __importDefault(require("../../contracts/erc721Cashback/erc721_abi")); const marketplace_1 = require("../../contracts/marketplace"); const fungible_1 = require("../../fungible"); const helpers_1 = require("../../helpers"); const model_1 = require("../../model"); const transaction_1 = require("../../transaction"); const caver_js_1 = __importDefault(require("caver-js")); const constants_1 = require("../../constants"); /** * For more details, see <a href="https://apidoc.tatum.io/#operation/MPAuctionFee" target="_blank">Tatum API documentation</a> */ const getAuctionFee = async (chain, contractAddress) => tatum_1.get(`/v3/blockchain/auction/auction/${chain}/${contractAddress}/fee`); exports.getAuctionFee = getAuctionFee; /** * For more details, see <a href="https://apidoc.tatum.io/#operation/MPAuction" target="_blank">Tatum API documentation</a> */ const getAuction = async (chain, contractAddress, auctionId) => tatum_1.get(`/v3/blockchain/auction/auction/${chain}/${contractAddress}/auction/${auctionId}`); exports.getAuction = getAuction; /** * For more details, see <a href="https://apidoc.tatum.io/#operation/MPAuctionRecipient" target="_blank">Tatum API documentation</a> */ const getAuctionFeeRecipient = async (chain, contractAddress) => tatum_1.get(`/v3/blockchain/auction/auction/${chain}/${contractAddress}/recipient`); exports.getAuctionFeeRecipient = getAuctionFeeRecipient; /** * Deploy new smart contract for NFT auction logic. Smart contract enables auction operator to create new auction for NFT (ERC-721/1155). * Operator can set a fee in percentage, which will be paid on top of the price of the asset. * can be offered for native asset - ETH, BSC, etc. - or any ERC20 token - this is configurable during auction creation. * Before auction is created, seller must approve transfer of the NFT to the auction contract. * Buyer will bid for the asset from the auction using native asset - send assets along the gid() smart contract call, or via ERC20 token. * Buyer of the auction must perform approval for the smart contract to access ERC20 token, before the actual bid() method is called. * Once there is higher bid than the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one. * When auction ends, anyone can settle the auction - NFT will be sent to the bidder, assets to the seller and fee to the operator. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const deployAuction = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareDeployAuction(testnet, body, provider)); }; exports.deployAuction = deployAuction; /** * Prepare signed transaction for NFT auction logic. Smart contract enables auction operator to create new auction for NFT (ERC-721/1155). * Operator can set a fee in percentage, which will be paid on top of the price of the asset. * can be offered for native asset - ETH, BSC, etc. - or any ERC20 token - this is configurable during auction creation. * Before auction is created, seller must approve transfer of the NFT to the auction contract. * Buyer will bid for the asset from the auction using native asset - send assets along the gid() smart contract call, or via ERC20 token. * Buyer of the auction must perform approval for the smart contract to access ERC20 token, before the actual bid() method is called. * Once there is higher bid than the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one. * When auction ends, anyone can settle the auction - NFT will be sent to the bidder, assets to the seller and fee to the operator. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareDeployAuction = async (testnet, body, provider) => { switch (body.chain) { case model_1.Currency.CELO: return await transaction_1.prepareCeloDeployAuctionSignedTransaction(testnet, body, provider); case model_1.Currency.ONE: return await transaction_1.prepareOneDeployAuctionSignedTransaction(testnet, body, provider); case model_1.Currency.ETH: return await transaction_1.prepareEthDeployAuctionSignedTransaction(body, provider); case model_1.Currency.BSC: return await transaction_1.prepareBscDeployAuctionSignedTransaction(body, provider); case model_1.Currency.MATIC: return await transaction_1.preparePolygonDeployAuctionSignedTransaction(testnet, body, provider); case model_1.Currency.KLAY: return await transaction_1.prepareKlaytnDeployAuctionSignedTransaction(testnet, body, provider); default: throw new Error('Unsupported chain'); } }; exports.prepareDeployAuction = prepareDeployAuction; /** * Update auction fee. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionUpdateFee = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.UpdateAuctionFee); const params = [`0x${new bignumber_js_1.default(body.auctionFee).toString(16)}`]; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.UpdateAuctionFee, 'setAuctionFee', params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionUpdateFee = prepareAuctionUpdateFee; /** * Update auction fee recipient. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionUpdateFeeRecipient = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.UpdateMarketplaceFeeRecipient); const params = [body.feeRecipient]; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.UpdateMarketplaceFeeRecipient, 'setAuctionFeeRecipient', params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionUpdateFeeRecipient = prepareAuctionUpdateFeeRecipient; /** * Approve NFT transfer for auction to perform listing of the asset. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionApproveNftTransfer = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.ApproveNftTransfer); const params = body.isErc721 ? [body.spender, `0x${new bignumber_js_1.default(body.tokenId).toString(16)}`] : [body.spender, true]; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.ApproveNftTransfer, body.isErc721 ? 'approve' : 'setApprovalForAll', params, undefined, provider, body.isErc721 ? erc721_abi_1.default : erc1155_abi_1.default); }; exports.prepareAuctionApproveNftTransfer = prepareAuctionApproveNftTransfer; /** * Approve ERC20 transfer for auction to perform bidding on the asset in the auction. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionApproveErc20Transfer = async (testnet, body, provider) => { return fungible_1.prepareApproveErc20(testnet, body, provider); }; exports.prepareAuctionApproveErc20Transfer = prepareAuctionApproveErc20Transfer; /** * Create new auction on the auction contract. Before auction, seller must approve spending of the NFT token for the Auction contract. * After auction is created, auction contract transfers the asset to the auction smart contract. * Only auction for existing NFTs can be created - seller must be owner of the NFT asset. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionCreate = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.CreateAuction); if (await exports.existsAuction(testnet, body.chain, body.id, body.contractAddress, provider)) { throw new Error(`Auction with id ${body.id} already exist`); } const params = [body.id, body.isErc721, body.nftAddress.trim(), `0x${new bignumber_js_1.default(body.tokenId).toString(16)}`, body.seller.trim(), `0x${new bignumber_js_1.default(body.amount || 0).toString(16)}`, `0x${new bignumber_js_1.default(body.endedAt).toString(16)}`, body.erc20Address || '0x0000000000000000000000000000000000000000']; body.amount = undefined; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.CreateAuction, 'createAuction', params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionCreate = prepareAuctionCreate; const existsAuction = async (testnet, chain, id, contractAddress, provider) => { let data = []; try { const web3 = helpers_1.helperGetWeb3Client(testnet, chain, provider); const c = web3 instanceof caver_js_1.default ? web3.klay : web3.eth; // @ts-ignore const contract = new c.Contract(marketplace_1.auction.abi, helpers_1.normalizeAddress(chain, contractAddress)); data = await contract.methods.getAuction(id).call(); if (data[0] === constants_1.ZERO_ADDRESS.ZERO_ADDRESS_42_CHARS) { return false; } } catch (e) { return false; } return true; }; exports.existsAuction = existsAuction; /** * Bid on the auction. Buyer must either send native assets with this operation, or approve ERC20 token spending before. * After auction is sold, it's in a pending state to be processed by the auction. Noone receives the assets unless the auction operator processes that. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionBid = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.InvokeAuctionOperation); const web3 = helpers_1.helperGetWeb3Client(testnet, body.chain, provider); const c = web3 instanceof caver_js_1.default ? web3.klay : web3.eth; // @ts-ignore const a = await (new c.Contract(marketplace_1.auction.abi, body.contractAddress)).methods.getAuction(body.id).call(); let decimals = 18; let methodName = 'bid'; const b = Object.assign({}, body); if (a[6] !== '0x0000000000000000000000000000000000000000') { // @ts-ignore decimals = await fungible_1.getErc20Decimals(testnet, body.chain, a[6], provider); if (body.bidder) { methodName = 'bidForExternalBidder'; } } else if (body.bidder) { throw new Error('Bidder could be present only for ERC20 based auctions.'); } else { b.amount = body.amount ? body.amount : body.bidValue; } const params = [body.id, `0x${new bignumber_js_1.default(body.bidValue).multipliedBy(new bignumber_js_1.default(10).pow(decimals)).toString(16)}`]; if (body.bidder) { params.push(body.bidder.trim()); } return await helpers_1.helperPrepareSCCall(testnet, b, model_1.InvokeAuctionOperation, methodName, params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionBid = prepareAuctionBid; /** * Cancel auction on the auction. Only possible for the seller or the operator. There must be no buyer present for that auction. NFT asset is sent back to the seller. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionCancel = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.InvokeAuctionOperation); const params = [body.id]; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.InvokeAuctionOperation, 'cancelAuction', params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionCancel = prepareAuctionCancel; /** * Settle auction. There must be buyer present for that auction. NFT will be sent to the bidder, assets to the seller and fee to the operator. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const prepareAuctionSettle = async (testnet, body, provider) => { await tatum_1.validateBody(body, model_1.InvokeAuctionOperation); const params = [body.id]; return await helpers_1.helperPrepareSCCall(testnet, body, model_1.InvokeAuctionOperation, 'settleAuction', params, undefined, provider, marketplace_1.auction.abi); }; exports.prepareAuctionSettle = prepareAuctionSettle; /** * Update auction fee. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionUpdateFee = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.put(`v3/blockchain/auction/fee`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionUpdateFee(testnet, body, provider)); }; exports.sendAuctionUpdateFee = sendAuctionUpdateFee; /** * Update auction fee recipient. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionUpdateFeeRecipient = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.put(`v3/blockchain/auction/recipient`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionUpdateFeeRecipient(testnet, body, provider)); }; exports.sendAuctionUpdateFeeRecipient = sendAuctionUpdateFeeRecipient; /** * Approve NFT transfer for auction to perform listing of the asset. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionApproveNftTransfer = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction/approve`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionApproveNftTransfer(testnet, body, provider)); }; exports.sendAuctionApproveNftTransfer = sendAuctionApproveNftTransfer; /** * Approve ERC20 transfer for auction to perform bidding on the asset in the auction. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionApproveErc20Transfer = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/token/approve`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionApproveErc20Transfer(testnet, body, provider)); }; exports.sendAuctionApproveErc20Transfer = sendAuctionApproveErc20Transfer; /** * Create new auction on the auction contract. Before auction, seller must approve spending of the NFT token for the Auction contract. * After auction is created, auction contract transfers the asset to the auction smart contract. * Only auction for existing NFTs can be created - seller must be owner of the NFT asset. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionCreate = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction/sell`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionCreate(testnet, body, provider)); }; exports.sendAuctionCreate = sendAuctionCreate; /** * Bid auction on the auction. Buyer must either send native assets with this operation, or approve ERC20 token spending before. * After auction is sold, it's in a pending state to be processed by the auction. Noone receives the assets unless the auction operator processes that. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionBid = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction/bid`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionBid(testnet, body, provider)); }; exports.sendAuctionBid = sendAuctionBid; /** * Cancel auction on the auction. Only possible for the seller or the operator. There must be no buyer present for that auction. NFT asset is sent back to the seller. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionCancel = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction/cancel`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionCancel(testnet, body, provider)); }; exports.sendAuctionCancel = sendAuctionCancel; /** * Settle auction. There must be buyer present for that auction. NFT will be sent to the bidder, assets to the seller and fee to the operator. * @param testnet chain to work with * @param body request data * @param provider optional provider to enter. if not present, Tatum Web3 will be used. * @returns {txId: string} Transaction ID of the operation, or signatureID in case of Tatum KMS */ const sendAuctionSettle = async (testnet, body, provider) => { if (body.signatureId) { return await tatum_1.post(`v3/blockchain/auction`, body); } return helpers_1.helperBroadcastTx(body.chain, await exports.prepareAuctionSettle(testnet, body, provider)); }; exports.sendAuctionSettle = sendAuctionSettle; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9uZnQvbWFya2V0cGxhY2UvYXVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxnRUFBcUM7QUFDckMsaURBQXFFO0FBQ3JFLHNGQUE4RDtBQUM5RCwyRkFBbUU7QUFDbkUsNkRBQXNEO0FBQ3RELDZDQUF1RTtBQUN2RSwyQ0FBOEc7QUFDOUcsdUNBU3FCO0FBQ3JCLG1EQU8yQjtBQUMzQix3REFBNEI7QUFDNUIsK0NBQThDO0FBa0Q5Qzs7R0FFRztBQUNJLE1BQU0sYUFBYSxHQUFHLEtBQUssRUFBRSxLQUFlLEVBQUUsZUFBdUIsRUFBbUIsRUFBRSxDQUMvRixXQUFHLENBQUMsa0NBQWtDLEtBQUssSUFBSSxlQUFlLE1BQU0sQ0FBQyxDQUFDO0FBRDNELFFBQUEsYUFBYSxpQkFDOEM7QUFFeEU7O0dBRUc7QUFDSSxNQUFNLFVBQVUsR0FBRyxLQUFLLEVBQUUsS0FBZSxFQUFFLGVBQXVCLEVBQUUsU0FBaUIsRUFBb0IsRUFBRSxDQUNoSCxXQUFHLENBQUMsa0NBQWtDLEtBQUssSUFBSSxlQUFlLFlBQVksU0FBUyxFQUFFLENBQUMsQ0FBQztBQUQ1RSxRQUFBLFVBQVUsY0FDa0U7QUFFekY7O0dBRUc7QUFDSSxNQUFNLHNCQUFzQixHQUFHLEtBQUssRUFBRSxLQUFlLEVBQUUsZUFBdUIsRUFBZ0MsRUFBRSxDQUNySCxXQUFHLENBQUMsa0NBQWtDLEtBQUssSUFBSSxlQUFlLFlBQVksQ0FBQyxDQUFDO0FBRGpFLFFBQUEsc0JBQXNCLDBCQUMyQztBQUc5RTs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0ksTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLE9BQWdCLEVBQUUsSUFBc0IsRUFBRSxRQUFpQixFQUFFLEVBQUU7SUFDakcsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO1FBQ3BCLE9BQU8sTUFBTSxZQUFJLENBQUMsdUJBQXVCLEVBQUUsSUFB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