
Sway
Bidirectional cross-chain swaps between Ethereum and Sui using 1inch Fusion+ extended protocol
Demo
About
Sway is a production-ready implementation that extends 1inch Fusion+ to enable secure, trustless cross-chain atomic swaps between Ethereum and Sui blockchain. The project bridges the gap between EVM and Move ecosystems by implementing hash-timelock contracts (HTLC) that work seamlessly across both networks. Key features include bidirectional swap capabilities (Ethereum↔Sui), automated event-driven relayer system, and preservation of atomic guarantees through cryptographic hashlocks. The implementation leverages existing battle-tested 1inch contracts on Ethereum while introducing custom Move smart contracts on Sui, ensuring compatibility with both blockchain architectures. Users can swap tokens between chains with complete security - either both transactions succeed or both revert, eliminating the risk of partial execution. The system supports any ERC20 tokens on Ethereum and Sui coin types, with gas-optimized execution and real-time cross-chain event propagation. Built for developers and DeFi protocols seeking reliable cross-chain infrastructure, Sway demonstrates how traditional AMM protocols can be extended to support next-generation blockchains while maintaining security and decentralization principles.
How it's made
## 🏗️ How This Was Built This section explains the technical implementation of extending 1inch Fusion+ to support Sui blockchain. ### 🧠 **Core Architecture Design** The implementation bridges two fundamentally different blockchain architectures: - **Ethereum (EVM)**: Account-based model with Keccak256 hashing - **Sui (Move)**: Object-centric model with BLAKE2b hashing **Key Challenge**: Maintaining atomic swap guarantees across incompatible hash functions and execution models. ### 🔧 **Technical Components** #### **1. Sui Move Smart Contracts** **`shared_locker.move`** - Maker-initiated swaps: ```move public entry fun maker_lock<T>( coin: coin::Coin<T>, hashlock: vector<u8>, // BLAKE2b hash of secret unlock_date: u64, // Timestamp for refund resolver: address, // Who can claim with secret ctx: &mut TxContext, ) { let locker = SharedLocker { id: object::new(ctx), coin, hashlock, unlock_date, maker: ctx.sender(), resolver, }; transfer::share_object(locker); // Make accessible to resolver } public entry fun claim_shared<T>( locker: SharedLocker<T>, secret: vector<u8>, // Reveals the secret receiver: address, clock_obj: &clock::Clock, ctx: &mut TxContext, ) { assert!(hash::blake2b256(&secret) == locker.hashlock, E_HASH_MISMATCH); let ev = SrcSecretRevealed { secret }; event::emit<SrcSecretRevealed>(ev); // Triggers cross-chain relay } ``` **`locker.move`** - Resolver-initiated swaps: ```move public entry fun lock<T>( coin: coin::Coin<T>, hashlock: vector<u8>, unlock_date: u64, receiver: address, ctx: &mut TxContext, ): Locker<T> { Locker { id: object::new(ctx), coin, hashlock, unlock_date, locker: ctx.sender(), receiver, } } ``` #### **2. Hash Compatibility Layer** **Problem**: Sui uses BLAKE2b, Ethereum uses Keccak256 - same secret produces different hashes. **Solution**: Dual hash generation in TypeScript: ```typescript // Generate single secret, create both hash types const secret = crypto.randomBytes(32); const hashBlake = blake2b(secret, { dkLen: 32 }); // For Sui const hashKeccak = keccak256(secret); // For Ethereum // Store mapping for cross-chain verification const mapping = { [hashKeccak]: { lockerId: suiLockerId, escrowAddress: ethEscrowAddress, }, }; ``` #### **3. Bidirectional Event Relayer** **Core Logic**: Listen for secret reveals on both chains and propagate cross-chain. ```typescript // Sui Event Listener await suiProvider.subscribeEvent({ filter: { MoveEventType: `${PACKAGE}::shared_locker::SrcSecretRevealed` }, onMessage: async (event) => { const secret = new Uint8Array(event.parsedJson.secret); await submitSecretToEthereum(secret); // Cross-chain relay }, }); // Ethereum Event Listener const filter = escrowContract.filters.SecretRevealed(); escrowContract.on(filter, async (secret, escrowAddress) => { await submitSecretToSui(secret, lockerId); // Cross-chain relay }); ``` #### **4. Ethereum Integration** **Reused 1inch Contracts**: No modifications needed to existing Fusion+ contracts. ```solidity // Existing 1inch EscrowFactory creates escrows with Keccak256 hashlocks contract EscrowSrc { function withdraw(bytes32 secret) external { require(keccak256(abi.encodePacked(secret)) == hashlock); // Transfer tokens and emit SecretRevealed event } } ``` ### 🔄 **Cross-Chain Flow Implementation** #### **Sui → Ethereum Swap** 1. **Maker** calls `maker_lock()` on Sui with BLAKE2b hashlock 2. **System** deploys Ethereum escrow with corresponding Keccak256 hashlock 3. **Resolver** calls `claim_shared()` on Sui, revealing secret 4. **Relayer** detects `SrcSecretRevealed` event, extracts secret 5. **Relayer** calls `withdraw()` on Ethereum escrow with same secret 6. **Atomic completion**: Both chains settle simultaneously #### **Ethereum → Sui Swap** 1. **Maker** deploys Ethereum escrow with Keccak256 hashlock 2. **Resolver** calls `lock()` on Sui with corresponding BLAKE2b hashlock 3. **Resolver** calls `claim()` on Sui, revealing secret 4. **Relayer** detects Sui event, submits secret to Ethereum 5. **Atomic completion**: Cross-chain settlement ### 🛡️ **Security Guarantees** #### **Hash Security** - **BLAKE2b** (Sui): Cryptographically secure, 256-bit output - **Keccak256** (Ethereum): Battle-tested, same security level - **Same Secret**: Both hashes derived from identical preimage #### **Timelock Protection** ```move // Sui: Timestamp-based expiry assert!(clock::timestamp_ms(clock_obj) < locker.unlock_date, E_CLAIM_TOO_EARLY); // Ethereum: Block-based expiry require(block.timestamp < timelock, "Timelock expired"); ``` #### **Atomic Guarantees** - **Either both succeed**: Secret revealed → both chains settle - **Or both revert**: Timelock expires → both chains refund - **No partial states**: Cryptographic proof prevents selective execution ### 🚀 **Performance Optimizations** #### **Gas Efficiency** - **Sui**: Object-centric design minimizes state changes - **Ethereum**: Reuse battle-tested 1inch contracts - **Relayer**: Batched event processing #### **Scalability** - **Event-driven**: No polling, pure push-based architecture - **Stateless relayer**: Can restart without losing state - **Parallel processing**: Multiple swaps simultaneously