List

List


Create Listing

A listing can be created with this command.

[!IMPORTANT] You cannot create multiple listings with the same contract ID in one command. Only the first listing will be processed.

Commands

[!NOTE] An order ID is created and the order ID is always the first UTXO that is spent.

[UTXO_SENDER_1, UTXO_SENDER_2, ... ,UTXO_SENDER_N] is the list of UTXOs containing the tokens for the listing. CHANGE_UTXO is the UTXO the change gets bound to. LISTING_UTXO is the UTXO the listing gets bound to. LISTING_AMOUNT is the quantity of the token being listed. SELL_PRICE is price per token of the token being lsited. PAY_ADDRESS is the address the BTC payment must go to (usually the lister's address).

Single List

<TXID, 
    {CONTRACT_ID_1:LIST[
        [UTXO_SENDER_1, UTXO_SENDER_2, ... ,UTXO_SENDER_N],
        CHANGE_UTXO,
        LISTING_UTXO,
        LISTING_AMOUNT,
        SELL_PRICE,
        PAY_ADDRESS]}>

Batched List

<TXID, 
    {CONTRACT_ID_1:LIST[
        [UTXO_SENDER_1, UTXO_SENDER_2, ... ,UTXO_SENDER_N],
        CHANGE_UTXO,
        LISTING_UTXO,
        LISTING_AMOUNT,
        SELL_PRICE,
        PAY_ADDRESS]},
    {CONTRACT_ID_2:LIST[
        [UTXO_SENDER_1, UTXO_SENDER_2, ... ,UTXO_SENDER_N],
        CHANGE_UTXO,
        LISTING_UTXO,
        LISTING_AMOUNT,
        SELL_PRICE,
        PAY_ADDRESS]},
    ...,
    {CONTRACT_ID_N:LIST
        [UTXO_SENDER_1, UTXO_SENDER_2, ... ,UTXO_SENDER_N],
        CHANGE_UTXO,
        LISTING_UTXO,
        LISTING_AMOUNT,
        SELL_PRICE,
        PAY_ADDRESS]}>

Examples

Single List

<8380c54d943ec72857b3022da9906e6f7da5bb8220ab03ed7b5b0a724144c5f2,
    {3b1b20518485ec89ce9acf5bb23c5ccdb0ac26d0661e377014e894d295eec29e:LIST[
        [9859b9e8d3d1a343819f22876c74fc3b304438083f005378f7e64085c7c5bf27:0,55c9d410e1c0fa7ff62efbad05361da919f7c77b7ef14590e6db5d4a1954a698:0],
        TXID:0,
        TXID:1,
        100000000,
        10000,
        tb1ql2qy8ecqdtfdd0np54c75vzlymkqykfc4uaa9h]}>

Batched List

<07de2d16fb4a0dc653f1667f52ebc05da24ada755bc68cd7c44bfefef4b95325,
    {0eebc6baa4463e8f0f9f8cf31440ed12e9f312671b334de97e338380ee1f5cc1:LIST[
        [a3e71f146c17db792d12e24a25957a0fe7baebfc40b0bf3a9bb1d52f8ce9844b:6],
        TXID:0,
        TXID:1,
        9462500000000,
        2,
        tb1q3aryc8esjula2m87k2gr3fmme8mjnmwulx8lm4]},
    {6a6787f011052aca7955a2c3c90e836f94f80d0918ba5b9b57e85ec3676857d7:LIST[
        [494afb28cd5de10ab76394ccaf18f6f2ee7e4fe0d8c19ad04fc4b40e63f7be92:1],
        TXID:2,
        TXID:3,
        50000000000,
        2000,
        tb1q3aryc8esjula2m87k2gr3fmme8mjnmwulx8lm4]}>

Implementations

Rust

pub fn list(&mut self, txid: &String, payload: &String, sender_utxos: &Vec<String>, new_listing: Listing, current_block_height:u64) -> Result<(String,u64,bool), String> {
    let mut owners_amount: u64 = 0;
    for sender_utxo in sender_utxos.clone() {
        if self.owners.contains_key(&sender_utxo) {
            owners_amount += self.owners[&sender_utxo];
        }
    }
    if owners_amount == 0 {
        return Err("list: owner amount is zero".to_string());
    }

    if sender_utxos.len() == 0 {
        return Err("list: no senders".to_string());
    }

    let mut new_owner = (new_listing.change_utxo.to_string(),0,false);

    if new_listing.list_amt <= owners_amount {
        let mut drips = match self.drips.clone() {
            Some(drips) => drips,
            None => HashMap::new(),
        };

        for sender_utxo in sender_utxos.clone() {
            if self.owners.contains_key(&sender_utxo) {
                self.owners.remove(&sender_utxo);
            }

            if let Some(old_drips) = drips.get(&sender_utxo) {
                let mut new_drips: Vec<Drip> = Vec::new();
                for drip in old_drips {
                    let new_drip = Drip {
                        block_end: drip.block_end.clone(),
                        drip_amount: drip.drip_amount.clone(),
                        amount: drip.amount.clone() - (current_block_height - drip.start_block) * drip.drip_amount,
                        start_block: current_block_height,
                        last_block_dripped:current_block_height.clone()
                    };
                    new_drips.push(new_drip.clone());
                }

                drips.insert(new_listing.change_utxo.clone(),new_drips);
                drips.remove(&sender_utxo);
                new_owner.2 = true;
            }
        }

        let change_amt: u64 = owners_amount - new_listing.list_amt;
        if change_amt > 0 {
            if self.owners.contains_key(&new_listing.change_utxo) {
                let new_amount = self.owners[&new_listing.change_utxo] + change_amt;
                new_owner.1 = new_amount.clone();
                self.owners.insert(new_listing.change_utxo.to_string(), new_amount);
            } else {
                new_owner.1 = change_amt.clone();
                self.owners.insert(new_listing.change_utxo.to_string(), change_amt);
            }
        }
        
        let order_id: String = sender_utxos[0].to_string();
        let mut listing = match self.listings.clone() {
            Some(listings) => listings,
            None => HashMap::new(),
        };

        listing.insert(order_id, new_listing.clone());
        self.listings = Some(listing);
        self.drips = Some(drips);
        self.payloads.insert(txid.to_string(), payload.to_string());
    }
    return Ok(new_owner);
}

Cancel Listing

A listing can be cancelled with this command.

Commands

LISTING_UTXO is the UTXO the listing is bound to.

<TXID, 
    {CONTRACT_ID_1:CANCELLISTING[
        LISTING_UTXO]}>

Examples

<c6dee0b8c41255ddd4faba2916b37797a5c0632ba56fa597c72471fa8fde39f3,
    {05874c81d5f3b83880d112178d09dbe2845148d256d4183936229547d8497505:CANCELLISTING[
        c894c5c8ea21bfe8c9aa0d9295db235ad74ec307ed4a493c06dd0393288608f7:1]}>

Implementations

Rust

pub fn cancel_listing(&mut self, txid: &String, listing_utxo: &String,  payload: String) -> Result<i32, String> {
    let mut bids_available = match self.bids.clone() {
        Some(bids_available) => bids_available,
        None => HashMap::new(),
    };

    let fulfillments = match self.fulfillments.clone() {
        Some(fulfillments) => fulfillments,
        None => HashMap::new(),
    };

    let mut listings = match self.listings.clone() {
        Some(listings) => listings,
        None => return Err("cancel_listing: no listings for contract".to_string()),
    };

    let mut canceled_listing = Listing::default();
    let mut order_id = String::new();
    for (key, value) in listings.clone() {
        if value.list_utxo == listing_utxo.to_string() {
            canceled_listing = value.clone();
            order_id = key.clone();
            break;
        }
    }

    for (_, value) in fulfillments {
        if value == order_id{
            return Err("cancel_listing: order has been fulfilled".to_string());
        }
    }

    let recievers_utxo: String = format!("{}:0",txid);
    if self.owners.contains_key(&recievers_utxo) {
        let new_amount = self.owners[&recievers_utxo] + canceled_listing.list_amt;
        self.owners.insert(recievers_utxo.to_string(), new_amount);
    } else {
        self.owners.insert(recievers_utxo.to_string(), canceled_listing.list_amt);
    }

    listings.remove(&order_id);

    for (key, value) in bids_available.clone().iter_mut() {
        if value.order_id == order_id.to_string() {
            bids_available.remove(key);
        }
    }

    self.bids = Some(bids_available.clone());
    self.listings = Some(listings.clone());

    self.payloads.insert(txid.to_string(), payload);
    return Ok(0);
}