{"_id":"@0takuc0mrade/swiftrail-sdk","_rev":"2-bcad7ffc5dc03b733d35a11dc0beea6a","name":"@0takuc0mrade/swiftrail-sdk","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@0takuc0mrade/swiftrail-sdk","version":"0.1.0","keywords":["arbitrum","gasless","checkout","usdc","sdk"],"license":"MIT","_id":"@0takuc0mrade/swiftrail-sdk@0.1.0","maintainers":[{"name":"0takuc0mrade","email":"junep059@gmail.com"}],"dist":{"shasum":"37a94846dc9b82ff008c56cd4cf0dcebf3f8ef50","tarball":"https://registry.npmjs.org/@0takuc0mrade/swiftrail-sdk/-/swiftrail-sdk-0.1.0.tgz","fileCount":6,"integrity":"sha512-cMfIC89TNgW6G7qVVXuvan4nOl2qGOOZe4BhexyHBQsvYcp9Weoq7sNkI4bXbuY0mRo0XrCoC4PLc2poBBX3zw==","signatures":[{"sig":"MEUCID0JUeedVNDX+jVNo/neKNl0OQSyBLAq5RKlELT7Y8D3AiEAmcY/nJlLlEPFK2QuC5W4n9zCjpS/zbgUiZPs1/Vj7g8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":471345},"main":"sdk.js","type":"module","types":"sdk.d.ts","module":"sdk.js","exports":{".":{"types":"./sdk.d.ts","import":"./sdk.js"}},"_npmUser":{"name":"0takuc0mrade","email":"junep059@gmail.com"},"_npmVersion":"11.10.0","description":"SwiftRail gasless checkout SDK for Arbitrum","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/swiftrail-sdk_0.1.0_1771336161094_0.448673753092949","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@0takuc0mrade/swiftrail-sdk","version":"0.1.1","description":"SwiftRail gasless checkout SDK for Arbitrum","license":"MIT","type":"module","main":"sdk.js","module":"sdk.js","types":"sdk.d.ts","exports":{".":{"types":"./sdk.d.ts","import":"./sdk.js"}},"keywords":["arbitrum","gasless","checkout","usdc","sdk"],"_id":"@0takuc0mrade/swiftrail-sdk@0.1.1","_nodeVersion":"24.13.0","_npmVersion":"11.10.0","dist":{"integrity":"sha512-d8CCN5k+rBn3AW5faVeKAyGZVcyucRBPPoMS16tuGeJdWgti7M42yLbdK8gax/OcCmywHfPNDZn12C2Hy5a8uw==","shasum":"ffbedd0ec86f986adf105b5042807bf89e5073de","tarball":"https://registry.npmjs.org/@0takuc0mrade/swiftrail-sdk/-/swiftrail-sdk-0.1.1.tgz","fileCount":6,"unpackedSize":471564,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBni+ndtSxw+OGqJU88bHDXW32FguC0Pn78cZVjQNBsRAiEAnyd+GtcTSBjo69bnTLYl2uy8LhPOQd/fQZ0sykyRb+8="}]},"_npmUser":{"name":"0takuc0mrade","email":"junep059@gmail.com"},"directories":{},"maintainers":[{"name":"0takuc0mrade","email":"junep059@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/swiftrail-sdk_0.1.1_1771336769244_0.2654662246013364"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-17T13:49:20.960Z","modified":"2026-02-17T13:59:29.583Z","0.1.0":"2026-02-17T13:49:21.319Z","0.1.1":"2026-02-17T13:59:29.463Z"},"license":"MIT","keywords":["arbitrum","gasless","checkout","usdc","sdk"],"description":"SwiftRail gasless checkout SDK for Arbitrum","maintainers":[{"name":"0takuc0mrade","email":"junep059@gmail.com"}],"readme":"# SDK Integration Guide\n\nThis guide shows how to integrate the checkout SDK into your own app (React, Vite, Next.js).\n\nPublished npm package:\n\n1. `@0takuc0mrade/swiftrail-sdk`\n2. `https://www.npmjs.com/package/@0takuc0mrade/swiftrail-sdk`\n\n## Install from npm\n\n```bash\nnpm i @0takuc0mrade/swiftrail-sdk\n```\n\n## What the SDK handles\n\n1. Wallet connect (`connect_wallet`)\n2. Arbitrum Sepolia network guard/switch (`421614`)\n3. USDC permit signing (`eth_signTypedData_v4`)\n4. Relayer submission (`POST /submit-payment`)\n\n## Prerequisites\n\n1. Running relayer (production URL, or local dev URL such as `http://127.0.0.1:3000`)\n2. Deployed payment contract address\n3. Correct USDC token address for your chain\n4. Browser wallet provider (`window.ethereum`, MetaMask)\n\n## Build the SDK package\n\nFrom repo root:\n\n```bash\nwasm-pack build sdk --target web --out-dir ./frontend/pkg\n```\n\nFor another app/repo, set `--out-dir` to a folder inside that app and import from that path.\n\n## Shared integration pattern\n\n```js\nimport init, { ArbitrumCheckout } from \"@0takuc0mrade/swiftrail-sdk\";\n\nawait init();\n\nconst sdk = new ArbitrumCheckout(\n  \"https://your-relayer.example.com\", // relayer URL\n  \"0xYourPaymentContractAddress\",   // payment contract\n  \"0xYourUsdcAddress\"               // USDC token\n);\n\nconst user = await sdk.connect_wallet();\n\nconst merchant = \"0xMerchantAddress\";\nconst amount = \"20000000\"; // 20 USDC in base units (6 decimals)\nconst resultJson = await sdk.checkout(user, merchant, amount);\nconst result = JSON.parse(resultJson);\n```\n\n## React example\n\n```jsx\nimport { useEffect, useState } from \"react\";\nimport init, { ArbitrumCheckout } from \"@0takuc0mrade/swiftrail-sdk\";\n\nexport default function CheckoutWidget() {\n  const [sdk, setSdk] = useState(null);\n  const [user, setUser] = useState(\"\");\n  const [status, setStatus] = useState(\"\");\n\n  useEffect(() => {\n    let mounted = true;\n    (async () => {\n      await init();\n      if (!mounted) return;\n      setSdk(\n        new ArbitrumCheckout(\n          \"https://your-relayer.example.com\",\n          \"0xYourPaymentContractAddress\",\n          \"0xYourUsdcAddress\"\n        )\n      );\n    })().catch((e) => setStatus(String(e)));\n\n    return () => {\n      mounted = false;\n    };\n  }, []);\n\n  async function connect() {\n    if (!sdk) return;\n    try {\n      const addr = await sdk.connect_wallet();\n      setUser(String(addr));\n      setStatus(`Connected: ${String(addr)}`);\n    } catch (e) {\n      setStatus(`Connect failed: ${String(e)}`);\n    }\n  }\n\n  async function pay() {\n    if (!sdk || !user) return;\n    try {\n      const res = await sdk.checkout(user, \"0xMerchantAddress\", \"20000000\");\n      const parsed = JSON.parse(String(res));\n      setStatus(`Payment tx: ${parsed.payment_tx_hash}`);\n    } catch (e) {\n      setStatus(`Payment failed: ${String(e)}`);\n    }\n  }\n\n  return (\n    <div>\n      <button onClick={connect}>Connect</button>\n      <button onClick={pay}>Pay</button>\n      <pre>{status}</pre>\n    </div>\n  );\n}\n```\n\n## Vite example\n\nUse the same React example above. For plain Vite JS:\n\n```js\nimport init, { ArbitrumCheckout } from \"@0takuc0mrade/swiftrail-sdk\";\n\nconst status = document.querySelector(\"#status\");\nconst connectBtn = document.querySelector(\"#connect\");\nconst payBtn = document.querySelector(\"#pay\");\n\nawait init();\nconst sdk = new ArbitrumCheckout(\n  \"https://your-relayer.example.com\",\n  \"0xYourPaymentContractAddress\",\n  \"0xYourUsdcAddress\"\n);\n\nlet user = \"\";\n\nconnectBtn.onclick = async () => {\n  try {\n    user = String(await sdk.connect_wallet());\n    status.textContent = `Connected: ${user}`;\n  } catch (e) {\n    status.textContent = `Connect failed: ${String(e)}`;\n  }\n};\n\npayBtn.onclick = async () => {\n  try {\n    const res = await sdk.checkout(user, \"0xMerchantAddress\", \"20000000\");\n    const parsed = JSON.parse(String(res));\n    status.textContent = `Payment tx: ${parsed.payment_tx_hash}`;\n  } catch (e) {\n    status.textContent = `Payment failed: ${String(e)}`;\n  }\n};\n```\n\n## Next.js example (App Router)\n\nCreate a client component (important):\n\n```tsx\n\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport init, { ArbitrumCheckout } from \"@0takuc0mrade/swiftrail-sdk\";\n\nexport default function CheckoutClient() {\n  const [sdk, setSdk] = useState<ArbitrumCheckout | null>(null);\n  const [user, setUser] = useState(\"\");\n  const [status, setStatus] = useState(\"\");\n\n  useEffect(() => {\n    (async () => {\n      await init();\n      setSdk(\n        new ArbitrumCheckout(\n          \"https://your-relayer.example.com\",\n          \"0xYourPaymentContractAddress\",\n          \"0xYourUsdcAddress\"\n        )\n      );\n    })().catch((e) => setStatus(String(e)));\n  }, []);\n\n  async function connect() {\n    if (!sdk) return;\n    try {\n      setUser(String(await sdk.connect_wallet()));\n    } catch (e) {\n      setStatus(String(e));\n    }\n  }\n\n  async function pay() {\n    if (!sdk || !user) return;\n    try {\n      const raw = await sdk.checkout(user, \"0xMerchantAddress\", \"20000000\");\n      const parsed = JSON.parse(String(raw));\n      setStatus(`Payment tx: ${parsed.payment_tx_hash}`);\n    } catch (e) {\n      setStatus(`Payment failed: ${String(e)}`);\n    }\n  }\n\n  return (\n    <div>\n      <button onClick={connect}>Connect</button>\n      <button onClick={pay}>Pay</button>\n      <p>{status}</p>\n    </div>\n  );\n}\n```\n\n## Common mistakes\n\n1. Passing human-readable amount (`\"20\"`) instead of base units (`\"20000000\"`).\n2. Wrong USDC address for current chain.\n3. Calling SDK on server side (no `window.ethereum`).\n4. Not running relayer, or using wrong relayer URL.\n5. Not parsing SDK checkout response with `JSON.parse`.\n\n## Response fields\n\nOn success:\n\n1. `payment_tx_hash`\n2. `settlement_tx_hash`\n3. `gross_amount`\n4. `fee_amount`\n5. `net_amount`\n6. `fee_bps`\n7. `fee_model_notes`\n","readmeFilename":"README.md"}