diff --git a/api-reference/endpoint/affiliate/get-earnings.mdx b/api-reference/endpoint/affiliate/get-earnings.mdx new file mode 100644 index 0000000..1c5b119 --- /dev/null +++ b/api-reference/endpoint/affiliate/get-earnings.mdx @@ -0,0 +1,7 @@ +--- +title: 'Earnings' +openapi: 'GET /apps/earnings' +version: 1.0 +--- + +Get affiliate earnings and claimable amounts for different assets. diff --git a/api-reference/endpoint/get-fees.mdx b/api-reference/endpoint/get-fees.mdx index ac9c74a..4e10dc0 100644 --- a/api-reference/endpoint/get-fees.mdx +++ b/api-reference/endpoint/get-fees.mdx @@ -1,5 +1,5 @@ --- -title: 'Fees' +title: 'Total Fees' openapi: 'GET /fees' version: 1.0 --- diff --git a/api-reference/endpoint/orders/create-order.mdx b/api-reference/endpoint/orders/create-order.mdx index 4b26d1e..a23226c 100644 --- a/api-reference/endpoint/orders/create-order.mdx +++ b/api-reference/endpoint/orders/create-order.mdx @@ -4,4 +4,4 @@ openapi: 'POST /orders' version: 1.0 --- -Create a new swap order to exchange assets across blockchain networks. This initiates the atomic swap process and returns order details including deposit addresses. +Create a new swap order to exchange assets across blockchain networks. This starts the atomic swap process and returns a pre-built transaction to initiate a swap on-chain. diff --git a/api-reference/openapi.json b/api-reference/openapi.json index fa32fd3..20cee28 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -178,32 +178,54 @@ } ] }, - "AffiliateFeeItem": { + "AffiliateEarningsItem": { "type": "object", "properties": { "total_earnings": { - "type": "string" + "type": "string", + "description": "Total earnings in asset units for the affiliate." + }, + "total_earnings_usd": { + "type": "string", + "description": "Total earnings in USD for the mentioned asset for the affiliate." }, "affiliate": { - "type": "string" + "type": "string", + "description": "The address that will receive the earnings." }, "asset": { "$ref": "#/components/schemas/AffiliateFeeAsset" }, + "token_address": { + "type": "string", + "description": "Contract address for the affiliate fee asset." + }, "claim_amount": { - "type": "string" + "type": "string", + "description": "Amount available for claiming in asset units. Only included if the affiliate has not yet claimed their earnings." }, - "claim_transaction": { - "$ref": "#/components/schemas/EVMTransaction" + "claim_amount_usd": { + "type": "string", + "description": "Amount available for claiming in USD. Only included if the affiliate has not yet claimed their earnings." + }, + "claim_signature": { + "type": "string", + "description": "Signature for claiming earnings. Only included if the affiliate has not yet claimed their earnings." + }, + "claim_contract": { + "type": "string", + "description": "Contract address for claiming earnings. Only included if the affiliate has not yet claimed their earnings." } }, "required": [ "total_earnings", + "total_earnings_usd", "affiliate", - "asset" + "asset", + "token_address" ] }, - "AffiliateFeesResponse": { + "AffiliateEarningsResponse": { "allOf": [ { "$ref": "#/components/schemas/Response" @@ -217,7 +239,7 @@ "result": { "type": "array", "items": { - "$ref": "#/components/schemas/AffiliateFeeItem" + "$ref": "#/components/schemas/AffiliateEarningsItem" } } } @@ -230,23 +252,30 @@ "type": "string", "title": "mainnet", "enum": [ - "arbitrum:ibtc", "arbitrum:usdc", "arbitrum:wbtc", + "arbitrum:seed", "base:cbbtc", - "bera:lbtc", "base:usdc", + "bera:lbtc", "bitcoin:btc", + "bnbchain:bnb", + "bnbchain:btcb", + "bnbchain:usdc", "botanix:btc", + "core:wbtc", "corn:btcn", "ethereum:cbbtc", "ethereum:wbtc", - "ethereum:ibtc", "ethereum:seed", "ethereum:usdc", - "hyperevm:ubtc", + "ethereum:eth", + "hyperliquid:ubtc", "solana:sol", + "solana:usdc", + "solana:cbbtc", "starknet:wbtc", + "sui:sui", "unichain:usdc", "unichain:wbtc" ] @@ -258,18 +287,71 @@ "arbitrum_sepolia:seed", "arbitrum_sepolia:ibtc", "arbitrum_sepolia:wbtc", + "arbitrum_sepolia:usdc", "base_sepolia:wbtc", "base_sepolia:usdt", "base_sepolia:ibtc", + "base_sepolia:usdc", "bitcoin_testnet:btc", - "citrea_testnet:cbtc", + "bnbchain_testnet:wbtc", "citrea_testnet:wcbtc", + "citrea_testnet:wbtc", + "citrea_testnet:cbtc", + "citrea_testnet:cbbtc", + "citrea_testnet:usdc", + "citrea_testnet:usdt", "ethereum_sepolia:wbtc", + "ethereum_sepolia:usdc", "monad_testnet:cbbtc", "monad_testnet:usdc", "solana_testnet:sol", - "starknet_sepolia:wbtc" + "solana_testnet:usdc", + "solana_testnet:cbbtc", + "starknet_sepolia:wbtc", + "sui_testnet:sui" + ] + } + ] + }, + "AssetName": { + "oneOf": [ + { + "type": "string", + "title": "mainnet", + "enum": [ + "USD Coin", + "Binance Bitcoin", + "Bitcorn", + "Bitcoin", + "BNB", + "Botanix Bitcoin", + "Coinbase Wrapped Bitcoin", + "Ethereum", + "Lombard Bitcoin", + "SEED", + "SUI", + "Solana", + "Unit Bitcoin", + "Wrapped Bitcoin" + ] + }, + { + "type": "string", + "title": "testnet", + "enum": [ + "Bitcoin", + "Citrea Bitcoin", + "Coinbase Wrapped Bitcoin", + "iBTC", + "SEED", + "Solana", + "SUI", + "Tether USD", + "USD Coin", + "Wrapped Bitcoin", + "Wrapped Citrea Bitcoin" ] + } ] }, @@ -292,6 +374,9 @@ "id": { "$ref": "#/components/schemas/Asset" }, + "name": { + "$ref": "#/components/schemas/AssetName" + }, "chain": { "$ref": "#/components/schemas/Chain" }, @@ -334,6 +419,17 @@ } } }, + "OrderStatus": { + "type": "string", + "title": "status", + "enum": [ + "not-initiated", + "in-progress", + "completed", + "expired", + "refunded" + ] + }, "Swap": { "type": "object", "properties": { @@ -752,7 +848,8 @@ "type": "object", "required": [ "order_id", - "transaction", + "approval_transaction", + "initiate_transaction", "typed_data" ], "properties": { @@ -761,7 +858,8 @@ }, "approval_transaction": { "nullable": true, - "$ref": "#/components/schemas/EVMTransaction" + "$ref": "#/components/schemas/EVMTransaction", + "description": "Can be `null`, if user has already given approval" }, "initiate_transaction": { "$ref": "#/components/schemas/EVMTransaction" @@ -899,18 +997,20 @@ "type": "object", "required": [ "order_id", - "transaction", + "approval_transaction", + "initiate_transaction", "typed_data" ], "properties": { "order_id": { "type": "string" }, - "approval_call": { + "approval_transaction": { "nullable": true, - "$ref": "#/components/schemas/StarknetTransaction" + "$ref": "#/components/schemas/StarknetTransaction", + "description": "Can be `null`, if user has already given approval" }, - "initiate_call": { + "initiate_transaction": { "nullable": true, "$ref": "#/components/schemas/StarknetTransaction" }, @@ -934,6 +1034,25 @@ } } }, + "SuiInitiateRequest": { + "type": "object", + "required": [ + "order_id", + "ptb_bytes" + ], + "properties": { + "order_id": { + "type": "string" + }, + "ptb_bytes": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + }, "InitiateRequest": { "anyOf": [ { @@ -951,6 +1070,10 @@ { "title": "solana", "$ref": "#/components/schemas/SolanaInitiateRequest" + }, + { + "title": "sui", + "$ref": "#/components/schemas/SuiInitiateRequest" } ] }, @@ -981,11 +1104,30 @@ "solver_id": { "type": "string" }, + "estimated_time": { + "type": "integer", + "description": "Estimated swap time in seconds" + }, "source": { "$ref": "#/components/schemas/QuoteAsset" }, "destination": { "$ref": "#/components/schemas/QuoteAsset" + }, + "slippage": { + "type": "integer", + "description": "in BIPS (base index points) where 100 bips = 1%", + "example": 50 + }, + "fee": { + "type": "integer", + "description": "in BIPS (base index points) where 100 bips = 1%", + "example": 30 + }, + "fixed_fee": { + "type": "string", + "description": "in USD", + "example": "0.05" } } }, @@ -1346,7 +1488,18 @@ "name": "affiliate_fee", "schema": { "type": "integer" - } + }, + "description": "in BIPS (base index points) where 100 bips = 1%", + "example": 10 + }, + { + "in": "query", + "name": "slippage", + "schema": { + "type": "integer" + }, + "description": "in BIPS (base index points) where 100 bips = 1%\nWhen not specified, the slippage configured in app settings is used, or zero if no default is configured.", + "example": 50 } ], "responses": { @@ -1454,69 +1607,17 @@ "/fees": { "get": { "summary": "Get swap fees.", - "security": [], - "parameters": [ - { - "in": "header", - "name": "garden-app-id", - "required": false, - "schema": { - "type": "string" - }, - "description": "Garden app ID for affiliate fee information" - } - ], "responses": { "200": { - "description": "Total swap fees or affiliate fees if garden-app-id is provided. For affiliate fees, claim_amount and claim_transaction are only included if the affiliate has not yet claimed their fees.", + "description": "Total swap fees.", "content": { "application/json": { "schema": { - "oneOf": [ - { - "$ref": "#/components/schemas/ResponseString", - "title": "Total Fees" - }, - { - "$ref": "#/components/schemas/AffiliateFeesResponse", - "title": "Affiliate Fees" - } - ] + "$ref": "#/components/schemas/ResponseString" }, - "examples": { - "total-fees": { - "summary": "Total Fees Response", - "value": { - "success": true, - "result": "2668122" - } - }, - "affiliate-fees": { - "summary": "Affiliate Fees Response", - "value": { - "success": true, - "result": [ - { - "total_earnings": "150750000", - "affiliate": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", - "asset": "ethereum:usdc", - "claim_amount": "50750000", - "claim_transaction": { - "to": "0x5EbEC4D8DA437b2BAD656D43d40fE412bA5D217a", - "value": "0x0", - "chain_id": 1, - "data": "0x4ede0ab7000000000000000000000000661ba32eb5f86cab358ddbb7f264b10c5825e2dd0000000000000000000000000000000000000000000000000000000000069780000000000000000000000000000000000000000000000000000000000000c3503331ff69aca609e06dcd4b97223667611d66bb4e8b56e26fc0ff53c49a1ed04d00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", - "gas_limit": "0x30d40" - } - }, - { - "total_earnings": "3000000", - "affiliate": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", - "asset": "ethereum:cbbtc" - } - ] - } - } + "example": { + "status": "Ok", + "result": "2668122" } } } @@ -1621,6 +1722,22 @@ }, "description": "Filter orders by destination chain" }, + { + "in": "query", + "name": "from_owner", + "schema": { + "type": "string" + }, + "description": "Filter orders by source owner" + }, + { + "in": "query", + "name": "to_owner", + "schema": { + "type": "string" + }, + "description": "Filter orders by destination owner" + }, { "in": "query", "name": "page", @@ -1959,6 +2076,46 @@ } } } + }, + "/apps/earnings": { + "get": { + "summary": "Get affiliate earnings.", + "responses": { + "200": { + "description": "List of affiliate earnings.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AffiliateEarningsResponse" + }, + "example": { + "status": "Ok", + "result": [ + { + "total_earnings": "15075000000", + "total_earnings_usd": "15075", + "affiliate": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "asset": "ethereum:usdc", + "token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "claim_amount": "5075000000", + "claim_amount_usd": "5075", + "claim_signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1b", + "claim_contract": "0x5EbEC4D8DA437b2BAD656D43d40fE412bA5D217a" + }, + { + "total_earnings": "30000000", + "total_earnings_usd": "30000", + "affiliate": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "asset": "ethereum:cbbtc", + "token_address": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf" + } + ] + } + } + } + } + } + } } } } \ No newline at end of file diff --git a/api-reference/quickstart.mdx b/api-reference/quickstart.mdx index 8522d5e..b50ec2d 100644 --- a/api-reference/quickstart.mdx +++ b/api-reference/quickstart.mdx @@ -4,7 +4,7 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta --- - This guide uses a testing app ID. Planning to build a production app with our API? Reach out to us in the [Townhall](https://discord.gg/dZwSjh9922). + This guide uses a testing app ID. Planning to build a production app with our API? Reach out to us in the [Townhall](https://discord.gg/B7RczEFuJ5). @@ -34,7 +34,11 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "display": "0.00049850", "value": "58.6435" }, - "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635" + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 600, + "slippage": 50, + "fee": 30, + "fixed_fee": "0.0" } ] } @@ -177,7 +181,11 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "display": "0.00049850", "value": "58.6933" }, - "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635" + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 20, + "slippage": 50, + "fee": 30, + "fixed_fee": "0.0" } ] } @@ -192,7 +200,7 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta --data '{ "source": { "asset": "ethereum_sepolia:wbtc", - "owner": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "owner": "0x4cD3FB4a504cc978f316a81Dc5165D2C5b30592d", "amount": "50000" }, "destination": { @@ -206,20 +214,33 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta { "status": "Ok", "result": { - "order_id": "646eabe9fd9e7612ac712d54d899cf3f1847251927184fbc22d80f2a9a55987d", - "transaction": { - "to": "0x88e1032252c712681a3659986f452e910d2134d8", - "value": "0x0", - "data": "0x97ffc7ae000000000000000000000000661ba32eb5f86cab358ddbb7f264b10c5825e2dd0000000000000000000000000000000000000000000000000000000000001c20000000000000000000000000000000000000000000000000000000000000c35061d22856ce12bc3693df0cd4967d404400449f61810080c52638fd805b379723", + "approval_transaction": { + "chain_id": 11155111, + "data": "0x095ea7b3000000000000000000000000d1e0ba2b165726b3a6051b765d4564d030fdcf50ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "gas_limit": "0xea60", + "to": "0xe918a5a47b8e0afac2382bc5d1e981613e63fb07", + "value": "0x0" + }, + "initiate_transaction": { + "chain_id": 11155111, + "data": "0x97ffc7ae000000000000000000000000661ba32eb5f86cab358ddbb7f264b10c5825e2dd0000000000000000000000000000000000000000000000000000000000001c20000000000000000000000000000000000000000000000000000000000000c3507b32dd44045d8d6fc477615d0d72f42fc7696078e44724fe64c85b563fc8f306", "gas_limit": "0x493e0", - "chain_id": 11155111 + "to": "0xd1e0ba2b165726b3a6051b765d4564d030fdcf50", + "value": "0x0" }, + "order_id": "7e69c6514fa6c7a46b88e235e484d9958029cbe748e125add69b1ffcf7265198", "typed_data": { "domain": { - "name": "HTLC", - "version": "2", "chainId": "0xaa36a7", - "verifyingContract": "0x88e1032252c712681a3659986f452e910d2134d8" + "name": "HTLC", + "verifyingContract": "0xd1e0ba2b165726b3a6051b765d4564d030fdcf50", + "version": "3" + }, + "message": { + "amount": "0xc350", + "redeemer": "0x661ba32eb5f86cab358ddbb7f264b10c5825e2dd", + "secretHash": "0x7b32dd44045d8d6fc477615d0d72f42fc7696078e44724fe64c85b563fc8f306", + "timelock": "0x1c20" }, "primaryType": "Initiate", "types": { @@ -259,12 +280,6 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "type": "bytes32" } ] - }, - "message": { - "redeemer": "0x661ba32eb5f86cab358ddbb7f264b10c5825e2dd", - "timelock": "0x1c20", - "amount": "0xc350", - "secretHash": "0x61d22856ce12bc3693df0cd4967d404400449f61810080c52638fd805b379723" } } } @@ -305,7 +320,7 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta Get the order by ID to check the status of the swap. ```bash wrap curl -X 'GET' \ - 'https://testnet.api.garden.finance/v2/orders/646eabe9fd9e7612ac712d54d899cf3f1847251927184fbc22d80f2a9a55987d' \ + 'https://testnet.api.garden.finance/v2/orders/7e69c6514fa6c7a46b88e235e484d9958029cbe748e125add69b1ffcf7265198' \ -H 'garden-app-id: f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796' \ -H 'accept: application/json' ``` @@ -313,19 +328,19 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta { "status": "Ok", "result": { - "created_at": "2025-07-11T14:48:19.354306Z", + "created_at": "2025-09-01T06:48:02.138492Z", "source_swap": { - "created_at": "2025-07-11T14:48:19.354306Z", - "swap_id": "30facc712b6eaa7a2453dba968da223d180322f224285db2820a8cdd7125147a", + "created_at": "2025-09-01T06:48:02.138492Z", + "swap_id": "f511550e9629124790646668b8cdc2a42bbdc9b9333857c4fdd3f1bf514b6575", "chain": "ethereum_sepolia", "asset": "ethereum_sepolia:wbtc", - "initiator": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "initiator": "0x4cD3FB4a504cc978f316a81Dc5165D2C5b30592d", "redeemer": "0x661bA32eb5f86CaB358DDbB7F264b10c5825e2dd", "timelock": 7200, "filled_amount": "0", - "asset_price": 118000.0, + "asset_price": 108107, "amount": "50000", - "secret_hash": "61d22856ce12bc3693df0cd4967d404400449f61810080c52638fd805b379723", + "secret_hash": "7b32dd44045d8d6fc477615d0d72f42fc7696078e44724fe64c85b563fc8f306", "secret": "", "initiate_tx_hash": "", "redeem_tx_hash": "", @@ -340,18 +355,18 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "refund_timestamp": null }, "destination_swap": { - "created_at": "2025-07-11T14:48:19.354306Z", - "swap_id": "tb1p57lque52sgj9juntnwz7s0sgpapwmh0tzck3n9lz0sw2h3nnfx4qk924vj", + "created_at": "2025-09-01T06:48:02.138492Z", + "swap_id": "tb1peepw3gum369qfu7zgnd6jq5sk77q5wyuzmznlpavzmeq8x72kcyqr66rxg", "chain": "bitcoin_testnet", "asset": "bitcoin_testnet:btc", "initiator": "460f2e8ff81fc4e0a8e6ce7796704e3829e3e3eedb8db9390bdc51f4f04cf0a6", "redeemer": "tb1p4pr78swsn60y4ushe05v28mqpqppxxkfkxu2wun5jw6duc8unj3sjrh4gd", - "delegate": "bc182774238a970984da3727d8acdc8c93c23f85167afd7d58db73ef9e81b9b0", + "delegate": "03f4776668ef95e35ff2d51d8c59eb7a461bb2354b540553d8455dbec91087c1", "timelock": 12, "filled_amount": "0", - "asset_price": 118000.0, + "asset_price": 108107, "amount": "49850", - "secret_hash": "61d22856ce12bc3693df0cd4967d404400449f61810080c52638fd805b379723", + "secret_hash": "7b32dd44045d8d6fc477615d0d72f42fc7696078e44724fe64c85b563fc8f306", "secret": "", "initiate_tx_hash": "", "redeem_tx_hash": "", @@ -365,13 +380,13 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "redeem_timestamp": null, "refund_timestamp": null }, - "nonce": "6010738665599915909", - "order_id": "646eabe9fd9e7612ac712d54d899cf3f1847251927184fbc22d80f2a9a55987d", + "nonce": "4326423548464636342", + "order_id": "7e69c6514fa6c7a46b88e235e484d9958029cbe748e125add69b1ffcf7265198", "affiliate_fees": [], - "integrator": "test_integrator", - "version": "v1" + "integrator": "DocsTesting", + "version": "v3" } -} + } ``` The swap is complete once the `order.destination_swap.redeem_tx_hash` field is populated. @@ -405,7 +420,11 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "display": "0.00048515", "value": "56.9524" }, - "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635" + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 20, + "slippage": 50, + "fee": 30, + "fixed_fee": "0.0" } ] } @@ -435,19 +454,51 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "status": "Ok", "result": { "order_id": "ee54521431fd3b7c01f46f2aaec086362d8cf2d6a7d3b31233c66c31bed9e4eb", - "versioned_tx": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100020408032aa331a727d64421581d1ec2ea7cdde7ac7bb04a7ab7bb5e7f4ea5992f08b30c777cae9e6cbeb9830b8b0cd529b6e1f3667ae0c1c21071cb64bba2c7763e000000000000000000000000000000000000000000000000000000000000000017b7828ca6c4f06b51139a60254f81fe1249c8e2b122febf32ca81322b9f1e8ed3c02412b5458cdb8b14d42d4a61166f85f0f4e4d536c8a9f111a4de7e86b77801030301000258053f7b71994b940e89e4221500000000c04b03000000000044070018cffb963a80cb5bf8974e0d64934c614d26340d947ddf3b762a014cacb8841dc97c588ab9e1b94f62627b97d54f8c1048b28c26749d413032e9d66c4e" + "versioned_tx": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100020408032aa331a727d64421581d1ec2ea7cdde7ac7bb04a7ab7bb5e7f4ea5992f08b30c777cae9e6cbeb9830b8b0cd529b6e1f3667ae0c1c21071cb64bba2c7763e000000000000000000000000000000000000000000000000000000000000000017b7828ca6c4f06b51139a60254f81fe1249c8e2b122febf32ca81322b9f1e8ed3c02412b5458cdb8b14d42d4a61166f85f0f4e4d536c8a9f111a4de7e86b77801030301000258053f7b71994b940e89e4221500000000c04b03000000000044070018cffb963a80cb5bf8974e0d64934c614d26340d947ddf3b762a014cacb8841dc97c588ab9e1b94f62627b97d54f8c1048b28c26749d413032e9d66c4e", + "versioned_tx_gasless": null } } ``` Then deposit the funds: - ```javascript - // Convert transaction object from response. - const buffer = Buffer.from(response.result.versioned_tx, 'hex'); - const transaction = VersionedTransaction.deserialize(buffer); - - // Sign and send using your wallet. - const signature = await wallet.signAndSendTransaction(transaction); - ``` + + + ```typescript + // Decode and deserialize the `versioned_tx` field + const buffer = Buffer.from(response.result.versioned_tx, 'base64'); + const transaction = VersionedTransaction.deserialize(buffer); + + // Sign and send using your wallet. + const signature = await wallet.signAndSendTransaction(transaction); + ``` + + + + Currently, this is only supported for Solana SPL orders. + As such, `versioned_tx_gasless` will be `null` for Solana orders with native SOL. + + ```typescript + // Note the use of `versioned_tx_gasless` + const buffer = Buffer.from(response.result.versioned_tx_gasless, 'base64'); + const transaction = VersionedTransaction.deserialize(buffer); + + // Sign using your wallet + const signedTransaction = await wallet.signTransaction(transaction); + + // Serialize and base64 encode the signed transaction + const encodedTx = Buffer.from(signedTransaction.serialize()).toString('base64'); + + // Pass this encoded transaction to the garden API + await fetch(`https://testnet.api.garden.finance/v2/orders/${response.result.order_id}?action=initiate`, { + method: 'PATCH', + headers: { + 'garden-app-id': 'f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ signature: encodedTx }) + }); + ``` + + Get the order by ID to check the status of the swap. @@ -553,7 +604,11 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "display": "0.00049850", "value": "58.7033" }, - "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635" + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 20, + "slippage": 50, + "fee": 30, + "fixed_fee": "0.0" } ] } @@ -582,29 +637,56 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta { "status": "Ok", "result": { - "order_id": "08322ec7359a2fc8ef0918e0c0ada7943e22d87bd0c4632e9576de26f646b372", + "approval_transaction": { + "calldata": [ + "0x6579d255314109429a4477d89629bc2b94f529ae01979c2f8014f9246482603", + "0xffffffffffffffffffffffffffffffff", + "0xffffffffffffffffffffffffffffffff" + ], + "selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", + "to": "0x496bef3ed20371382fbe0ca6a5a64252c5c848f9f1f0cccf8110fc4def912d5" + }, + "initiate_transaction": { + "calldata": [ + "0x78f8ae98fe78b5df9d3755b5910864c028d5249b4af685eb45687b1b76a4205", + "0xb40", + "0xc350", + "0x0", + "0x5e0dfe4c", + "0x3c6495a", + "0x5f81f922", + "0x204d8c16", + "0x964f6ca5", + "0xcc766f3a", + "0x6a4cc6cd", + "0x2117fdb4" + ], + "selector": "0x2aed25fcd0101fcece997d93f9d0643dfa3fbd4118cae16bf7d6cd533577c28", + "to": "0x6579d255314109429a4477d89629bc2b94f529ae01979c2f8014f9246482603" + }, + "order_id": "f64db51ba3894ba3720925aaa816d4eb538f623802686595bf8ac50ecbc68bad", "typed_data": { "domain": { - "chainId": "SN_SEPOLIA", + "chainId": "0x534e5f5345504f4c4941", "name": "HTLC", - "revision": "1", - "version": "1" + "revision": 1, + "version": "0x31" }, "message": { "amount": { - "high": "0x0", - "low": "0xc350" + "high": "0x0", + "low": "0xc350" }, "redeemer": "3419807808164513772718725483164424774502669183354591566218616648407888577029", "secretHash": [ - 3887207343, - 2041436155, - 1951867791, - 3328046620, - 3034489147, - 987985137, - 3049690424, - 3858545034 + 1577975372, + 63326554, + 1602353442, + 541953046, + 2521787557, + 3430313786, + 1783416525, + 555220404 ], "timelock": "2880" }, @@ -647,24 +729,6 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta } ] } - }, - "transaction": { - "calldata": [ - "0x78f8ae98fe78b5df9d3755b5910864c028d5249b4af685eb45687b1b76a4205", - "0xb40", - "0xc350", - "0x0", - "0xe7b213af", - "0x79add7fb", - "0x7457238f", - "0xc65df61c", - "0xb4dea13b", - "0x3ae374f1", - "0xb5c69538", - "0xe5fcb98a" - ], - "selector": "0x2aed25fcd0101fcece997d93f9d0643dfa3fbd4118cae16bf7d6cd533577c28", - "to": "0x6579d255314109429a4477d89629bc2b94f529ae01979c2f8014f9246482603" } } } @@ -702,7 +766,7 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta Get the order by ID to check the status of the swap. ```bash wrap curl -X 'GET' \ - 'https://testnet.api.garden.finance/v2/orders/08322ec7359a2fc8ef0918e0c0ada7943e22d87bd0c4632e9576de26f646b372' \ + 'https://testnet.api.garden.finance/v2/orders/f64db51ba3894ba3720925aaa816d4eb538f623802686595bf8ac50ecbc68bad' \ -H 'garden-app-id: f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796' \ -H 'accept: application/json' ``` @@ -710,19 +774,19 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta { "status": "Ok", "result": { - "created_at": "2025-07-11T14:46:01.293643Z", + "created_at": "2025-09-01T07:02:07.851646Z", "source_swap": { - "created_at": "2025-07-11T14:46:01.293643Z", - "swap_id": "61ea20c8abf2a327035c2bc1170b3d32a13b271f14ad5a3739f995ce9a54ebf", + "created_at": "2025-09-01T07:02:07.851646Z", + "swap_id": "3ef65007bb6cabe9749309ecfb4e343bc31c3f1e66865dd49623c557c275dcb", "chain": "starknet_sepolia", "asset": "starknet_sepolia:wbtc", "initiator": "0x00609190b1348bcc06da44d58c79709495c11a5a6f0b9e154e1209f2a17dd933", "redeemer": "0x078f8ae98fe78b5df9d3755b5910864c028d5249b4af685eb45687b1b76a4205", "timelock": 2880, "filled_amount": "0", - "asset_price": 118000.0, + "asset_price": 108201, "amount": "50000", - "secret_hash": "e7b213af79add7fb7457238fc65df61cb4dea13b3ae374f1b5c69538e5fcb98a", + "secret_hash": "5e0dfe4c03c6495a5f81f922204d8c16964f6ca5cc766f3a6a4cc6cd2117fdb4", "secret": "", "initiate_tx_hash": "", "redeem_tx_hash": "", @@ -737,18 +801,18 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "refund_timestamp": null }, "destination_swap": { - "created_at": "2025-07-11T14:46:01.293643Z", - "swap_id": "tb1psllge60w4dtm9lkwhflyznay60775nl3k06s2rl6r96d99kv7ccqaxtq7h", + "created_at": "2025-09-01T07:02:07.851646Z", + "swap_id": "tb1p3nug6w3cjtnvjuu43aytqtnx5420q6nmntzsrdkngk4na7ny4x7qfayy5n", "chain": "bitcoin_testnet", "asset": "bitcoin_testnet:btc", "initiator": "460f2e8ff81fc4e0a8e6ce7796704e3829e3e3eedb8db9390bdc51f4f04cf0a6", "redeemer": "tb1p4pr78swsn60y4ushe05v28mqpqppxxkfkxu2wun5jw6duc8unj3sjrh4gd", - "delegate": "60e484adb39f5dc2af267c160c92afcbc1dd93e9c4c745316b8f55c8e0d664fc", + "delegate": "e6ca4c227c7e048c5d605bfe478e79ee313de490cdfbb11160c2cc1221dbdc71", "timelock": 12, "filled_amount": "0", - "asset_price": 118000.0, + "asset_price": 108201, "amount": "49850", - "secret_hash": "e7b213af79add7fb7457238fc65df61cb4dea13b3ae374f1b5c69538e5fcb98a", + "secret_hash": "5e0dfe4c03c6495a5f81f922204d8c16964f6ca5cc766f3a6a4cc6cd2117fdb4", "secret": "", "initiate_tx_hash": "", "redeem_tx_hash": "", @@ -762,11 +826,186 @@ description: "Use Garden's API to get quotes, submit orders, and track their sta "redeem_timestamp": null, "refund_timestamp": null }, - "nonce": "2212051334241171111", - "order_id": "08322ec7359a2fc8ef0918e0c0ada7943e22d87bd0c4632e9576de26f646b372", + "nonce": "5463708687999347822", + "order_id": "f64db51ba3894ba3720925aaa816d4eb538f623802686595bf8ac50ecbc68bad", "affiliate_fees": [], - "integrator": "test_integrator", - "version": "v1" + "integrator": "DocsTesting", + "version": "v2" + } + } + ``` + + The swap is complete once the `order.destination_swap.redeem_tx_hash` field is populated. + + + + + + + + + Let's get a quote to trade 3 Sui on **Sui Testnet** to BTC on **Bitcoin Testnet4**. + ```bash wrap + curl -X 'GET' 'https://testnet.api.garden.finance/v2/quote?from=sui_testnet:sui&to=bitcoin_testnet:btc&from_amount=3000000000' \ + -H 'garden-app-id: f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796' \ + -H 'accept: application/json' + ``` + ```json Response expandable + { + "status": "Ok", + "result": [ + { + "source": { + "asset": "sui_testnet:sui", + "amount": "3000000000", + "display": "3.00000000", + "value": "9.9997" + }, + "destination": { + "asset": "bitcoin_testnet:btc", + "amount": "9079", + "display": "0.00009079", + "value": "9.9697" + }, + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 20, + "slippage": 50, + "fee": 30, + "fixed_fee": "0.0" + } + ] + } + ``` + + + Once a quote is received, we can submit the order: + ```bash + curl --location 'http://testnet.api.garden.finance/v2/orders' \ + --header 'garden-app-id: f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796' \ + --header 'Content-Type: application/json' \ + --data '{ + "source": { + "asset": "sui_testnet:sui", + "owner": "0x79a1582388c16d0ab85904f320eb0527481391a9b9ab4b2ab46adc4c2564f9d0", + "amount": "3000000000" + }, + "destination": { + "asset": "bitcoin_testnet:btc", + "owner": "tb1p4pr78swsn60y4ushe05v28mqpqppxxkfkxu2wun5jw6duc8unj3sjrh4gd", + "amount": "9079" + } + }' + ``` + ```json Response expandable wrap + { + "status": "Ok", + "result": { + "order_id": "e7a2d8b8dbf8d1e315c17e40cd9287410ea9449258f806a1833b7f9ad68527f5", + "ptb_bytes": [0,8,0,8,0,94,208,178,0,0,0,0,1,1,92,67,135,21,183,220,192,45,18,171,146,68,145,83,161,229,173,226,48,22,32,213,191,96,170,116,143,0,103,38,211,105,76,48,204,31,0,0,0,0,1,0,32,121,161,88,35,136,193,109,10,184,89,4,243,32,235,5,39,72,19,145,169,185,171,75,42,180,106,220,76,37,100,249,208,0,32,63,109,158,7,253,76,218,187,170,112,151,193,158,207,101,88,9,200,147,169,207,227,244,24,195,255,188,4,37,13,59,76,0,33,32,57,81,42,177,166,145,123,61,75,78,219,100,208,167,124,32,76,159,215,52,146,144,167,63,206,85,74,183,15,149,211,219,0,32,0,92,38,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,0,2,2,0,1,1,0,0,0,153,134,91,3,221,27,192,61,10,106,128,92,69,78,162,87,196,100,247,171,204,202,233,205,75,98,27,145,231,202,4,222,10,65,116,111,109,105,99,83,119,97,112,8,105,110,105,116,105,97,116,101,1,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,115,117,105,3,83,85,73,0,9,1,1,0,1,2,0,1,3,0,1,4,0,1,0,0,1,5,0,1,6,0,2,0,0,1,7,0] + } + } + ``` + Then deposit the funds: + ```typescript + import { SuiClient, getFullnodeUrl } from "@mysten/sui/client"; + import { Transaction } from "@mysten/sui/transactions"; + import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; + + const client = new SuiClient({ url: getFullnodeUrl('testnet') }); + const gasPrice = await client.getReferenceGasPrice(); + const estimatedGasBudget = 10000000; // 10M gas units as a conservative estimate + + let transaction = Transaction.fromKind(new Uint8Array(ptb_bytes)) // ptb_bytes are the Programmable Transaction Bytes returned from the create order response + transaction.setSender(sender); + transaction.setGasPrice(gasPrice); + transaction.setGasBudget(estimatedGasBudget); + + const suiWallet = Ed25519Keypair.fromSecretKey("[private-key]"); + + try { + const result = await client.signAndExecuteTransaction({ + transaction: transaction, + signer: suiWallet, + options: { + showEffects: true, + }, + }); + + console.log(result) + } catch (error) { + console.error('Transaction execution failed:', error); + } + ``` + + + Get the order by ID to check the status of the swap. + ```bash wrap + curl -X 'GET' \ + 'https://testnet.api.garden.finance/v2/orders/e7a2d8b8dbf8d1e315c17e40cd9287410ea9449258f806a1833b7f9ad68527f5' \ + -H 'garden-app-id: f242ea49332293424c96c562a6ef575a819908c878134dcb4fce424dc84ec796' \ + -H 'accept: application/json' + ``` + ```json Response expandable focus={45} + { + "status": "Ok", + "result": { + "created_at": "2025-09-01T09:33:10.050305Z", + "source_swap": { + "created_at": "2025-09-01T09:33:10.050305Z", + "swap_id": "1220ade677e925f325fbcef8ded85efd4d416852015678634dd471bfd77e8f2f", + "chain": "sui_testnet", + "asset": "sui_testnet:sui", + "initiator": "0x79a1582388c16d0ab85904f320eb0527481391a9b9ab4b2ab46adc4c2564f9d0", + "redeemer": "0x3f6d9e07fd4cdabbaa7097c19ecf655809c893a9cfe3f418c3ffbc04250d3b4c", + "timelock": 86400000, + "filled_amount": "0", + "asset_price": 3.3332479255988647, + "amount": "3000000000", + "secret_hash": "39512ab1a6917b3d4b4edb64d0a77c204c9fd7349290a73fce554ab70f95d3db", + "secret": "", + "initiate_tx_hash": "", + "redeem_tx_hash": "", + "refund_tx_hash": "", + "initiate_block_number": "0", + "redeem_block_number": "0", + "refund_block_number": "0", + "required_confirmations": 0, + "current_confirmations": 0, + "initiate_timestamp": null, + "redeem_timestamp": null, + "refund_timestamp": null + }, + "destination_swap": { + "created_at": "2025-09-01T09:33:10.050305Z", + "swap_id": "tb1p77xn22avz3qyu9tkm00q4rfuyz5c2960y33vde7z58xwh0zymv3sk879l4", + "chain": "bitcoin_testnet", + "asset": "bitcoin_testnet:btc", + "initiator": "460f2e8ff81fc4e0a8e6ce7796704e3829e3e3eedb8db9390bdc51f4f04cf0a6", + "redeemer": "tb1p4pr78swsn60y4ushe05v28mqpqppxxkfkxu2wun5jw6duc8unj3sjrh4gd", + "delegate": "f5a577508b4b55e65d693f7c772eab767b2e22626e8a76b654b6142abc3ffd5e", + "timelock": 12, + "filled_amount": "0", + "asset_price": 109799.0308368164, + "amount": "9079", + "secret_hash": "39512ab1a6917b3d4b4edb64d0a77c204c9fd7349290a73fce554ab70f95d3db", + "secret": "", + "initiate_tx_hash": "", + "redeem_tx_hash": "", + "refund_tx_hash": "", + "initiate_block_number": "0", + "redeem_block_number": "0", + "refund_block_number": "0", + "required_confirmations": 0, + "current_confirmations": 0, + "initiate_timestamp": null, + "redeem_timestamp": null, + "refund_timestamp": null + }, + "nonce": "9973478672661146798", + "order_id": "e7a2d8b8dbf8d1e315c17e40cd9287410ea9449258f806a1833b7f9ad68527f5", + "affiliate_fees": [], + "integrator": "DocsTesting", + "version": "v2" } } ``` diff --git a/api-reference/setup.mdx b/api-reference/setup.mdx index b9f967f..e62d21d 100644 --- a/api-reference/setup.mdx +++ b/api-reference/setup.mdx @@ -13,4 +13,4 @@ Start building immediately with our testing app ID. This key lets you explore th ## Production access -Planning to build a production app with our API? Reach out to us in the [Townhall](https://discord.gg/dZwSjh9922). +Planning to build a production app with our API? Reach out to us in the [Townhall](https://discord.gg/B7RczEFuJ5). diff --git a/changelog.mdx b/changelog.mdx index 348bea8..4068c1c 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -2,14 +2,129 @@ title: "Changelog" description: "Product updates and announcements" --- + + + ### Endpoint update + - Update GET `/quote` endpoint to include `fee` and `fixed_fee` + - Update GET `/assets` endpoint to include `name` + - Update GET `/chains` endpoint to include `name` + + + + ### New endpoint + - Add `/apps/earnings` endpoint for fetching affiliate earnings + + + + ### Endpoint updates + - Update POST `/orders` to use `initiate_on_behalf` calldata when the source delegate is passed + + + + ### Endpoint updates + - Update GET `/orders` to include the following filters: `from_owner`, `to_owner` + - Update GET `/quote` endpoint to accept `slippage` parameter + + + + ### Endpoint update + - Update GET `/quote` endpoint to include `estimated_time` + + + + ### New chains + - Add Core support + + ### New assets + - Add SPL tokens support for Solana + + ### Approval flow improvements + - Add check after approval to verify the latest allowance amount. + + + + ### Watcher improvements + - Update event watch deadline for Bitcoin swaps from 1 hour to 6 hours + + + + ### New chains + - Add Sui support + + ### API call improvements + - Extend `getOrders` function with new filters (e.g. status , transaction hash) for more precise order queries. + - Accept `AbortController` as a parameter in get methods of `@gardenfi/orderbook` to allow cancellation of ongoing orderbook API calls. + + ### Network switching improvements + - Fix error handling in `switchOrAddNetwork` utility for case when network is not found. + + ### Local testing + - Add `yarn link` support allowing developers to locally test the changes done in SDK within a working project directory. + + + + ### Affiliate fees endpoint + - Add GET `/apps/earnings` to track an integrator's affiliate fees + + + + ### New chains + - Add Sui support + + + + ### Order status fixes + - Fix order status parsing to ensure swap initiation and initiation detection are confirmed before the attested deadline, preventing orders from being accepted after expiry. + + + + ### New chains + - Add SPL tokens support for Solana + + + + ### Endpoint updates + - Update GET `/orders` to include the following filters: `address`, `tx_hash`, `from_chain`, `to_chain`, `page`, `per_page`, `status` + - Update GET `/chains` to include the default explorer URL + + + + ### New chains + - Add BNB Chain support + + ### One-click swaps + - Add `handleSecretManagement` flag for optional secret management. + - When set to `false`, we use [one-click swaps](/developers/api/1click) + - When set to `true`, we manage secrets within the SDK, and the user has to keep his session active + + + + ### New endpoint + - Add PATCH `/orders/:id?action=refund` endpoint to process Bitcoin refunds + + + + ### Endpoint updates + - Update GET `/assets` endpoint to return `chain_id` and fiat value + - Update POST `/orders` endpoint to make Bitcoin address optional, to allow refund address updates after expiry + + + + ### Phantom wallet fixes + - Finalize all inputs of a Partially Signed Bitcoin Transaction in `PhantomProvider`, fixing issues with transaction broadcasting + + + + ### Dependency update + - Internalised `@catalogfi/wallets` dependency to Garden SDK + + ### New endpoints - - Add `/schemas/{name}` endpoint for fetching specific contract schemas - Add `/schemas` endpoint for browsing available contract interfaces ### Enhanced schema types - - Add support for different HTLC contract types across chains: - `evm:htlc`, `evm:htlc_erc20` - `solana:htlc`, `solana:htlc_spltoken` diff --git a/developers/affiliate-fees.mdx b/developers/affiliate-fees.mdx index e7e9d1c..be2ba97 100644 --- a/developers/affiliate-fees.mdx +++ b/developers/affiliate-fees.mdx @@ -160,3 +160,98 @@ For example, a 30 bps fee could be split by sending 10 bps in USDC to an Ethereu + +## How to claim + +The claiming process involves two steps: checking your available earnings through the API, then submitting an on-chain transaction to withdraw them. + +### Check available earnings + +First, call the earnings endpoint to get your claimable amounts: + +```bash cURL +curl -X 'GET' 'https://api.garden.finance/v2/apps/earnings' \ + -H 'garden-app-id: YOUR_APP_ID' \ + -H 'accept: application/json' +``` + +Example response: + +```json Success +{ + "status": "Ok", + "result": [ + { + "total_earnings": "15075000000", + "total_earnings_usd": "15075", + "affiliate": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "asset": "ethereum:usdc", + "token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "claim_amount": "5075000000", + "claim_amount_usd": "5075", + "claim_signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1b", + "claim_contract": "0x5EbEC4D8DA437b2BAD656D43d40fE412bA5D217a" + } + ] +} +``` + + + The `claim_amount`, `claim_amount_usd`, `claim_signature`, and `claim_contract` fields are only included when you have unclaimed earnings available. + + +### Claim your earnings + +To claim your earnings, you need to call the `claim` function on the distributor contract. Here's how to construct the transaction: + + + Make sure to call the claim function on the same chain where you received the rewards. For example, if your earnings are in `ethereum:usdc`, you should use the Ethereum mainnet RPC URL and chain configuration. + + +```javascript JavaScript +import { createWalletClient, createPublicClient, http, parseAbi } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { mainnet } from 'viem/chains'; + +async function claimAffiliateEarnings(claimData) { + const account = privateKeyToAccount(''); + + // Create wallet client for sending transactions + const walletClient = createWalletClient({ + account, + chain: mainnet, + transport: http('YOUR_RPC_URL'), + }); + + // Create public client for reading transaction receipts + const publicClient = createPublicClient({ + chain: mainnet, + transport: http('YOUR_RPC_URL'), + }); + + // Parse the ABI for the claim function + const abi = parseAbi([ + 'function claim((address toAddress, address tokenAddress, uint256 totalRewards) _claim, bytes _signature)' + ]); + + // Prepare claim parameters + const claimParams = { + toAddress: claimData.affiliate, + tokenAddress: claimData.token_address, + totalRewards: BigInt(claimData.total_earnings) + }; + + // Execute the claim transaction + const hash = await walletClient.writeContract({ + address: claimData.claim_contract, + abi, + functionName: 'claim', + args: [claimParams, claimData.claim_signature] + }); + + // Wait for transaction receipt + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + return receipt; +} +``` + diff --git a/developers/core/sessions.mdx b/developers/core/sessions.mdx index b2610a5..6c8005e 100644 --- a/developers/core/sessions.mdx +++ b/developers/core/sessions.mdx @@ -3,7 +3,7 @@ title: "Sessions" description: "Understanding how sessions enable secure, trustless atomic swaps while delivering seamless user experience" --- -**Sessions** play a vital role in enabling secure, trustless [atomic swaps](/home/fundamentals/introduction/atomic-swaps) while also delivering a seamless swapping experience. For integrators, sessions provide a unified framework to manage secrets, interact with Bitcoin's P2SH addresses, and ensure smooth interactions without compromising security. By abstracting complex processes like secret generation and Bitcoin wallet integration, sessions simplify the developer experience while maintaining robust protections for users. +**Sessions** play a vital role in enabling secure, trustless [atomic swaps](/home/fundamentals/core-concepts/atomic-swaps) while also delivering a seamless swapping experience. For integrators, sessions provide a unified framework to manage secrets, interact with Bitcoin's P2SH addresses, and ensure smooth interactions without compromising security. By abstracting complex processes like secret generation and Bitcoin wallet integration, sessions simplify the developer experience while maintaining robust protections for users. ## Why do we need sessions? diff --git a/developers/guides/api.mdx b/developers/guides/api.mdx index 04575c3..ea49639 100644 --- a/developers/guides/api.mdx +++ b/developers/guides/api.mdx @@ -1,743 +1,845 @@ --- -title: "Integrate with Garden API" -description: "Guide to integrating Garden into your wallet backend, bridge aggregator, or infrastructure service using our API" +title: "Build with Garden V2 API" +description: "Step-by-step guide to building a cross-chain swap terminal UI using Garden's V2 API in Rust" --- -If you get stuck during implementation, reach out in our [Townhall](https://discord.gg/dZwSjh9922)—our dev team is ready to help! +If you are stuck at any part of the implementation, drop a message in our [Townhall](https://discord.gg/B7RczEFuJ5)—our dev team is ready to assist! -This cookbook guides you through integrating Garden into your wallet backend, bridge aggregator, or infrastructure service using our API. You'll learn how to authenticate users, create and initiate cross-chain swaps, and track and redeem them on the destination chain. If you're unsure whether to use the SDK or APIs, see this [comparison](/developers/overview#choosing-between-sdk-and-api). +This cookbook provides a step-by-step guide to building a terminal-based swap application using Garden's V2 API. It walks through creating an interactive TUI (Terminal User Interface) in Rust that enables seamless cross-chain swaps between Bitcoin and various EVM chains. -We'll demonstrate a complete swap flow from Bitcoin Testnet4 (tBTC) to Arbitrum Sepolia (WBTC), showing how to coordinate with Garden APIs at each step. +For a fully functional reference, check out [api-cookbook-demo](https://github.com/gardenfi/api-cookbook-demo), allowing you to see how these steps integrate into a working application. -For a full reference implementation, see this [page](https://github.com/gardenfi/api-cookbook-demo)—a working terminal UI in Rust that demonstrates these steps in a real application. + + ![Network Selector UI](../images/api-demo-app/Network_selector.png) + -## Authenticate +## What you'll build -Before placing or interacting with orders, your system must authenticate the user. Garden supports two authentication methods: +- **Network selector**: Choose between localnet, testnet, or mainnet environments +- **Asset pair selector**: Browse and select from all available trading pairs +- **Quote dashboard**: Get real-time quotes with amount input +- **Order dashboard**: Create orders, initiate transactions, and track swap status -### Option 1: Direct SIWE +## Quick start -Garden uses Sign-In with Ethereum (SIWE) to verify wallet ownership. +### Prerequisites -**1. Request a nonce** -Generate a unique, single-use nonce as a challenge. +- Rust and Cargo installed +- Bitcoin and EVM private keys +- Access to Bitcoin and EVM networks (testnet for testing) -```bash -POST /auth/siwe/challenges -``` - -Expected response: -```json -{ - "status": "Ok", - "result": "a34f6521d29cb6f0febbef3c0799f1b8213f85162fa206a535e5e11424c87b43" -} -``` - -**2. Sign the nonce** -The user signs the nonce with their EVM wallet, generating a structured SIWE message. This is done by creating a local signer instance (e.g., using 'PrivateKeySigner' from the Alloy crate in Rust), which uses the user's private key to sign the message. The signed message ensures: - -- The nonce is unique and prevents replay attacks -- The user's private key remains secure - -SIWE message format: -``` - wants you to sign in with your Ethereum account: - -Garden.fi -URI: -Version: 1 -Chain ID: -Nonce: -Issued At: -``` +### Installation -Example for testnet: -``` -localhost:4361 wants you to sign in with your Ethereum account: -0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf -Garden.fi -URI: http://localhost:4361 -Version: 1 -Chain ID: 11155111 -Nonce: a34f6521d29cb6f0febbef3c0799f1b8213f85162fa206a535e5e11424c87b43 -Issued At: 2025-04-09T07:29:20.203Z -``` - -**3. Verify the signed message** -Send the signed message to obtain a JSON web token (JWT). +Clone and set up the repository: ```bash -POST /auth/siwe/tokens -``` - -Request: -```json -{ - "message": "", - "signature": "", - "nonce": "" -} -``` - -Expected response: -```json -{ - "status": "Ok", - "result": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMHhlOTg5MmE4QTNENTk4MTREYjE0OTkxOEFEOWZGNDI4MmMyRDk5MUU4IiwiZXhwIjoxNzQ0MzYyMDIwfQ.iHiPUkeaNBkoUPhDQLqYkP6-6F3NtdmqrfozpafX8oM" -} +git clone https://github.com/gardenfi/api-cookbook-demo +cd api-cookbook-demo ``` -### Option 2: API key +### Configuration -API keys offer a convenient way to authenticate if you prefer to manage authentication in-house or need persistent access without requiring users to sign messages repeatedly. +**1. Set up environment variables** -If you need an API key, please reach out to us on [Townhall](https://discord.gg/dZwSjh9922) and ping us, or raise a support ticket. - -Include the API key in your request headers as "api-key" with the generated key as its value. This replaces JWT bearer tokens for authentication. +Create a `.env` file with your private keys: ```bash -api-key: -``` - -## Order lifecycle - -This section outlines the swap lifecycle and how each step maps to specific API calls. +# EVM Private Key (hex format without 0x prefix) +PRIV_KEY=your_evm_private_key_here -When a user requests to swap assets, start by retrieving a price quote for the order pair (source chain, source asset, destination chain, destination asset, and amount). After confirming the quote, the order is attested and validated by Garden's API, then created via the `/relayer/create-order` endpoint. - -For a detailed breakdown of the order lifecycle, including status transitions, see the [order lifecycle](/developers/core/order-lifecycle). For a deeper understanding of the Garden protocol, read the [intent flow](/home/fundamentals/how-it-works/intent-flow). +# Bitcoin Private Key (WIF or hex format) +# If not provided, PRIV_KEY will be used +BTC_PRIV_KEY=your_btc_private_key_here +``` -### Get supported pairs +**2. Configure network endpoints** -The first step is to display all available options. Use the `/quote/strategies` endpoint to get all supported pairs from Garden. Each pair has a unique 'id'. +The `config.json` file contains API endpoints and provider URLs for each network: -```bash -GET /quote/strategies -``` - -Example response: -```json + +```json Response expandable { - "status": "Ok", - "result": { - "btyrasac": { - "id": "btyrasac", - "source_chain_address": "1db36714896afaee20c2cc817d170689870858b5204d3b5a94d217654e94b2fb", - "dest_chain_address": "0x29f72597ca8a21F9D925AE9527ec5639bAFD5075", - "source_chain": "bitcoin_testnet", - "dest_chain": "arbitrum_sepolia", - "source_asset": { - "asset": "primary", - "token_id": "bitcoin", - "decimals": 8 + "networks": { + "mainnet": { + "api": { + "assets_url": "https://api.garden.finance/v2/chains", + "quote_server_url": "https://api.garden.finance/v2/quote", + "authenticator_url": "https://api.garden.finance/auth", + "orderbook_url": "https://api.garden.finance/v2/orders" }, - "dest_asset": { - "asset": "0x795Dcb58d1cd4789169D5F938Ea05E17ecEB68cA", - "token_id": "bitcoin", - "decimals": 8 + "providers": { + "bitcoin": "https://mempool.space/api", + "arbitrum": "https://arb-mainnet.g.alchemy.com/v2/demo", + "ethereum": "https://eth-mainnet.g.alchemy.com/v2/demo" + } + }, + "testnet": { + "api": { + "assets_url": "https://testnet.api.garden.finance/v2/chains", + "quote_server_url": "https://testnet.api.garden.finance/v2/quote", + "authenticator_url": "https://testnet.api.garden.finance/auth", + "orderbook_url": "https://testnet.api.garden.finance/v2/orders" }, - "makers": [], - "min_amount": "10000", - "max_amount": "100000", - "min_source_timelock": 12, - "min_source_confirmations": 1, - "min_price": 1.0001, - "fee": 30 + "providers": { + "bitcoin": "https://mempool.space/testnet4/api", + "arbitrum": "https://arbitrum-sepolia.drpc.org", + "ethereum": "https://ethereum-sepolia-rpc.publicnode.com" + } + }, + "localnet": { + "api": { + "assets_url": "http://localhost:8080", + "quote_server_url": "http://localhost:6969", + "authenticator_url": "http://localhost:4427", + "orderbook_url": "http://localhost:4455" + }, + "providers": { + "bitcoin": "http://localhost:30000", + "arbitrum": "http://localhost:8546", + "ethereum": "http://localhost:8545" + } } } } ``` + -Define the `order pair` based on user selection in this format: -`source_chain:source_asset::destination_chain:destination_asset` - -For our tBTC to WBTC (Arbitrum) example: -``` -bitcoin_testnet:primary::arbitrum_sepolia:0x795Dcb58d1cd4789169D5F938Ea05E17ecEB68cA -``` - -### Get quote +### Running the application -Request solver quotes for the expected output (or required input) amount using the selected `order pair` and specifying the `amount` in sats. +Start the terminal UI: ```bash -GET /quote/?order_pair=&amount=&exact_out=boolean +cargo run -- --c config.json ``` -`exact_out` lets you choose whether to specify what you want to spend or what you want to receive: - -- `exact_out=false`: Specify input amount (e.g., send 0.01 BTC → get X WBTC) -- `exact_out=true`: Specify desired output (e.g., get 10 WBTC → send X BTC) +## Application flow -For our tBTC to WBTC (Arbitrum) example: - -```bash -GET /quote/?order_pair=bitcoin_testnet:primary::arbitrum_sepolia:0x795Dcb58d1cd4789169D5F938Ea05E17ecEB68cA&amount=10000&exact_out=false -``` - -Example response: -```json -{ - "status": "Ok", - "result": { - "quotes": { - "btyrasac": "9970" - }, - "input_token_price": 77328.3666062084, - "output_token_price": 77328.3666062084 - } -} -``` +### 1. Network selection -The response provides asset prices (in USD) from market oracles and solver quotes for the specified amount. If `exact_out` is `false`, the quote reflects the output (receive) amount for the user. +When you launch the app, you'll first select your target network. The terminal interface presents all available networks (localnet, testnet, and mainnet) in an interactive list where you can navigate with arrow keys and select with Enter: - -In atomic swaps, funds are locked on-chain using a secret hash, which is the SHA256 hash of a randomly generated secret. + + ![Network Selection](../images/api-demo-app/Network_selector.png) + -Garden offers two approaches for managing the secret and its hash: +The network selector is implemented in `src/ui/states/network_selector.rs`: -**Garden-managed secret**: Garden generates and manages the secret and secret hash internally. -- Redemptions are done automatically. + +```rust network_selector.rs +pub struct NetworkSelectorState { + selected_index: usize, + networks: Vec, + list_state: ListState, +} -**Developer-managed secret**: You can generate and manage the secret and hash yourself. -- The developer must manually perform redemption calls. -- Setup instant refund for bitcoin swaps +impl NetworkSelectorState { + pub fn new(config: &Config) -> Self { + let mut networks: Vec = config.networks.keys().map(|k| k.to_string()).collect(); + networks.sort(); + + let mut list_state = ListState::default(); + list_state.select(Some(0)); + Self { + selected_index: 0, + networks, + list_state, + } + } -After receiving a quote, you can proceed with either a [**Garden-managed secret**](#garden-managed-secret) or a [**Developer-managed secret**](#developer-managed-secret) flow, depending on what best suits your integration needs. - + pub fn get_selected_network(&self) -> &str { + &self.networks[self.selected_index] + } -## Garden-managed secret + fn update_list_state(&mut self) { + self.list_state.select(Some(self.selected_index)); + } +} +``` + -### Create order +**Key features:** +- Navigate with `↑/↓` arrow keys +- Select with `Enter` +- Quit with `q` +- Scrollable list that adapts to terminal size -When ready, create an order by sending a request to `/relayer/create-order`. This creates the order in Garden's orderbook. The response includes the unique `order ID` for tracking and managing the order. +### 2. Fetching supported chains and assets -```bash -POST /relayer/create-order -``` +After selecting a network, the app fetches all available chains and their assets from Garden's API: -Example request for tBTC to WBTC: + +```rust chains.rs +pub fn get_chains(&self) -> Result> { + let response = self + .client + .get(&self.assets_url) + .send() + .map_err(|e| anyhow!("Failed to fetch chains: {}", e))?; -```json -{ - "source_chain": "bitcoin_testnet", - "destination_chain": "arbitrum_sepolia", - "source_asset": "primary", - "destination_asset": "0x795Dcb58d1cd4789169D5F938Ea05E17ecEB68cA", - "initiator_destination_address": "0x753Cf575A0224c590ACF3587031E88b238261f7a", - "source_amount": "10000", - "destination_amount": "9970", - "nonce": "1743337081630", - "additional_data": { - "strategy_id": "btyrasac", - "bitcoin_optional_recipient": "tb1qz0pnh98kfynptg9dtkj06f7sqnlxl3dxnmnjw4" - } -} -``` + let response_text = response + .error_for_status() + .map_err(|e| anyhow!("HTTP error: {}", e))? + .text() + .map_err(|e| anyhow!("Failed to read response body: {}", e))?; - -- Since the source is Bitcoin, `initiator_source_address` is not required. -- If the destination is Bitcoin, `initiator_destination_address` is not required. - + let api_response: ApiResponse> = serde_json::from_str(&response_text) + .map_err(|e| anyhow!("Failed to parse chains response: {}", e))?; -Expected response: -```json -{ - "result": "", - "status": "Ok" + Ok(api_response.result) } ``` + -### Get order data - -To retrieve order data for an order ID: +**Response structure:** -```bash -GET /orders/id/:id/ -``` - -Expected response: -```json +```json Response expandable { "status": "Ok", - "result": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "source_swap": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "swap_id": "", - "chain": "", - "asset": "", - "initiator": "", - "redeemer": "", - "timelock": "", - "filled_amount": "", - "amount": "", - "secret_hash": "", - "secret": "", - "initiate_tx_hash": "", - "redeem_tx_hash": "", - "refund_tx_hash": "", - "initiate_block_number": "", - "redeem_block_number": "0", - "refund_block_number": "", - "required_confirmations": "", - "current_confirmations": "" - }, - "destination_swap": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "swap_id": "", - "chain": "", - "asset": "", - "initiator": "", - "redeemer": "", - "timelock": "", - "filled_amount": "", - "amount": "", - "secret_hash": "", - "secret": "", - "initiate_tx_hash": "", - "redeem_tx_hash": "", - "refund_tx_hash": "", - "initiate_block_number": "", - "redeem_block_number": "0", - "refund_block_number": "", - "required_confirmations": "", - "current_confirmations": "" + "result": [ + { + "chain": "bitcoin_testnet", + "id": "bitcoin", + "icon": "https://garden.imgix.net/token-images/bitcoin.svg", + "explorer_url": "https://mempool.space/testnet4", + "confirmation_target": 1, + "source_timelock": "144", + "destination_timelock": "12", + "supported_htlc_schemas": [], + "supported_token_schemas": [], + "assets": [ + { + "id": "bitcoin_testnet:btc", + "name": "Bitcoin", + "chain": "bitcoin", + "icon": "https://garden.imgix.net/token-images/bitcoin.svg", + "htlc": null, + "token": null, + "decimals": 8, + "min_amount": "50000", + "max_amount": "10000000000", + "price": 114641.1 + } + ] }, - "create_order": { - // order metadata + { + "chain": "ethereum_sepolia", + "id": "evm:11155111", + "icon": "https://garden.imgix.net/chain_images/sepolia.svg", + "explorer_url": "https://sepolia.etherscan.io", + "confirmation_target": 1, + "source_timelock": "7200", + "destination_timelock": "600", + "supported_htlc_schemas": [ + "evm:htlc_erc20" + ], + "supported_token_schemas": [ + "evm:erc20" + ], + "assets": [ + { + "id": "ethereum_sepolia:wbtc", + "name": "Wrapped Bitcoin", + "chain": "evm:11155111", + "icon": "https://garden.imgix.net/token-images/wbtc.svg", + "htlc": { + "address": "0xd1E0Ba2b165726b3a6051b765d4564d030FDcf50", + "schema": "evm:htlc_erc20" + }, + "token": { + "address": "0xE918A5a47b8e0AFAC2382bC5D1e981613e63fB07", + "schema": "evm:erc20" + }, + "decimals": 8, + "min_amount": "50000", + "max_amount": "10000000000", + "price": 114641.1 + }, + { + "id": "ethereum_sepolia:usdc", + "name": "USD Coin", + "chain": "evm:11155111", + "icon": "https://garden.imgix.net/token-images/usdc.svg", + "htlc": { + "address": "0x730Be401ef981D199a0560C87DfdDaFd3EC1C493", + "schema": "evm:htlc_erc20" + }, + "token": { + "address": "0xadDD620EA6D20f4f9c24fff3BC039E497ceBEDc2", + "schema": "evm:erc20" + }, + "decimals": 6, + "min_amount": "15000000", + "max_amount": "10000000000", + "price": 1 + } + ] } - } + ] } ``` -If the order is unmatched, this endpoint returns null. - -### Initiate order - -The order initiation process begins when the user initiates the swap on the source chain. For EVM-based chains, use the `/relayer/initiate` endpoint. The process differs for Bitcoin, which uses scripts. - -**Initiating on EVM:** - -To initiate, the user must sign the HTLC initiation message using their wallet provider's EIP-712 typed data signing method. This signature authorizes the HTLC contract to lock tokens in escrow with the specified parameters. The signature is used for contract initialization. - -1. **Get EIP712 domain data** - The user must call the `eip712domain()` function on the HTLC contract that returns the eip712 domain data. - - Sample EIP712domain data: - ``` - [ eip712Domain method Response ] - name string : HTLC - version string : 1 - chainId uint256 : 42161 - verifyingContract address : 0x6b6303fAb8eC7232b4f2a7b9fa58E5216F608fcb - ``` - -2. **Format initiation message** - The initiation message must be in the following format: +### 3. Asset pair selection - ```typescript - { - address redeemer; - uint256 timelock; - uint256 amount; - bytes32 secretHash; - } - ``` - -3. **Sign and submit** - The message, along with the domain data, must be signed with the wallet, and the signature is sent with the initiate request to the relayer. - - ```bash - POST /relayer/initiate - ``` - - Example request: - ```json - { - "order_id": "", - "signature": "", - "perform_on": "Source" - } - ``` - - Expected response: - ```json - { - "result": "", - "status": "Ok" - } - ``` - -**Initiating on Bitcoin:** - -On Bitcoin, initiation can be done in two ways: - -1. Fund the HTLC script address directly using a Bitcoin wallet -2. Construct a transaction paying the required amount to the HTLC script address and broadcast it - -The HTLC script address is the swap ID of the source chain swap, found in the `source_swap` field in the `/orders/id/:id` response. - -### Redeem asset - -Redemption is handled automatically for the user. No manual action is required to redeem tokens. - - -If the secret is managed by the developer, redemptions must also be handled by the developer. - +The app generates all possible trading pairs and displays them in an interactive scrollable list. Browse through available swap routes showing the source and destination assets with their respective chains: -## Developer managed secret + + ![Asset Pair Selection](../images/api-demo-app/Asset_pair.png) + -### Generate secret and secret Hash + +```rust network_information.rs +pub fn generate_asset_pairs(chains: Vec) -> Vec { + let mut assets = Vec::new(); -The secret hash is a SHA256 hash of a randomly generated secret. + for chain in chains { + for asset in chain.assets { + if asset.price.unwrap_or(0.0) > 0.0 { + assets.push(asset.id); + } + } + } -The **secret** must be **hashed using the SHA256 algorithm**. This hash is used for initiating and redeeming swaps. + let mut pairs = Vec::new(); + for i in 0..assets.len() { + for j in 0..assets.len() { + if i != j { + pairs.push(AssetPair::new(assets[i].clone(), assets[j].clone())); + } + } + } -Example: -``` -secret = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" //randomly generated hex string - | SHA256 hashed - v -secret_hash = "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456" + pairs +} ``` - -### Create order - -When ready, create an order by sending a request to `/relayer/create-order`. This creates the order in Garden's orderbook. The response includes the unique `order ID` for tracking and managing the order. - -```bash -POST /relayer/create-order + + +**Key features:** +- Automatic pair generation from chain data +- Scrollable list with visual indicators +- Back navigation to network selection +- Search and filter capabilities + +### 4. Getting quotes + +Once you select a pair, enter an amount and press "g" to get a real-time quote. The swap page displays the selected asset pair and allows you to input the amount you want to swap: + + + ![Swap Page](../images/api-demo-app/Swap_page.png) + + +After submitting the amount, the application fetches real-time quotes from available solvers and displays detailed swap information including estimated output, fees, and execution time. Press "s" to proceed with creating the order: + + + ![Create Order](../images/api-demo-app/Create_order.png) + + + +```rust quote.rs +pub async fn fetch_quote( + context: &ApiContext, + from: &str, + to: &str, + from_amount: &str, +) -> Result> { + let url = format!( + "{}/v2/quote?from={}&to={}&from_amount={}", + context.base_url, from, to, from_amount + ); + + let response = reqwest::Client::new() + .get(&url) + .header("garden-app-id", &context.app_id) + .header("accept", "application/json") + .send() + .await?; + + let quote_response: QuoteResponse = response.json().await?; + Ok(quote_response.result) +} ``` + -Example request for tBTC to WBTC: +**Quote response:** ```json { - "source_chain": "bitcoin_testnet", - "destination_chain": "arbitrum_sepolia", - "source_asset": "primary", - "destination_asset": "0x795Dcb58d1cd4789169D5F938Ea05E17ecEB68cA", - "initiator_source_address": "609c8b4b2026902fa15ad850de19d56ecee31ce9b61f0f69cc732da3a58b6ad6", - "initiator_destination_address": "0x753Cf575A0224c590ACF3587031E88b238261f7a", - "source_amount": "10000", - "destination_amount": "9970", - "nonce": "1743337081630", - "secret_hash": "5b876744fc3b8812da6b5317e3dcbb833c68c13c59cb67e9dfac992d388a1b74", - "additional_data": { - "strategy_id": "btyrasac", - "bitcoin_optional_recipient": "tb1qz0pnh98kfynptg9dtkj06f7sqnlxl3dxnmnjw4" - } + "status": "Ok", + "result": [ + { + "source": { + "asset": "bitcoin_testnet:btc", + "amount": "50000", + "display": "0.00050000", + "value": "58.82" + }, + "destination": { + "asset": "base_sepolia:wbtc", + "amount": "49850", + "display": "0.00049850", + "value": "58.64" + }, + "solver_id": "0x9dd9c2d208b07bf9a4ef9ca311f36d7185749635", + "estimated_time": 20, + "slippage": 0, + "fee": 30, + "fixed_fee": "0" + } + ] } ``` -Expected response: -```json -{ - "result": "", - "status": "Ok" +### 5. Creating orders + +After confirming the quote, the application creates an order on Garden's orderbook. You'll see the order being processed with all the swap details: + + + ![Order Created](../images/api-demo-app/Order_created.png) + + +For EVM source swaps, you'll need to approve token spending before initiating the swap. The application will prompt you to sign the approval transaction by clicking "a": + + + ![Token Approval](../images/api-demo-app/Token_approval.png) + + + +```rust orders.rs +pub async fn create_order( + context: &ApiContext, + request: CreateOrderRequest, +) -> Result { + let url = format!("{}/v2/orders", context.base_url); + + let response = reqwest::Client::new() + .post(&url) + .header("garden-app-id", &context.app_id) + .header("Content-Type", "application/json") + .json(&request) + .send() + .await?; + + let order_response: OrderCreationResponse = response.json().await?; + Ok(order_response.result) } ``` + -### Get order data - -To retrieve order data for an order ID: +**Order creation request:** -```bash -GET /orders/id/:id/ -``` - -Expected response: ```json { - "status": "Ok", - "result": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "source_swap": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "swap_id": "", - "chain": "", - "asset": "", - "initiator": "", - "redeemer": "", - "timelock": "", - "filled_amount": "", - "amount": "", - "secret_hash": "", - "secret": "", - "initiate_tx_hash": "", - "redeem_tx_hash": "", - "refund_tx_hash": "", - "initiate_block_number": "", - "redeem_block_number": "0", - "refund_block_number": "", - "required_confirmations": "", - "current_confirmations": "" - }, - "destination_swap": { - "created_at": "", - "updated_at": "", - "deleted_at": null, - "swap_id": "", - "chain": "", - "asset": "", - "initiator": "", - "redeemer": "", - "timelock": "", - "filled_amount": "", - "amount": "", - "secret_hash": "", - "secret": "", - "initiate_tx_hash": "", - "redeem_tx_hash": "", - "refund_tx_hash": "", - "initiate_block_number": "", - "redeem_block_number": "0", - "refund_block_number": "", - "required_confirmations": "", - "current_confirmations": "" - }, - "create_order": { - // order metadata - } + "source": { + "asset": "bitcoin_testnet:btc", + "owner": "tb1p4pr78swsn60y4ushe05v28mqpqppxxkfkxu2wun5jw6duc8unj3sjrh4gd", + "amount": "50000" + }, + "destination": { + "asset": "base_sepolia:wbtc", + "owner": "0x004Cc75ACF4132Fc08cB6a252E767804F303F729", + "amount": "49850" } } ``` -If the order is unmatched, this endpoint returns null. - -### Initiate order - -The order initiation process begins when the user initiates the swap on the source chain. For EVM-based chains, use the `/relayer/initiate` endpoint. The process differs for Bitcoin, which uses scripts. - -**Initiating on EVM:** - -To initiate, the user must sign the HTLC initiation message using their wallet provider's EIP-712 typed data signing method. This signature authorizes the HTLC contract to lock tokens in escrow with the specified parameters. The signature is used for contract initialization. - -1. **Get EIP712 domain data** - The user must call the `eip712domain()` function on the HTLC contract that returns the eip712 domain data. - - Sample EIP712domain data: - ``` - [ eip712Domain method Response ] - name string : HTLC - version string : 1 - chainId uint256 : 42161 - verifyingContract address : 0x6b6303fAb8eC7232b4f2a7b9fa58E5216F608fcb - ``` - -2. **Format initiation message** - The initiation message must be in the following format: - - ```typescript - { - address redeemer; - uint256 timelock; - uint256 amount; - bytes32 secretHash; - } - ``` - -3. **Sign and submit** - The message, along with the domain data, must be signed with the wallet, and the signature is sent with the initiate request to the relayer. - - ```bash - POST /relayer/initiate - ``` - - Example request: - ```json - { - "order_id": "", - "signature": "", - "perform_on": "Source" - } - ``` - - Expected response: - ```json - { - "result": "", - "status": "Ok" - } - ``` - -**Initiating on Bitcoin:** - -On Bitcoin, initiation can be done in two ways: - -1. Fund the HTLC script address directly using a Bitcoin wallet -2. Construct a transaction paying the required amount to the HTLC script address and broadcast it - -The HTLC script address is the swap ID of the source chain swap, found in the `source_swap` field in the `/orders/id/:id` response. - -### Setup Bitcoin Instant-Refund +### 6. Initiating transactions + +The initiation process differs based on the source chain. After creating an order and approving tokens (for EVM), you'll see the initiation screen with transaction details ready to be signed and broadcast: + + + ![Initiate Transaction](../images/api-demo-app/Initiate_txn.png) + + +#### Bitcoin Initiation + +For Bitcoin swaps, construct and broadcast a transaction to the HTLC address: + + +```rust expandable htlc_handler.rs +pub fn initiate_htlc( + &self, + private_key: PrivateKey, + htlc_addr: bitcoin::Address, + amount: i64, +) -> Result { + let public_key = PublicKey::from_private_key(&self.secp, &private_key); + let compressed_pubkey = CompressedPublicKey::try_from(public_key).unwrap(); + let sender_address = Address::p2wpkh(&compressed_pubkey, self.network); + + let runtime = tokio::runtime::Runtime::new() + .map_err(|e| anyhow!("Unable to create runtime: {}", e))?; + + let utxos = runtime.block_on( + self.indexer + .get_utxos_for_amount(&sender_address.to_string(), amount), + )?; + + let mut inputs: Vec = Vec::new(); + let mut input_values: Vec = Vec::new(); + for utxo in utxos { + let txid = Txid::from_str(&utxo.txid)?; + inputs.push(TxIn { + previous_output: OutPoint { + txid, + vout: utxo.vout, + }, + script_sig: ScriptBuf::new(), + sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: Witness::new(), + }); + input_values.push(utxo.value); + } -Instant refund is triggered automatically in these scenarios: + let fee = 250 * inputs.len() as u64; + let total_input: u64 = input_values.iter().sum(); -1. **Order Expiry**: User initiates swap → Filler fills → User fails to redeem before expiry → Instant refund triggered -2. **Partial Fill**: User initiates swap → Filler confirms partial fill → Remaining unfilled portion triggers instant refund + let output = TxOut { + value: Amount::from_sat(amount as u64), + script_pubkey: htlc_addr.script_pubkey(), + }; -To enable instant refund when the source swap is bitcoin, make the following API calls. + let mut outputs = vec![output]; -**Generate signature hashes** + if total_input > (amount as u64 + fee) { + outputs.push(TxOut { + value: Amount::from_sat(total_input - amount as u64 - fee), + script_pubkey: sender_address.script_pubkey(), + }); + } -```bash -POST /relayer/bitcoin/instant-refund-hash -``` + let mut unsigned_tx = Transaction { + version: Version::TWO, + lock_time: LockTime::ZERO, + input: inputs, + output: outputs, + }; + + let mut sighash_cache = SighashCache::new(&mut unsigned_tx); + + for i in 0..input_values.len() { + let script_pubkey = ScriptBuf::new_p2wpkh(&public_key.wpubkey_hash()?); + let sighash_type = EcdsaSighashType::All; + let sighash = sighash_cache.p2wpkh_signature_hash( + i, + &script_pubkey, + Amount::from_sat(input_values[i]), + sighash_type, + )?; + + let msg = Message::from(sighash); + let signature = self.secp.sign_ecdsa(&msg, &private_key.inner); + + let btc_signature = bitcoin::ecdsa::Signature { + signature, + sighash_type, + }; + let pubkey_bytes = public_key.to_bytes(); + *sighash_cache.witness_mut(i).unwrap() = Witness::p2wpkh( + &btc_signature, + &bitcoin::secp256k1::PublicKey::from_slice(&pubkey_bytes)?, + ) + } -Generates the transaction digest(s) that must be signed to enable instant refund. + let signed_tx = sighash_cache.into_transaction(); -Request Body: -```json -{ - "order_id": "" + Ok(signed_tx.clone()) } ``` - -Response: -```json -{ - "sighashes": [ - "" - ] + + +#### EVM Initiation + +For EVM chains, sign EIP-712 typed data and submit to the relayer: + + +```rust expandable order/evm.rs +// Sign EIP-712 message +match sign_order_typed_data(&typed_data, &context.wallet.signer) { + Ok(signature) => { + self.signature = Some(signature.clone()); + + // Start initiate process + self.progress = OrderProgress::InitiatingTransaction; + self.set_status("Initiating transaction...".to_string()); + + // Send signature to initiate endpoint + match context + .api + .orders + .initiate_order(&order_response.order_id, &signature) + { + Ok(result) => { + self.initiate_result = Some(format!("{result:?}")); + self.set_status( + "Transaction initiated successfully!\nFetching order status..." + .to_string(), + ); + // Fetch actual order status from API + self.fetch_order_status(context); + } + Err(e) => { + self.progress = OrderProgress::Failed(e.to_string()); + self.set_status(format!("Initiation failed: {e}")); + } + } + } + Err(e) => { + self.progress = OrderProgress::Failed(e.to_string()); + self.set_status(format!("Signing failed: {e}")); + } } ``` - - -Sign each sighash using **Schnorr signature** with **SIGHASH_SINGLE | ANYONECANPAY** - - -**Submit instant refund transaction** - -```bash -POST /relayer/bitcoin/instant-refund -``` - -Accepts user signatures and stores the prepared SACP (Single + AnyoneCanPay) transaction for future use. - -Request Body: -```json -{ - "order_id": "", - "signatures": [ - "" - ] + + +### 7. Tracking order status + +Monitor your swap progress in real-time. The order status screen displays detailed information about your swap including transaction hashes, swap amounts, and the current state: + + + ![Order Status](../images/api-demo-app/Order_status.png) + + +The status dashboard provides comprehensive information including: +- Current order status (Created, Initiated, Awaiting Redeem, Redeemed) +- Swap amounts and asset details +- Real-time status updates + +Once the swap completes successfully, you'll see the final status with all transaction details confirmed: + + + ![Swap Completed](../images/api-demo-app/Swap_completed.png) + + + +```rust order/actions.rs +pub(super) fn fetch_order_status(&mut self, context: &mut AppContext) { + if let Some(order_id) = context.order.current_order_id.clone() { + match context.api.orders.get_order_details(&order_id) { + Ok(order_status) => { + self.order_id = order_status.order_id.clone(); + + let parsed_status = parse_order_status(&order_status); + let status_label = get_order_status_label(parsed_status); + + let status_msg = format!( + "Status: {} ({})\nOrder ID: {}\nSource: {} {}\nDest: {} {}\nCreated: {}{}{}", + status_label.as_str(), + parsed_status.as_str(), + order_status.order_id, + order_status.source_swap.amount, + order_status.source_swap.asset, + order_status.destination_swap.amount, + order_status.destination_swap.asset, + order_status.created_at, + if !order_status.source_swap.initiate_tx_hash.is_empty() { format!("\nInitiate Tx: {}", order_status.source_swap.initiate_tx_hash) } else { String::new() }, + if order_status.source_swap.current_confirmations > 0 { format!("\nConfirmations: {}/{}", order_status.source_swap.current_confirmations, order_status.source_swap.required_confirmations) } else { String::new() } + ); + + match parsed_status.as_str() { + "Redeemed" | "Refunded" => { + self.set_status(status_msg); + self.progress = OrderProgress::Completed; + } + "Expired" => { + self.set_status(status_msg); + self.progress = OrderProgress::Failed("Order expired".to_string()); + } + "Created" => { + self.update_action_status(&status_msg); + } + _ => { + if order_status.source_swap.initiate_tx_hash.is_empty() { + self.update_action_status(&status_msg); + } else { + self.set_status(status_msg); + self.progress = OrderProgress::CheckingStatus; + } + } + } + } + Err(e) => { + self.set_status(format!("Failed to fetch order status: {e}")); + } + } + } } ``` - -Response: -```json -{ - "status": "ok", - "result": "" + + +**Order status progression:** + +1. **Created** - Order submitted to orderbook +2. **Initiate Detected** - User's deposit transaction detected +3. **Initiated** - Deposit confirmed on source chain +4. **Awaiting Redeem** - Solver has filled on destination chain +5. **Redeem Detected** - Redemption transaction detected +6. **Redeemed** - Swap completed successfully + +The status parser (`src/service/garden/status.rs`) implements the complete logic: + + +```rust status.rs +pub fn parse_order_status(order: &OrderDetails) -> OrderStatusEnum { + // Check for redemption + if !order.destination_swap.redeem_tx_hash.is_empty() { + if order.destination_swap.redeem_block_number != "0" { + return OrderStatusEnum::Redeemed; + } + return if is_bitcoin(&order.destination_swap.chain) { + OrderStatusEnum::Redeemed + } else { + OrderStatusEnum::RedeemDetected + }; + } + + // Check for refund + if !order.source_swap.refund_tx_hash.is_empty() { + if order.source_swap.refund_block_number != "0" { + return OrderStatusEnum::Refunded; + } + return OrderStatusEnum::RefundDetected; + } + + // Check for initiation + if !order.destination_swap.initiate_tx_hash.is_empty() { + return OrderStatusEnum::AwaitingRedeem; + } + + if !order.source_swap.initiate_tx_hash.is_empty() { + if order.source_swap.initiate_block_number != "0" { + return OrderStatusEnum::Initiated; + } + return OrderStatusEnum::InitiateDetected; + } + + OrderStatusEnum::Created } ``` + -**Validation:** -- Signatures are verified against generated sighashes -- Public key must match swap initiator -- Schnorr signature format with correct SIGHASH type enforced +## Key implementation details -With this, Bitcoin swaps can be refunded instantly to the user if the order expires or is partially filled. +### Bitcoin HTLC construction -### Redeem asset +The app includes a complete Bitcoin HTLC handler (`src/service/blockchain/bitcoin/htlc_handler.rs`) that: -The redemption step finalizes the swap, allowing the user to claim assets on the destination chain after the order has been successfully initiated and confirmed. +- Fetches UTXOs from Bitcoin indexers +- Constructs P2WPKH transactions +- Signs with Schnorr signatures +- Broadcasts to the network +- Handles Taproot script paths -**Prerequisites:** -- The swap must be complete on the `source chain`, and assets must be ready on the `destination chain` -- The destination chain must show an `initiate_tx_hash` under `destination_swap` -- The `secret` generated during order creation must be revealed +### EIP-712 signing -**Retrieving order details:** +For EVM chains, the app uses Alloy to sign typed data: -Poll the `/orders/id/:id` endpoint to fetch the latest order status. Once `destination_swap.initiate_tx_hash` is present, the destination HTLC is funded and ready for redemption. + +```rust expandable context.rs +use alloy::signers::local::PrivateKeySigner; -**Redemption on EVM chain:** - -Use the `/relayer/redeem` endpoint to submit the redemption request, including the secret that proves the user can claim the funds. +pub struct WalletContext { + pub signer: LocalSigner, + pub btc_private_key: bitcoin::PrivateKey, + pub btc_address: String, + pub provider_urls: HashMap, +} -```bash -POST /relayer/redeem +impl WalletContext { + fn new(network: &str, provider_urls: HashMap) -> WalletContext { + let eth_priv_key = env::var("PRIV_KEY").expect("please provide a valid PRIV_KEY in env"); + let btc_priv_key = env::var("BTC_PRIV_KEY").unwrap_or(eth_priv_key.clone()); + + let signer = PrivateKeySigner::from_str(ð_priv_key).expect("ERR CREATING ETH SIGNER"); + let btc_network = match network { + "mainnet" => bitcoin::Network::Bitcoin, + "testnet" => bitcoin::Network::Testnet4, + _ => bitcoin::Network::Regtest, + }; + + let btc_private_key = if btc_priv_key.len() == 64 { + let priv_key_bytes = hex::decode(&btc_priv_key).unwrap(); + PrivateKey::from_slice(&priv_key_bytes, btc_network).unwrap() + } else { + PrivateKey::from_wif(&btc_priv_key).unwrap() + }; + let secp = Secp256k1::new(); + let pubkey = PublicKey::from_private_key(&secp, &btc_private_key); + let btc_pubkey = CompressedPublicKey::try_from(pubkey).unwrap(); + let btc_address = Address::p2wpkh(&btc_pubkey, btc_network).to_string(); + + Self { + signer, + btc_network, + btc_private_key, + btc_address, + provider_urls, + } + } +} ``` + + +### TUI architecture + +The terminal UI is built with `ratatui` and follows a state machine pattern: -Example request: -```json -{ - "order_id": "", - "secret": "", - "perform_on": "Destination" -} +``` +NetworkSelector → AssetSelector → SwapInformation → CreateOrder → OrderDashboard + ↑ ↓ ↓ ↓ ↓ + └──────────┴───────────┴─────────┴──────────┘ + (back navigation) ``` -Expected response: -```json -{ - "status": "Ok", - "result": "" +Each state implements the `State` trait: + + +```rust mod.rs +pub trait State { + fn draw(&mut self, f: &mut Frame, context: Option<&AppContext>); + fn handle_key(&mut self, key: KeyEvent, context: Option<&AppContext>) + -> Result>; + fn as_any(&self) -> &dyn Any; } ``` + -**Redeeming on Bitcoin:** +## API reference -For Bitcoin-based swaps, redemption involves constructing and signing a transaction with the appropriate witness data. +The app demonstrates usage of Garden's V2 API: -The HTLC on Bitcoin is constructed using the `destination_swap` details from `/orders/id/:id`. +| Endpoint | Purpose | +|----------|---------| +| `GET /v2/chains` | Fetch all supported chains and assets | +| `GET /v2/quote` | Get real-time swap quotes | +| `POST /v2/orders` | Create a new swap order | +| `POST /v2/orders/{id}?action=initiate` | Submit EVM initiation signature | +| `GET /v2/orders/{id}` | Check order status | -To redeem: -- Use the secret from order creation -- Generate the required witness data: - - Secret - - Redeem leaf bytes - - Control block bytes -- Construct and sign the Bitcoin transaction -- Use Garden's relayer service for gasless redemption by sending the transaction hex bytes in the specified format +All API calls include: +- `garden-app-id` header for authentication +- `accept: application/json` header +- Proper error handling with `anyhow::Result` -[Example in Rust on how to construct and sign HTLC transactions](https://github.com/gardenfi/api-cookbook-demo/blob/main/src/service/blockchain/bitcoin/htlc_handler.rs) + + You now have a complete reference implementation for building cross-chain swap applications using Garden's V2 API! + -```bash -POST /bitcoin/redeem -``` - -Example request: -```json -{ - "order_id": "", - "redeem_tx_bytes": "" -} -``` +## Next steps -Expected response: -```json -{ - "status": "Ok", - "result": "" -} -``` +By exploring this cookbook, you've seen how to build a production-ready swap application. Consider extending it with: -## Next Steps +- **Multi-order management** to track multiple swaps simultaneously +- **Web interface** using the same backend logic +- **Advanced Bitcoin features** like RBF and CPFP +- **Order history persistence** with a database +- **Affiliate fee integration** for monetization - - Explore the Garden SDK for easier integration + + View complete V2 API documentation - - View complete API documentation + + Explore the full source code - -You now have everything you need to integrate Garden swaps into your application using our APIs. diff --git a/developers/guides/cookbook.mdx b/developers/guides/cookbook.mdx index 8e3b504..0193fa1 100644 --- a/developers/guides/cookbook.mdx +++ b/developers/guides/cookbook.mdx @@ -9,11 +9,11 @@ Each guide walks you through a different use case, helping you integrate efficie Build a Bitcoin bridge in Next.js using Garden SDK. - - Build a terminal UI app using Garden API (full cookbook guide coming soon). + + Build a cross-chain swap terminal UI in Rust using Garden API. - Check back regularly for new recipes! If you're looking for a specific recipe, drop by our [Townhall](https://discord.gg/dZwSjh9922) and let us know. + Check back regularly for new recipes! If you're looking for a specific recipe, drop by our [Townhall](https://discord.gg/B7RczEFuJ5) and let us know. diff --git a/developers/guides/sdk.mdx b/developers/guides/sdk.mdx index cc7610a..54f4087 100644 --- a/developers/guides/sdk.mdx +++ b/developers/guides/sdk.mdx @@ -4,7 +4,7 @@ description: "Step-by-step guide to integrating Garden SDK for fetching quotes, --- -If you are stuck at any part of the implementation, drop a message in our [Townhall](https://discord.gg/dZwSjh9922)—our dev team is ready to assist! +If you are stuck at any part of the implementation, drop a message in our [Townhall](https://discord.gg/B7RczEFuJ5)—our dev team is ready to assist! This cookbook provides a step-by-step guide to integrating Garden SDK for fetching quotes, executing swaps, and tracking them. It walks through building a simple cross-chain bridge in a Next.js environment, enabling seamless swaps between BTC (Bitcoin Testnet4) and WBTC (Ethereum Sepolia). @@ -146,7 +146,7 @@ Now that you have the quotes, it's time to execute the swap. Garden SDK provides Here's what it does: 1. Creates your swap order. -2. Waits for it to be matched with the [solver](/home/fundamentals/introduction/solvers). +2. Waits for it to be matched with the [solver](/home/fundamentals/core-concepts/solvers). 3. Automatically initiates the swap if you're on a smart contract chain. You'll need to provide the swap parameters (including the quote details you got earlier). The hook will return either a matched order or an error message if something goes wrong. diff --git a/developers/images/api-demo-app/Asset_pair.png b/developers/images/api-demo-app/Asset_pair.png new file mode 100644 index 0000000..d2b6254 Binary files /dev/null and b/developers/images/api-demo-app/Asset_pair.png differ diff --git a/developers/images/api-demo-app/Create_order.png b/developers/images/api-demo-app/Create_order.png new file mode 100644 index 0000000..9bee890 Binary files /dev/null and b/developers/images/api-demo-app/Create_order.png differ diff --git a/developers/images/api-demo-app/Initiate_txn.png b/developers/images/api-demo-app/Initiate_txn.png new file mode 100644 index 0000000..7463ed9 Binary files /dev/null and b/developers/images/api-demo-app/Initiate_txn.png differ diff --git a/developers/images/api-demo-app/Network_selector.png b/developers/images/api-demo-app/Network_selector.png new file mode 100644 index 0000000..4804ecd Binary files /dev/null and b/developers/images/api-demo-app/Network_selector.png differ diff --git a/developers/images/api-demo-app/Order_created.png b/developers/images/api-demo-app/Order_created.png new file mode 100644 index 0000000..ecc1f6d Binary files /dev/null and b/developers/images/api-demo-app/Order_created.png differ diff --git a/developers/images/api-demo-app/Order_status.png b/developers/images/api-demo-app/Order_status.png new file mode 100644 index 0000000..03f6da4 Binary files /dev/null and b/developers/images/api-demo-app/Order_status.png differ diff --git a/developers/images/api-demo-app/Swap_completed.png b/developers/images/api-demo-app/Swap_completed.png new file mode 100644 index 0000000..1c800c7 Binary files /dev/null and b/developers/images/api-demo-app/Swap_completed.png differ diff --git a/developers/images/api-demo-app/Swap_page.png b/developers/images/api-demo-app/Swap_page.png new file mode 100644 index 0000000..e9086ec Binary files /dev/null and b/developers/images/api-demo-app/Swap_page.png differ diff --git a/developers/images/api-demo-app/Token_approval.png b/developers/images/api-demo-app/Token_approval.png new file mode 100644 index 0000000..b8f16b5 Binary files /dev/null and b/developers/images/api-demo-app/Token_approval.png differ diff --git a/developers/localnet.mdx b/developers/localnet.mdx index 7f4e2d6..1cb65fe 100644 --- a/developers/localnet.mdx +++ b/developers/localnet.mdx @@ -9,8 +9,8 @@ Merry is a CLI tool that leverages Docker to set up a multi-chain testing enviro - **Bitcoin regtest node:** A local Bitcoin testnet environment. - **EVM localnet nodes:** Local Ethereum and Arbitrum test environments. Simply add the localnet details to your EVM wallet to detect and interact. -- **Filler bot:** Simulates the behavior of a live [solver](/home/fundamentals/introduction/solvers) based on predefined strategies. -- **Orderbook:** Local version of the [order book](/home/fundamentals/introduction/auctions) to test how intents are matched and fulfilled. +- **Filler bot:** Simulates the behavior of a live [solver](/home/fundamentals/core-concepts/solvers) based on predefined strategies. +- **Orderbook:** Local version of the [order book](/home/fundamentals/core-concepts/auctions) to test how intents are matched and fulfilled. - **Faucet:** Generate unlimited test funds for seamless testing. - **Electrum services:** Lightweight wallet support for interacting with Bitcoin network. diff --git a/developers/supported-chains.mdx b/developers/supported-chains.mdx index 40df2dc..3af63ca 100644 --- a/developers/supported-chains.mdx +++ b/developers/supported-chains.mdx @@ -29,5 +29,5 @@ Garden uses the following contracts to perform swaps on respective chains: If you would like to see a chain or asset that isn't listed here, reach out to - us in the [Townhall](https://discord.gg/dZwSjh9922). + us in the [Townhall](https://discord.gg/B7RczEFuJ5). diff --git a/docs.json b/docs.json index 99081b7..e3a0fed 100644 --- a/docs.json +++ b/docs.json @@ -136,7 +136,8 @@ "group": "Developer Guides", "pages": [ "developers/guides/cookbook", - "developers/guides/sdk" + "developers/guides/sdk", + "developers/guides/api" ] }, { @@ -206,6 +207,12 @@ "api-reference/endpoint/orders/get-instant-refund-hash", "api-reference/endpoint/orders/patch" ] + }, + { + "group": "Affiliate", + "pages": [ + "api-reference/endpoint/affiliate/get-earnings" + ] } ] }, @@ -230,7 +237,7 @@ }, { "anchor": "Community", - "href": "https://discord.gg/dZwSjh9922", + "href": "https://discord.gg/B7RczEFuJ5", "icon": "discord" } ] @@ -244,7 +251,7 @@ "links": [ { "label": "Support", - "href": "https://discord.gg/dZwSjh9922" + "href": "https://discord.gg/B7RczEFuJ5" } ], "primary": { @@ -257,7 +264,7 @@ "socials": { "x": "https://x.com/garden_finance", "github": "https://github.com/gardenfi", - "discord": "https://discord.gg/dZwSjh9922" + "discord": "https://discord.gg/B7RczEFuJ5" }, "links": [ { diff --git a/home/about.mdx b/home/about.mdx index 398a07c..4a88447 100644 --- a/home/about.mdx +++ b/home/about.mdx @@ -10,15 +10,15 @@ With over a billion dollars in volume facilitated, Garden stands apart from othe - Fast, secure, and low-cost swaps. [Head to the app]((https://app.garden.finance)) and try Garden now. + Fast, secure, and low-cost swaps. [**Head to the app**](https://app.garden.finance) and try Garden now. - If you're a developer interested in building or integrating with Garden, check out the [API](/developers/api/overview) or [SDK](/developers/sdk/overview). + If you're a developer interested in building or integrating with Garden, check out the [**API**](/developers/api/overview) or [**SDK**](/developers/sdk/overview). - Provide liquidity to Garden by becoming a [solver](/home/fundamentals/introduction/solvers) for the Garden protocol. If you're interested, reach out to us in the [Townhall](https://discord.gg/dZwSjh9922) to discuss the next steps. + Provide liquidity to Garden by becoming a [solver](/home/fundamentals/core-concepts/solvers) for the Garden protocol. If you're interested, reach out to us in the [**Townhall**](https://discord.gg/B7RczEFuJ5) to discuss the next steps. - [Stake on Garden](https://app.garden.finance/stake) to help guide the protocol’s direction and earn rewards for your participation. + [**Stake on Garden**](https://app.garden.finance/stake) to help guide the protocol’s direction and earn rewards for your participation. diff --git a/home/fundamentals/benefits/better-prices.mdx b/home/fundamentals/benefits/better-prices.mdx index cb02bf5..3d70715 100644 --- a/home/fundamentals/benefits/better-prices.mdx +++ b/home/fundamentals/benefits/better-prices.mdx @@ -5,7 +5,7 @@ description: "Garden delivers unmatched rates by leveraging on-chain and off-cha Traditional bridges often rely on AMMs to facilitate swaps, exposing users to slippage based on the depth of the liquidity pools. This is especially inefficient for swaps between likewise assets, such as BTC and WBTC or cbBTC. -Garden's intents-based architecture removes this inefficiency. [Solvers](/home/fundamentals/introduction/solvers) maintain flexibility in their quotes and compete to fulfill user intents using on-chain and off-chain liquidity. +Garden's intents-based architecture removes this inefficiency. [Solvers](/home/fundamentals/core-concepts/solvers) maintain flexibility in their quotes and compete to fulfill user intents using on-chain and off-chain liquidity. Users not only get a competitive price at the time of swap initiation but also have the potential to settle at better prices. By leveraging peer-to-peer matching, and advanced settlement mechanisms like [xCoW](/home/fundamentals/how-it-works/cross-chain-coincidence-of-wants-xcow), Garden dynamically optimizes swaps during execution. diff --git a/home/fundamentals/benefits/broad-chain-coverage.mdx b/home/fundamentals/benefits/broad-chain-coverage.mdx index 650321a..2f46fbf 100644 --- a/home/fundamentals/benefits/broad-chain-coverage.mdx +++ b/home/fundamentals/benefits/broad-chain-coverage.mdx @@ -5,7 +5,7 @@ description: "Garden's simple design enables quick-and-easy support for new chai Supporting many chains typically requires maintaining liquidity pools on each chain. This ties up idle capital, limiting how many chains traditional bridges can practically support. -Using an [intents](/home/fundamentals/introduction/intents)-based model removes the need for pre-deployed liquidity. Liquidity is provided on demand at the moment of execution. This allows support for a wide range of blockchains, without additional liquidity constraints. +Using an [intents](/home/fundamentals/core-concepts/intents)-based model removes the need for pre-deployed liquidity. Liquidity is provided on demand at the moment of execution. This allows support for a wide range of blockchains, without additional liquidity constraints. diff --git a/home/fundamentals/benefits/free-option-protection.mdx b/home/fundamentals/benefits/free-option-protection.mdx index 38688ff..4223bf0 100644 --- a/home/fundamentals/benefits/free-option-protection.mdx +++ b/home/fundamentals/benefits/free-option-protection.mdx @@ -3,7 +3,7 @@ title: "Free Option Protection" description: "Garden protects against the free option problems via its incentive structure" --- -The **free option problem** in [atomic swaps](/home/fundamentals/introduction/atomic-swaps) arises when one party exploits market conditions by deciding to complete or abort a swap based on price movements, leaving the counterparty at a disadvantage. These cases are covered in [scenarios and safeguards](/home/fundamentals/introduction/atomic-swaps#scenarios-and-safeguards). +The **free option problem** in [atomic swaps](/home/fundamentals/core-concepts/atomic-swaps) arises when one party exploits market conditions by deciding to complete or abort a swap based on price movements, leaving the counterparty at a disadvantage. These cases are covered in [scenarios and safeguards](/home/fundamentals/core-concepts/atomic-swaps#scenarios-and-safeguards). Garden addresses this challenge with built-in mechanisms that ensure fairness and accountability for the participants. @@ -17,7 +17,7 @@ Garden addresses this challenge with built-in mechanisms that ensure fairness an This penalty directly discourages solver misuse and ensures stakers will keep solvers accountable as they can always switch their vote to another solver. - Settlement speed is already factored into the solver score [formula](/home/fundamentals/introduction/auctions), reducing the ability of unreliable solvers to win future intents. + Settlement speed is already factored into the solver score [formula](/home/fundamentals/core-concepts/auctions), reducing the ability of unreliable solvers to win future intents. diff --git a/home/fundamentals/benefits/no-custody-risk.mdx b/home/fundamentals/benefits/no-custody-risk.mdx index 076baef..34868d7 100644 --- a/home/fundamentals/benefits/no-custody-risk.mdx +++ b/home/fundamentals/benefits/no-custody-risk.mdx @@ -47,5 +47,5 @@ Garden's approach eliminates this category of risk by ensuring users maintain co -For more details, see [atomic swaps](/home/fundamentals/introduction/atomic-swaps) and [intent flow](/home/fundamentals/how-it-works/intent-flow). +For more details, see [atomic swaps](/home/fundamentals/core-concepts/atomic-swaps) and [intent flow](/home/fundamentals/how-it-works/intent-flow). \ No newline at end of file diff --git a/home/fundamentals/core-concepts/solvers.mdx b/home/fundamentals/core-concepts/solvers.mdx index 79c404c..3f6f202 100644 --- a/home/fundamentals/core-concepts/solvers.mdx +++ b/home/fundamentals/core-concepts/solvers.mdx @@ -3,15 +3,15 @@ title: "Solvers" description: "Understand how solvers act as market makers in Garden protocol to execute user intents efficiently" --- -Solvers are the market makers of Garden protocol, responsible for ensuring user [intents](/home/fundamentals/introduction/intents) are executed efficiently and securely. By leveraging diverse liquidity sources—on-chain, off-chain, and private order flows—solvers are incentivized to optimize every transaction for users, delivering competitive quotes. +Solvers are the market makers of Garden protocol, responsible for ensuring user [intents](./intents) are executed efficiently and securely. By leveraging diverse liquidity sources—on-chain, off-chain, and private order flows—solvers are incentivized to optimize every transaction for users, delivering competitive quotes. -Solvers address key challenges in decentralized systems. They enhance liquidity access by enabling the protocol to utilize existing DeFi liquidity rather than fragmenting it with native pools. For users, solvers offer [benefits](/home/fundamentals/introduction/intents#why-do-we-choose-intents) such as better pricing, MEV resistance, and higher chances of transaction finality, making the system more efficient and user-friendly. +Solvers address key challenges in decentralized systems. They enhance liquidity access by enabling the protocol to utilize existing DeFi liquidity rather than fragmenting it with native pools. For users, solvers offer [benefits](./intents#why-do-we-choose-intents%3F) such as better pricing, MEV resistance, and higher chances of transaction finality, making the system more efficient and user-friendly. ## How do solvers work? - Solvers receive user intents via the [order book](/home/fundamentals/introduction/auctions), detailing the desired outcomes such as assets, chains, and amounts. + Solvers receive user intents via the [order book](./auctions), detailing the desired outcomes such as assets, chains, and amounts. @@ -44,5 +44,5 @@ To become a solver, here's what you need: -Please reach out to us in the [Townhall](https://discord.gg/dZwSjh9922) for help with onboarding. +Please reach out to us in the [Townhall](https://discord.gg/B7RczEFuJ5) for help with onboarding. diff --git a/home/fundamentals/core-concepts/stakers.mdx b/home/fundamentals/core-concepts/stakers.mdx index 856e3a4..408d882 100644 --- a/home/fundamentals/core-concepts/stakers.mdx +++ b/home/fundamentals/core-concepts/stakers.mdx @@ -3,13 +3,13 @@ title: "Stakers" description: "Stakers support Garden protocol through token staking and solver governance" --- -Staking serves as the gateway for users to engage with the Garden protocol, supporting its decentralization, efficiency, and accountability. By staking **SEED tokens**, stakers can vote for trusted [solvers](/home/fundamentals/introduction/solvers) to execute intents and earn rewards based on their performance. This system incentivizes long-term [commitment](https://dune.com/garden_finance/gardenfinance#stake-your-seed), balances solver selection, and helps maintain the protocol's fairness and reliability. +Staking serves as the gateway for users to engage with the Garden protocol, supporting its decentralization, efficiency, and accountability. By staking **SEED tokens**, stakers can vote for trusted [solvers](./solvers) to execute intents and earn rewards based on their performance. This system incentivizes long-term [commitment](https://dune.com/garden_finance/gardenfinance#stake-your-seed), balances solver selection, and helps maintain the protocol's fairness and reliability. ## How does it work? - Anyone holding a minimum of **2,100 SEED** tokens is eligible to [stake](https://app.garden.finance/stake/). Staking has to be done in multiples of 2,100 SEED. Stakers deposit **SEED tokens** into the protocol, locking them for a chosen duration. Longer lock periods result in a higher staking multiplier, increasing both votes and potential rewards. Follow [this tutorial](/home/basics/guides/stake/stake-seed) for a step-by-step breakdown of staking. + Anyone holding a minimum of **2,100 SEED** tokens is eligible to [stake](https://app.garden.finance/stake/). Staking has to be done in multiples of 2,100 SEED. Stakers deposit **SEED tokens** into the protocol, locking them for a chosen duration. Longer lock periods result in a higher staking multiplier, increasing both votes and potential rewards. Follow [this tutorial](/home/resources/guides/stake/stake-seed) for a step-by-step breakdown of staking. For those looking to maximize their staking benefits, staking 21,000 SEED permanently mints the [Gardener pass](/home/governance/gardener-pass), an exclusive NFT that unlocks enhanced rewards, governance power, and tradability. diff --git a/home/governance/gardener-pass.mdx b/home/governance/gardener-pass.mdx index c0a2b94..bd572e7 100644 --- a/home/governance/gardener-pass.mdx +++ b/home/governance/gardener-pass.mdx @@ -10,7 +10,7 @@ Initially introduced during the [seasons](https://garden.finance/blog/seasons-in Pass holders gain a 7x multiplier on their staking rewards. - Staking 21,000 SEED normally gives you 10 governance votes. However, Garden pass holders receive 70 votes because of the 7x multiplier, offering substantial influence in protocol governance and revenue sharing. + Staking 21,000 SEED normally gives you 10 governance votes. However, Gardener Pass holders receive 70 votes because of the 7x multiplier, offering substantial influence in protocol governance and revenue sharing. As a fully tradable NFT, the pass can be sold or transferred on [marketplaces](https://opensea.io/collection/gardener-pass). Minting a pass requires permanently staking SEED, effectively burning it, which establishes its inherent value. @@ -18,7 +18,7 @@ Initially introduced during the [seasons](https://garden.finance/blog/seasons-in -You can mint the Gardener Pass by staking **21,000 SEED** indefinitely on the [staking page](/home/basics/guides/stake/stake-seed). +You can mint the Gardener Pass by staking **21,000 SEED** indefinitely on the [staking page](/home/resources/guides/stake/stake-seed). ## What's next? diff --git a/home/governance/governance-process.mdx b/home/governance/governance-process.mdx index 1c6c309..a62929c 100644 --- a/home/governance/governance-process.mdx +++ b/home/governance/governance-process.mdx @@ -3,7 +3,7 @@ title: "Governance Process" description: "Garden's community governance process overview, from temp checks to implementation" --- -To participate in Garden's governance, one must be an active [staker](/home/fundamentals/introduction/stakers). The number of governance votes you own is dependent on the staking multiplier, similar to staking rewards. +To participate in Garden's governance, one must be an active [staker](/home/fundamentals/core-concepts/stakers). The number of governance votes you own is dependent on the staking multiplier, similar to staking rewards. Voting Multiplier Chart @@ -38,7 +38,7 @@ For example, if you staked 21,000 SEED for 24 months, then your total voting pow Discuss your idea with community members to gather feedback and understand their perspectives. Choose a platform for your Temp Check: - + Post a message in the #governance channel **Criteria:** 10+ 🔼 (up votes) to proceed @@ -64,7 +64,7 @@ Raising a proposal requires a minimum of **500 votes**. Proposers are responsibl ### Community voting -The voting phase lasts for **7 days**, where stakers cast their votes via snapshot. Proposers can use this time to actively engage with the community in the [Townhall](https://discord.gg/dZwSjh9922) to generate excitement and support for their proposal. +The voting phase lasts for **7 days**, where stakers cast their votes via snapshot. Proposers can use this time to actively engage with the community in the [Townhall](https://discord.gg/B7RczEFuJ5) to generate excitement and support for their proposal. Encourage discussions, answer questions, and highlight the benefits of the proposal to motivate community members to participate in the voting process. diff --git a/home/governance/snapshot.mdx b/home/governance/snapshot.mdx index 03e9299..81738e3 100644 --- a/home/governance/snapshot.mdx +++ b/home/governance/snapshot.mdx @@ -36,4 +36,4 @@ Garden's Snapshot system features two key roles: ## Voting power -Voting power in Garden is determined by staking [multipliers](/home/fundamentals/introduction/stakers) and ownership of the Gardener Pass NFT. Stakers gain increased voting power based on their staking multiplier, which rewards long-term commitment to the protocol. Additionally, Gardener Pass NFT holders receive a fixed voting power of 70 votes. +Voting power in Garden is determined by staking [multipliers](/home/fundamentals/core-concepts/stakers) and ownership of the Gardener Pass NFT. Stakers gain increased voting power based on their staking multiplier, which rewards long-term commitment to the protocol. Additionally, Gardener Pass NFT holders receive a fixed voting power of 70 votes. diff --git a/home/governance/tokenomics.mdx b/home/governance/tokenomics.mdx index 1038872..811337c 100644 --- a/home/governance/tokenomics.mdx +++ b/home/governance/tokenomics.mdx @@ -6,10 +6,10 @@ description: "SEED is the utility token of Garden, designed to facilitate partic The SEED token launched on [January 18th, 2024](https://etherscan.io/tx/0x02446e6d65cef97f2a172382179c035bf5cd5738dfc1ba3c01c7f8a8439ec00d). It empowers holders to actively shape the Garden ecosystem: - + Stake SEED to participate in protocol governance and earn revenue. - + Holding 210,000 SEED tokens grants eligibility to become a solver. diff --git a/home/resources/guides/stake/stake-seed.mdx b/home/resources/guides/stake/stake-seed.mdx index da9ee14..835cf8e 100644 --- a/home/resources/guides/stake/stake-seed.mdx +++ b/home/resources/guides/stake/stake-seed.mdx @@ -23,7 +23,7 @@ Participate in the Garden protocol by staking [SEED](/home/governance/tokenomics - Select your preferred **Staking duration** from the drop-down menu. The longer you stake, the higher your rewards, based on the [staking multiplier](/home/fundamentals/introduction/stakers#how-does-it-work). + Select your preferred **Staking duration** from the drop-down menu. The longer you stake, the higher your rewards, based on the [staking multiplier](/home/fundamentals/core-concepts/stakers#how-does-it-work). Choose staking duration @@ -63,5 +63,5 @@ Participate in the Garden protocol by staking [SEED](/home/governance/tokenomics -If you have any questions about staking or encounter issues while staking or withdrawing rewards, drop a message in the [Townhall](https://discord.gg/dZwSjh9922)—our community will assist you promptly. +If you have any questions about staking or encounter issues while staking or withdrawing rewards, drop a message in the [Townhall](https://discord.gg/B7RczEFuJ5)—our community will assist you promptly. diff --git a/home/resources/guides/swap/btc-wbtc.mdx b/home/resources/guides/swap/btc-wbtc.mdx index c458f95..5734689 100644 --- a/home/resources/guides/swap/btc-wbtc.mdx +++ b/home/resources/guides/swap/btc-wbtc.mdx @@ -166,9 +166,9 @@ After receiving your WBTC: ## Need Help? -- **Questions**: Join our [Discord community](https://discord.com/invite/kqMBgeAKAh) +- **Questions**: Join our [Discord community](https://discord.gg/B7RczEFuJ5) - **Technical Issues**: Check the [troubleshooting guide](/developers/troubleshooting) -Want to swap back? Check out our guide on [how to swap WBTC to BTC](/home/basics/guides/swap/wbtc-btc). +Want to swap back? Check out our guide on [how to swap WBTC to BTC](/home/resources/guides/swap/wbtc-btc). \ No newline at end of file diff --git a/home/resources/guides/swap/wbtc-btc.mdx b/home/resources/guides/swap/wbtc-btc.mdx index 9e49830..168000e 100644 --- a/home/resources/guides/swap/wbtc-btc.mdx +++ b/home/resources/guides/swap/wbtc-btc.mdx @@ -146,15 +146,15 @@ Once you receive your Bitcoin: ## Related Guides - + Want to wrap Bitcoin again? Learn how to convert BTC back to WBTC - + Move WBTC between different blockchain networks ## Need Help? -- **Questions**: Join our [Discord community](https://discord.com/invite/kqMBgeAKAh) +- **Questions**: Join our [Discord community](https://discord.gg/B7RczEFuJ5) - **Technical Support**: Check our [troubleshooting guide](/developers/troubleshooting) \ No newline at end of file diff --git a/home/resources/guides/swap/wbtc-wbtc.mdx b/home/resources/guides/swap/wbtc-wbtc.mdx index 725af28..e60e394 100644 --- a/home/resources/guides/swap/wbtc-wbtc.mdx +++ b/home/resources/guides/swap/wbtc-wbtc.mdx @@ -216,17 +216,17 @@ Moving WBTC from Arbitrum back to Ethereum mainnet. ## Related Guides - + Wrap Bitcoin to get WBTC for cross-chain transfers - + Unwrap WBTC back to native Bitcoin ## Need Help? -- **Discord Support**: Join our [community](https://discord.com/invite/kqMBgeAKAh) for assistance +- **Discord Support**: Join our [community](https://discord.gg/B7RczEFuJ5) for assistance - **Technical Issues**: Check our [troubleshooting guide](/developers/troubleshooting) - **Documentation**: Review our [developer docs](/developers/overview) for integration details diff --git a/logo/dark.svg b/logo/dark.svg index 579a37d..e037f52 100644 --- a/logo/dark.svg +++ b/logo/dark.svg @@ -1,11 +1,11 @@ - - - - + + + + - - + + diff --git a/logo/light.svg b/logo/light.svg index 5ffe2f8..4ba2d4f 100644 --- a/logo/light.svg +++ b/logo/light.svg @@ -1,11 +1,11 @@ - - - - + + + + - - + + diff --git a/snippets/supported-assets.jsx b/snippets/supported-assets.jsx index 15acb20..bdab655 100644 --- a/snippets/supported-assets.jsx +++ b/snippets/supported-assets.jsx @@ -14,7 +14,15 @@ export const getChainName = (chain) => { }; export const trimAssetName = (id) => { - return id.split(":")[1].toUpperCase(); + const ASSET_NAME_OVERRIDE = { + cbbtc: "cbBTC", + ibtc: "iBTC", + ubtc: "uBTC", + }; + + const assetName = id.split(":")[1]; + const override = ASSET_NAME_OVERRIDE[assetName.toLowerCase()]; + return override || assetName.toUpperCase(); }; export const titilize = (chain) => { @@ -48,6 +56,7 @@ export const getExplorerUrl = (chain, address, explorer_url) => { }; export const AssetRow = ({ chain, assets }) => { + // console.log(assets) return (
{ colSpan={4} >
{chain.chain} + {chain.chain} {titilize(getChainName(chain.chain))} @@ -72,7 +85,11 @@ export const AssetRow = ({ chain, assets }) => { className="border-none flex items-center gap-2" > - {asset.id} + {asset.id} {trimAssetName(asset.id)}