Skip to main content

What are Deals?

Deals are the foundation of the IOTA Repstation system. They represent agreements between two parties (Party A and Party B) that enable mutual rating after completion. Every rating in the system must be tied to a specific deal, ensuring accountability and preventing spam ratings.

Deal Lifecycle

Deals follow a strict three-state lifecycle:
1

PENDING

Deal is created by Party A but not yet accepted by Party B.
  • Only Party A can modify or cancel
  • No ratings allowed
  • Party B can accept to move to ACTIVE
2

ACTIVE

Both parties have agreed to the deal terms.
  • Deal is locked and cannot be modified
  • No ratings allowed yet
  • Either party can close the deal
3

CLOSED

Deal has been completed and closed.
  • Both parties can now rate each other
  • Deal cannot be reopened
  • Ratings can be updated or revoked

Deal Components

Participants

Each deal has exactly two participants:
  • Party A: The deal initiator (usually the service requester)
  • Party B: The deal acceptor (usually the service provider)

Subject Reference

Every deal includes a subject reference that identifies what the deal is about:
interface SubjectReference {
  type: string;  // e.g., "NFT", "SERVICE", "ORDER"
  id: string;    // e.g., "nft-123", "order-456"
}
Common Subject Types:
  • NFT - Non-fungible token transactions
  • SERVICE - Service agreements
  • ORDER - Purchase orders
  • LOAN - Lending agreements
  • ESCROW - Escrow services

Deal Amount

The monetary value associated with the deal, stored as a string to handle large numbers:
// Examples
amount: "1000"     // 1000 units
amount: "250000"   // 250k units
amount: "0"        // Free service

Creating Deals

Admin-Created Deals

Applications with admin capabilities can create deals directly:
const { deal_id } = await client.openDealAdmin({
  signer: adminWallet,
  admin_cap_id: adminCapability,
  party_b: customerWallet,
  subject_ref: {
    type: "ORDER",
    id: "ORD-2024-001"
  },
  amount: "15000"
});

Client-Created Deals

Users with client capabilities can create deals:
const { deal_id } = await client.openDealClient({
  signer: userWallet,
  client_cap_id: userCapability,
  party_b: providerWallet,
  subject_ref: {
    type: "SERVICE",
    id: "web-design-project"
  },
  amount: "50000"
});

Deal Acceptance

Only Party B can accept a pending deal:
// Party B accepts the deal
await client.acceptDeal({
  signer: partyBWallet,
  deal_id: dealId
});
Once a deal is accepted, it cannot be modified. Ensure all terms are agreed upon before acceptance.

Deal Completion

Either party can close an active deal:
// Close the deal when work is completed
await client.closeDeal({
  signer: partyWallet, // Can be either party
  deal_id: dealId
});

Deal States and Permissions

StateParty A CanParty B CanRatings Allowed
PENDINGCancel, CloseAccept
ACTIVECloseClose
CLOSEDRate Party BRate Party A

Best Practices

1. Clear Subject References

Use descriptive and unique subject references:
// Good
subject_ref: {
  type: "NFT_MARKETPLACE_SALE",
  id: "cryptopunk-7804-sale-2024"
}

// Avoid
subject_ref: {
  type: "SALE",
  id: "123"
}

2. Accurate Amounts

Always specify the correct deal amount:
// For a $150 service (assuming token has 2 decimals)
amount: "15000"  // 150.00 in smallest units

3. Timely Deal Closure

Close deals promptly when work is completed to enable rating:
// In your application logic
async function markOrderDelivered(orderId: string) {
  // Update your database
  await db.orders.update(orderId, { status: 'delivered' });
  
  // Close the reputation deal
  const order = await db.orders.findById(orderId);
  await reputationClient.closeDeal({
    signer: adminWallet,
    deal_id: order.reputationDealId
  });
}

Error Handling

Common deal-related errors and solutions:
try {
  await client.acceptDeal({ signer, deal_id });
} catch (error) {
  switch (error.code) {
    case 'DEAL_NOT_FOUND':
      console.error('Deal ID does not exist');
      break;
    case 'NOT_PARTY_B':
      console.error('Only Party B can accept this deal');
      break;
    case 'DEAL_ALREADY_ACCEPTED':
      console.error('Deal is already in ACTIVE state');
      break;
    case 'DEAL_ALREADY_CLOSED':
      console.error('Deal has been closed');
      break;
  }
}

Integration Patterns

E-commerce Integration

class OrderService {
  async createOrder(buyerId: string, sellerId: string, productId: string, amount: number) {
    // Create order in your system
    const order = await this.db.orders.create({
      buyerId, sellerId, productId, amount,
      status: 'pending'
    });
    
    // Create reputation deal
    const dealResult = await this.reputation.openDealAdmin({
      signer: this.adminWallet,
      admin_cap_id: this.adminCap,
      party_b: buyerId,
      subject_ref: {
        type: 'ECOMMERCE_ORDER',
        id: order.id
      },
      amount: amount.toString()
    });
    
    // Link deal to order
    await this.db.orders.update(order.id, {
      reputationDealId: dealResult.deal_id
    });
    
    return order;
  }
}

Service Platform Integration

class ServiceBooking {
  async bookService(clientId: string, providerId: string, serviceType: string, fee: number) {
    // Create booking
    const booking = await this.createBooking({
      clientId, providerId, serviceType, fee
    });
    
    // Auto-accept deal for service bookings
    const dealResult = await this.reputation.openDealClient({
      signer: clientId,
      client_cap_id: await this.getClientCap(clientId),
      party_b: providerId,
      subject_ref: {
        type: 'SERVICE_BOOKING',
        id: booking.id
      },
      amount: fee.toString()
    });
    
    // Auto-accept if provider is online
    if (await this.isProviderOnline(providerId)) {
      await this.reputation.acceptDeal({
        signer: providerId,
        deal_id: dealResult.deal_id
      });
    }
    
    return booking;
  }
}

Next Steps