Take list as seller - tx

Take the ๐”‰rc20 token purchase listing as a seller

Example of Fixes Inscription data string:

op=list-take-sellnow,tick=fixes,amt=10000.0

Transaction parameters:

Key
Required
FType
Description

tick

t.String

Ticker: identity of the ๐”‰rc20 token

batchSellItems

t.Dictionary({ key: t.String, value: t.UFix64 })

The dictionary for selling:

rankedId => Amount You can get RankedListingId by querying the marketplace

๐Ÿ““Note: The key of batchSellItems should be itemInMarket.rankedId which can be obtained in the response of querying listings. and the value is how much tokens you will take in the order. ๐”‰rc20 trading orders support partial deal.

Transaction code example:

import txUserTakeAsSeller from "@fixes/contracts/transactions/marketplace/user-take-as-seller-with-commission.cdc?raw";

async function userTakeAsSeller(
  tick: string,
  batchSellItems: Record<string, number>
) {
  let args: Array<{ key: string; value: string }> = [];
  for (const key in batchSellItems) {
    if (!Object.prototype.hasOwnProperty.call(batchSellItems, key)) continue;
    args.push({
      key,
      value: batchSellItems[key].toFixed(8),
    });
  }
  const txid = await flow.sendTransaction(txUserTakeAsSeller, (arg, t) => [
    arg(tick, t.String),
    arg(args, t.Dictionary({ key: t.String, value: t.UFix64 })),
  ]);
  return txid;
}

Transaction source code

https://github.com/fixes-world/fixes/blob/main/cadence/transactions/marketplace/user-take-as-seller-with-commission.cdc
// Thirdparty imports
import "MetadataViews"
import "FungibleToken"
import "FlowToken"
// Fixes imports
import "Fixes"
import "FixesInscriptionFactory"
import "FixesAvatar"
import "FixesHeartbeat"
import "FRC20FTShared"
import "FRC20Indexer"
import "FRC20TradingRecord"
import "FRC20Storefront"
import "FRC20Marketplace"
import "FRC20MarketManager"

transaction(
    tick: String,
    // RankedId => SellAmount
    batchSellItems: {String: UFix64},
) {
    let market: &{FRC20Marketplace.MarketPublic}

    prepare(acct: auth(Storage, Capabilities) &Account) {
        /** ------------- Prepare the Inscription Store - Start ---------------- */
        let storePath = Fixes.getFixesStoreStoragePath()
        if acct.storage
            .borrow<auth(Fixes.Manage) &Fixes.InscriptionsStore>(from: storePath) == nil {
            acct.storage.save(<- Fixes.createInscriptionsStore(), to: storePath)
        }

        let store = acct.storage
            .borrow<auth(Fixes.Manage) &Fixes.InscriptionsStore>(from: storePath)
            ?? panic("Could not borrow a reference to the Inscriptions Store!")
        /** ------------- End -------------------------------------------------- */

        /** ------------- Start -- FRC20 Marketplace -------------  */
        // Borrow a reference to the FRC20Marketplace contract
        self.market = FRC20MarketManager.borrowMarket(tick)
            ?? panic("Could not borrow reference to the FRC20Market")

        assert(
            self.market.getTickerName() == tick,
            message: "The market is not for the FRC20 token with tick ".concat(tick)
        )
        assert(
            self.market.canAccess(addr: acct.address),
            message: "You are not allowed to access this market for now."
        )
        /** ------------- End -------------------------------------  */

        /** ------------- Start -- TradingRecords General Initialization -------------  */
        // Ensure hooks are initialized
        if acct.storage.borrow<&AnyResource>(from: FRC20FTShared.TransactionHookStoragePath) == nil {
            let hooks <- FRC20FTShared.createHooks()
            acct.storage.save(<- hooks, to: FRC20FTShared.TransactionHookStoragePath)
        }

        // link the hooks to the public path
        if acct
            .capabilities.get<&FRC20FTShared.Hooks>(FRC20FTShared.TransactionHookPublicPath)
            .borrow() == nil {
            // link the hooks to the public path
            acct.capabilities.unpublish(FRC20FTShared.TransactionHookPublicPath)
            acct.capabilities.publish(
                acct.capabilities.storage.issue<&FRC20FTShared.Hooks>(FRC20FTShared.TransactionHookStoragePath),
                at: FRC20FTShared.TransactionHookPublicPath
            )
        }

        // borrow the hooks reference
        let hooksRef = acct.storage
            .borrow<auth(FRC20FTShared.Manage) &FRC20FTShared.Hooks>(from: FRC20FTShared.TransactionHookStoragePath)
            ?? panic("The hooks were not created")

        // Ensure Trading Records is initialized
        if acct.storage.borrow<&AnyResource>(from: FRC20TradingRecord.TradingRecordsStoragePath) == nil {
            let tradingRecords <- FRC20TradingRecord.createTradingRecords(nil)
            acct.storage.save(<- tradingRecords, to: FRC20TradingRecord.TradingRecordsStoragePath)
            // link the trading records to the public path
            acct.capabilities.unpublish(FRC20TradingRecord.TradingRecordsPublicPath)
            acct.capabilities.publish(
                acct.capabilities.storage.issue<&FRC20TradingRecord.TradingRecords>(FRC20TradingRecord.TradingRecordsStoragePath),
                at: FRC20TradingRecord.TradingRecordsPublicPath
            )
        }

        // Ensure trading record hook is added to the hooks
        // get the public capability of the trading record hook
        let tradingRecordsCap = acct
            .capabilities.get<&FRC20TradingRecord.TradingRecords>(
                FRC20TradingRecord.TradingRecordsPublicPath
            )
        assert(tradingRecordsCap.check(), message: "The trading record hook is not valid")
        // get the reference of the trading record hook
        let recordsRef = tradingRecordsCap.borrow() ?? panic("The trading record hook is not valid")
        if !hooksRef.hasHook(recordsRef.getType()) {
            hooksRef.addHook(tradingRecordsCap)
        }

        // Ensure Fixes Avatar is initialized
        if acct.storage.borrow<&AnyResource>(from: FixesAvatar.AvatarStoragePath) == nil {
            acct.storage.save(<- FixesAvatar.createProfile(), to: FixesAvatar.AvatarStoragePath)
            // link the avatar to the public path
            acct.capabilities.unpublish(FixesAvatar.AvatarPublicPath)
            acct.capabilities.publish(
                acct.capabilities.storage.issue<&FixesAvatar.Profile>(FixesAvatar.AvatarStoragePath),
                at: FixesAvatar.AvatarPublicPath
            )
        }
        let profileCap = FixesAvatar.getProfileCap(acct.address)
        assert(profileCap.check(), message: "The profile is not valid")
        let profileRef = profileCap.borrow() ?? panic("The profile is not valid")
        if !hooksRef.hasHook(profileRef.getType()) {
            hooksRef.addHook(profileCap)
        }
        /** ------------- End -----------------------------------------------------------------  */

        // Get a reference to the signer's stored vault
        let vaultRef = acct.storage
            .borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
            ?? panic("Could not borrow reference to the owner's Vault!")

        // For each buy item, check the listing
        for rankedId in batchSellItems.keys {
            let listedItem = self.market.getListedItemByRankdedId(rankedId: rankedId)
            /** ------------- Start -- FRC20 Storefront Initialization -------------  */
            // Do not panic for better UX
            if listedItem == nil {
                continue
            }
            let storefront = listedItem!.borrowStorefront()
            let listing = listedItem!.borrowListing()
            // Do not panic for better UX
            if storefront == nil || listing == nil {
                continue
            }
            let listingDetails = listing!.getDetails()
            // Do not panic for better UX
            if listingDetails.status != FRC20Storefront.ListingStatus.Available {
                continue
            }
            if listingDetails.type != FRC20Storefront.ListingType.FixedPriceSellNow {
                continue
            }
            if listingDetails.tick != tick {
                continue
            }
            /** ------------- End --------------------------------------------------  */

            var commissionFlowRecipient: Capability<&FlowToken.Vault>? = nil
            if let receivers = listing!.getAllowedCommissionReceivers() {
                if receivers.length > 0 {
                    commissionFlowRecipient = receivers[0]
                    assert(commissionFlowRecipient!.check(), message: "Invalid commission recipient")
                }
            }

            let sellAmount = batchSellItems[rankedId]!

            /** ------------- Start -- Inscription Initialization -------------  */
            // create the metadata
            let dataStr = FixesInscriptionFactory.buildMarketTakeSellNow(tick: tick, amount: sellAmount)

            // estimate the required storage
            let estimatedReqValue = FixesInscriptionFactory.estimateFrc20InsribeCost(dataStr)

            // Withdraw tokens from the signer's stored vault
            // Total amount to withdraw is the estimated required value + the buy price
            let flowToReserve <- vaultRef.withdraw(amount: estimatedReqValue)

            // Create the Inscription first
            let newInsId = FixesInscriptionFactory.createAndStoreFrc20Inscription(
                dataStr,
                <- (flowToReserve as! @FlowToken.Vault),
                store
            )
            // borrow a reference to the new Inscription
            let insRef = store.borrowInscriptionWritableRef(newInsId)
                ?? panic("Could not borrow reference to the new Inscription!")
            /** ------------- End ---------------------------------------------  */

            // execute taking
            listing?.takeSellNow(ins: insRef, commissionRecipient: commissionFlowRecipient)

            // cleanup
            self.market.tryRemoveCompletedListing(rankedId: listedItem!.rankedId)
        }
    }

    execute {
        log("Done: user take as seller with commission")
    }
}

Last updated