🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Alkahest Developer

by @mlegls

Help developers write code that interacts with Alkahest escrow contracts using the TypeScript, Rust, or Python SDK

Versionv1.0.0
Downloads454
TERMINAL
clawhub install alkahest-developer

πŸ“– About This Skill


name: alkahest-developer description: Help developers write code that interacts with Alkahest escrow contracts using the TypeScript, Rust, or Python SDK

Alkahest Developer Skill

When to Use

Use this skill when a developer wants to write code that interacts with Alkahest escrow contracts. This covers:

  • Integrating Alkahest into an application
  • Writing bots/agents that create escrows, fulfill obligations, or arbitrate
  • Building custom arbiters or obligation contracts
  • Understanding SDK patterns and APIs
  • SDK Overview

    | SDK | Language | Package | Foundation | |-----|----------|---------|------------| | TypeScript | TypeScript/JavaScript | @alkahest/ts-sdk | viem | | Rust | Rust | alkahest-rs | alloy | | Python | Python | alkahest-py | PyO3 wrapper around Rust SDK |

    Client Setup

    TypeScript

    import { createWalletClient, http } from "viem";
    import { privateKeyToAccount } from "viem/accounts";
    import { baseSepolia } from "viem/chains";
    import { makeClient } from "@alkahest/ts-sdk";

    const walletClient = createWalletClient({ account: privateKeyToAccount("0xPRIVATE_KEY"), chain: baseSepolia, transport: http("https://rpc-url"), });

    // Full client with all extensions const client = makeClient(walletClient);

    // Custom addresses (optional) const client = makeClient(walletClient, customAddresses);

    // Minimal client for custom extension patterns const minimal = makeMinimalClient(walletClient); const extended = minimal.extend((base) => ({ custom: makeErc20Client(base.viemClient, pickErc20Addresses(base.contractAddresses)), }));

    Rust

    use alkahest_rs::AlkahestClient;

    // Full client with all extensions (Base Sepolia default) let client = AlkahestClient::with_base_extensions( "0xPRIVATE_KEY", "https://rpc-url", None, // uses Base Sepolia addresses ).await?;

    // Custom addresses use alkahest_rs::{DefaultExtensionConfig, ETHEREUM_SEPOLIA_ADDRESSES}; let client = AlkahestClient::with_base_extensions( "0xPRIVATE_KEY", "https://rpc-url", Some(ETHEREUM_SEPOLIA_ADDRESSES), ).await?;

    // Bare client + custom extensions let bare = AlkahestClient::new("0xPRIVATE_KEY", "https://rpc-url").await?; let extended = bare.extend::(Some(erc20_config)).await?;

    Python

    from alkahest_py import PyAlkahestClient

    Full client with all extensions (Base Sepolia default)

    client = PyAlkahestClient("0xPRIVATE_KEY", "https://rpc-url")

    Custom addresses

    from alkahest_py import DefaultExtensionConfig, PyErc20Addresses, ... config = DefaultExtensionConfig(erc20_addresses=..., ...) client = PyAlkahestClient("0xPRIVATE_KEY", "https://rpc-url", config)

    Core Patterns

    Creating an Escrow

    TypeScript:

    // 1. Approve token
    await client.erc20.util.approve({ address: TOKEN, value: amount }, "escrow");

    // 2. Create escrow const { hash, attested } = await client.erc20.escrow.nonTierable.doObligation( client.erc20.escrow.nonTierable.encodeObligationRaw({ token: TOKEN, amount, arbiter: ARBITER, demand: DEMAND_BYTES, }), ); const escrowUid = attested.uid;

    Rust:

    // 1. Approve
    client.erc20().approve(&Erc20Data { address: token, value: amount }, ApprovalPurpose::Escrow).await?;

    // 2. Create escrow let receipt = client.erc20().escrow().non_tierable().make_statement( token, amount, arbiter, demand_bytes, expiration, ).await?; let attested = client.get_attested_event(receipt)?;

    Python:

    # 1. Approve
    await client.erc20.util.approve(token_address, amount, "escrow")

    2. Create escrow

    uid = await client.erc20.escrow.non_tierable.create( token=token_address, amount=amount, arbiter=arbiter_address, demand=demand_bytes, expiration=expiration, )

    Fulfilling with StringObligation

    TypeScript:

    const { attested } = await client.stringObligation.doObligation(
      "fulfillment content",
      undefined,  // schema
      escrowUid,  // refUID
    );
    

    Rust:

    let receipt = client.string_obligation().do_obligation(
        "fulfillment content", None, Some(escrow_uid),
    ).await?;
    

    Python:

    uid = await client.string_obligation.do_obligation(
        "fulfillment content",
        ref_uid=escrow_uid,
    )
    

    Collecting Escrow

    TypeScript:

    const { hash } = await client.erc20.escrow.nonTierable.collectObligation(
      escrowUid,
      fulfillmentUid,
    );
    

    Rust:

    let receipt = client.erc20().escrow().non_tierable().collect_payment(
        escrow_uid, fulfillment_uid,
    ).await?;
    

    Python:

    tx_hash = await client.erc20.escrow.non_tierable.collect(escrow_uid, fulfillment_uid)
    

    Waiting for Fulfillment

    TypeScript:

    const result = await client.waitForFulfillment(
      client.contractAddresses.erc20EscrowObligation,
      escrowUid,
    );
    

    Rust:

    let log = client.wait_for_fulfillment(
        client.erc20_address(Erc20Contract::EscrowObligation),
        escrow_uid,
        None, // from_block
    ).await?;
    

    Python:

    result = await client.wait_for_fulfillment(
        escrow_contract_address,
        escrow_uid,
    )
    

    Encoding Demands

    TypeScript:

    // Trusted oracle
    const demand = client.arbiters.general.trustedOracle.encodeDemand({
      oracle: ORACLE, data: "0x",
    });

    // Logical composition const demand = client.arbiters.logical.all.encodeDemand({ arbiters: [ARBITER_A, ARBITER_B], demands: [DEMAND_A, DEMAND_B], });

    // Attestation properties const demand = client.arbiters.attestationProperties.attester.encodeDemand({ attester: REQUIRED_ATTESTER, });

    Rust:

    // Trusted oracle (ABI encoding)
    use alloy::sol_types::SolValue;
    let demand = TrustedOracleArbiter::DemandData { oracle, data: Bytes::new() }.abi_encode();

    // Decode arbiter demand (auto-detects) let decoded = client.arbiters().decode_arbiter_demand(arbiter_addr, &demand_bytes)?;

    Python:

    # Trusted oracle
    demand = client.arbiters.trusted_oracle.encode_demand(oracle=ORACLE, data=b"")

    Logical composition

    demand = client.arbiters.logical.all.encode( arbiters=[ARBITER_A, ARBITER_B], demands=[DEMAND_A, DEMAND_B], )

    Commit-Reveal Pattern

    TypeScript:

    // 1. Compute commitment
    const commitment = await client.commitReveal.computeCommitment(
      escrowUid, claimerAddress, { payload, salt, schema },
    );
    // 2. Commit (sends bond as ETH)
    await client.commitReveal.commit(commitment);
    // 3. Wait 1+ blocks, then reveal
    const { attested } = await client.commitReveal.doObligation(
      { payload, salt, schema }, escrowUid,
    );
    // 4. Reclaim bond
    await client.commitReveal.reclaimBond(attested.uid);
    

    Rust:

    let commitment = client.commit_reveal().compute_commitment(
        escrow_uid, claimer, &obligation_data,
    ).await?;
    client.commit_reveal().commit(commitment).await?;
    // wait 1+ blocks
    let receipt = client.commit_reveal().do_obligation(&obligation_data, Some(escrow_uid)).await?;
    client.commit_reveal().reclaim_bond(obligation_uid).await?;
    

    Python:

    commitment = await client.commit_reveal.compute_commitment(
        escrow_uid, claimer, payload, salt, schema,
    )
    await client.commit_reveal.commit(commitment)
    

    wait 1+ blocks

    uid = await client.commit_reveal.do_obligation(payload, salt, schema, ref_uid=escrow_uid) await client.commit_reveal.reclaim_bond(uid)

    Barter Utilities

    Barter utils provide atomic single-transaction token swaps:

    TypeScript:

    await client.erc20.barter.buyErc20ForErc20(
      { address: BID_TOKEN, value: bidAmount },
      { address: ASK_TOKEN, value: askAmount },
      BigInt(Math.floor(Date.now() / 1000) + 3600),
    );
    

    Rust:

    client.erc20().barter().buy_erc20_for_erc20(
        &bid_token, &ask_token, expiration,
    ).await?;
    

    Key Type Differences

    | Concept | TypeScript | Rust | Python | |---------|-----------|------|--------| | Addresses | ` 0x${string} | Address | str (hex) | | Big integers | bigint | U256 | str (decimal) | | Bytes | 0x${string} | Bytes / FixedBytes<32> | bytes / str (hex) | | Receipts | { hash, attested } | TransactionReceipt | str (tx hash or uid) | | Attestations | Attestation object | IEAS::Attestation | PyAttestation |

    Reference Documentation

  • references/typescript-api.md β€” full TS SDK API tree
  • references/rust-api.md β€” full Rust SDK API tree
  • references/python-api.md β€” full Python SDK API tree
  • references/contracts.md β€” contract addresses and data schemas
  • docs/Escrow Flow (pt 1).md β€” token trading walkthrough
  • docs/Escrow Flow (pt 2).md β€” oracle arbitration walkthrough
  • docs/Escrow Flow (pt 2b).md β€” commit-reveal frontrunning protection
  • docs/Escrow Flow (pt 3).md β€” composing demands with logical arbiters
  • docs/Writing Arbiters/ β€” custom arbiter development
  • docs/Writing Contracts/ β€” custom escrow/obligation development
  • docs/mcp-server/` β€” MCP server for looking up contract details
  • ⚑ When to Use

    TriggerAction
    - Integrating Alkahest into an application
    - Writing bots/agents that create escrows, fulfill obligations, or arbitrate
    - Building custom arbiters or obligation contracts
    - Understanding SDK patterns and APIs