Atomic swaps are a mechanism that allows two parties to exchange cryptocurrencies directly without the need for a trusted third party. This is achieved through the use of smart contracts that ensure both parties fulfill their obligations before the swap is completed. In this guide, we will explain how to implement atomic swaps using Web3.js.

1. Understanding Atomic Swaps

Atomic swaps utilize Hash Time-Locked Contracts (HTLCs) to ensure that either both parties receive their assets or neither does. The process involves:

  • Creating a hash of a secret.
  • Locking funds in a smart contract with a time limit.
  • Revealing the secret to unlock the funds.

2. Smart Contract for Atomic Swap

First, you need to create a smart contract that implements the HTLC logic. Below is a simple example in Solidity:

solidity
pragma solidity ^0.8.0;

contract AtomicSwap {
struct Swap {
address initiator;
address participant;
uint amount;
bytes32 secretHash;
uint expiration;
}

mapping(bytes32 => Swap) public swaps;

function initiateSwap(bytes32 _secretHash, address _participant, uint _expiration) public payable {
require(msg.value > 0, "Must send ETH");
swaps[_secretHash] = Swap(msg.sender, _participant, msg.value, _secretHash, _expiration);
}

function claimSwap(bytes32 _secret, bytes32 _secretHash) public {
Swap memory swap = swaps[_secretHash];
require(swap.participant == msg.sender, "Not the participant");
require(keccak256(abi.encodePacked(_secret)) == _secretHash, "Invalid secret");
require(block.timestamp < swap.expiration, "Swap expired");

payable(msg.sender).transfer(swap.amount);
delete swaps[_secretHash];
}

function refundSwap(bytes32 _secretHash) public {
Swap memory swap = swaps[_secretHash];
require(swap.initiator == msg.sender, "Not the initiator");
require(block.timestamp >= swap.expiration, "Swap not expired");

payable(msg.sender).transfer(swap.amount);
delete swaps[_secretHash];
}
}

3. Deploying the Smart Contract

Once the smart contract is written, you need to deploy it to the Ethereum blockchain. Here’s how to do it using Web3.js:

javascript
const Web3 = require('web3');
const web3 = new Web3('https://mainnet.infura.io/YOUR_INFURA_API_KEY');

const contractABI = [ /* ABI array here */ ];
const contractBytecode = '0xYourContractBytecode';

async function deployContract() {
const accounts = await web3.eth.getAccounts();
const contract = new web3.eth.Contract(contractABI);

const deployTx = contract.deploy({
data: contractBytecode
});

const receipt = await deployTx.send({
from: accounts[0],
gas: 2000000
});

console.log('Contract Address:', receipt.contractAddress);
}

// Example usage
deployContract();

4. Initiating an Atomic Swap

To initiate an atomic swap, the initiator must call the initiateSwap function of the deployed contract:

javascript
async function initiateAtomicSwap(secretHash, participant, expiration) {
const accounts = await web3.eth.getAccounts();
const swapAmount = web3.utils.toWei('0.1', 'ether'); // Example amount

await contract.methods.initiateSwap(secretHash, participant, expiration).send({
from: accounts[0],
value: swapAmount,
gas: 2000000
});

console.log('Swap initiated!');
}

// Example usage
const secretHash = web3.utils.keccak256("your-secret"); // Hash of the secret
const participantAddress = '0xParticipantAddress';
const expirationTime = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
initiateAtomicSwap(secretHash, participantAddress, expirationTime);

5. Claiming the Swap

The participant can claim the swap using the secret once they receive it from the initiator:

javascript
async function claimAtomicSwap(secret, secretHash) {
const accounts = await web3.eth.getAccounts();

await contract.methods.claimSwap(secret, secretHash).send({
from: accounts[0],
gas: 2000000
});

console.log('Swap claimed!');
}

// Example usage
const secret = "your-secret"; // The secret used to claim the swap
claimAtomicSwap(secret, secretHash);

6. Refunding the Swap

If the swap expires without being claimed, the initiator can refund their funds:

javascript
async function refundAtomicSwap(secretHash) {
const accounts = await web3.eth.getAccounts();

await contract.methods.refundSwap(secretHash).send({
from: accounts[0],
gas: 2000000
});

console.log('Swap refunded!');
}

// Example usage
refundAtomicSwap(secretHash);

7. Conclusion

Implementing atomic swaps using Web3.js involves creating a smart contract that utilizes HTLCs, deploying the contract, and providing functions for initiating, claiming, and refunding swaps. By following the steps outlined in this guide, you can create a secure and efficient atomic swap mechanism for your decentralized applications.