> For the complete documentation index, see [llms.txt](https://intmax.gitbook.io/plasma-next-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://intmax.gitbook.io/plasma-next-docs/programability/example-1-atomic-swap-on-plasma-next.md).

# Example 1: Atomic Swap on Plasma Next

{% hint style="info" %}
Programmability support in the Plasma Next Mainnet is currently under development. The contents of this document cannot be tested on the Mainnet at present. Please wait until the support is fully implemented.
{% endhint %}

In this example, we consider a scenario where Alice, who holds ETH on Plasma Next, conducts an Atomic Swap with Bob, who holds DAI on the same platform. The flow of ETH and DAI follows the diagram below.&#x20;

<figure><img src="/files/jCqHpX8z0trZdXxZRpBh" alt=""><figcaption></figcaption></figure>

Here, we discuss the ZKPTLC for transfers from Alice to the operator. The ZKPTLC for transfers from the operator to Bob is exactly the same. The ZKPTLC for transfers from Alice to the operator is conditioned on two airdrops: one is an airdrop of ETH from the operator to Bob, and the other is an airdrop of DAI from the operator to Alice. Illustrated, this would look as follows: compared to Plasma Next's Default ZKPTLC, there is one additional condition related to the airdrops.

<figure><img src="/files/hW2tfkmNEh2yy0ibnonF" alt=""><figcaption></figcaption></figure>

The `instance` of the ZKPTLC must be bound to the transfer from Operator to Bob and the transfer from Operator to Alice. To generalize, let's call them `transfer1` and `transfer2`, respectively. The instance should be the hash values of these two transfers.

```solidity
function computeInstance(
  ITransfer.Transfer memory transfer1,
  ITransfer.Transfer memory transfer2
) external pure returns (bytes32) {
  bytes32 tc1 = transfer1.transferCommitment();
  bytes32 tc2 = transfer2.transferCommitment();
  return keccak256(abi.encodePacked(tc1, tc2));
}
```

We use the same \_verifyExistence function as the default ZKPTLC. This internal function verifies that the given transfer exists in Plasma Next.

```solidity
function _verifyExistence(
    ITransfer.Transfer memory transfer,
    IMerkleProof.EvidenceWithMerkleProof memory proof
) internal view {
    if (transfer.transferCommitment() != proof.leaf.transferCommitment) {
        revert("Transfer commitment does not match");
    }
    IRootManager(rootManagerAddress).verifyEvidenceMerkleProof(proof);
}
```

Let's implement `VerifyCondition`. The witness consists of `transfer1`, `transfer2`, and their corresponding settlement proofs `proof1`, `proof2`. Decode the `witness` from bytes, ensure it matches the `instance`, and then pass it through the `_verifyExistence` function we implemented earlier.

```solidity
struct Witness {
    ITransfer.Transfer transfer1;
    ITransfer.Transfer transfer2;
    IMerkleProof.EvidenceWithMerkleProof proof1;
    IMerkleProof.EvidenceWithMerkleProof proof2;
}

function verifyCondition(
    bytes32 instance,
    bytes memory witness
) external view {
    Witness memory w = abi.decode(witness, (Witness));
    bytes32 expectedInstance = computeInstance(w.transfer1, w.transfer2);
    if (instance != expectedInstance) {
        revert("Invalid instance");
    }
    _verifyExistence(w.transfer1, w.proof1);
    _verifyExistence(w.transfer2, w.proof2);
}
```

The entire contract is as follows.

<details>

<summary>The entire contract of Atomic swap on Plasma Next</summary>

```solidity
/// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {IRootManager} from "../root-manager/IRootManager.sol";
import {ITransfer} from "../common-interface/ITransfer.sol";
import {IMerkleProof} from "../common-interface/IMerkleProof.sol";
import {TransferLib} from "../utils/TransferLib.sol";

contract TwoWaySwap {
    using TransferLib for ITransfer.Transfer;

    address public rootManagerAddress;

    constructor(address _rootManagerAddress) {
        rootManagerAddress = _rootManagerAddress;
    }

    function computeInstance(
        ITransfer.Transfer memory transfer1,
        ITransfer.Transfer memory transfer2
    ) public pure returns (bytes32) {
        bytes32 tc1 = transfer1.transferCommitment();
        bytes32 tc2 = transfer2.transferCommitment();
        return keccak256(abi.encodePacked(tc1, tc2));
    }

    function _verifyExistence(
        ITransfer.Transfer memory transfer,
        IMerkleProof.EvidenceWithMerkleProof memory proof
    ) internal view {
        if (transfer.transferCommitment() != proof.leaf.transferCommitment) {
            revert("Transfer commitment does not match");
        }
        IRootManager(rootManagerAddress).verifyEvidenceMerkleProof(proof);
    }

    struct Witness {
        ITransfer.Transfer transfer1;
        ITransfer.Transfer transfer2;
        IMerkleProof.EvidenceWithMerkleProof proof1;
        IMerkleProof.EvidenceWithMerkleProof proof2;
    }

    function verifyCondition(
        bytes32 instance,
        bytes memory witness
    ) external view {
        Witness memory w = abi.decode(witness, (Witness));
        bytes32 expectedInstance = computeInstance(w.transfer1, w.transfer2);
        if (instance != expectedInstance) {
            revert("Invalid instance");
        }
        _verifyExistence(w.transfer1, w.proof1);
        _verifyExistence(w.transfer2, w.proof2);
    }
}

```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://intmax.gitbook.io/plasma-next-docs/programability/example-1-atomic-swap-on-plasma-next.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
