@synfin/widget 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/synfin-widget.global.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,15 @@ fees. Non-custodial: it holds no keys and signs nothing.
|
|
|
8
8
|
- Docs: https://synfin.xyz/docs/sdk
|
|
9
9
|
- Status: **v0**, the surface may evolve with design partners. Pin a version.
|
|
10
10
|
|
|
11
|
+
> **What the widget shows today:** a live quote across the Canton venues with
|
|
12
|
+
> your disclosed fees (the 15 bps Synfin service fee + your integrator split).
|
|
13
|
+
> **Tradecraft is the executable venue today.** The fees are DISCLOSED for
|
|
14
|
+
> display; on-ledger fee collection is flag-gated off today
|
|
15
|
+
> (`FEE_COLLECTION_ENABLED = false`) and is wallet-dependent when it flips (see
|
|
16
|
+
> [`@synfin/client`](https://www.npmjs.com/package/@synfin/client)). The widget
|
|
17
|
+
> holds no keys and signs nothing — execution is your wallet's, via
|
|
18
|
+
> `@synfin/client`.
|
|
19
|
+
|
|
11
20
|
## Install
|
|
12
21
|
|
|
13
22
|
Two paths, pick one. Both register the same `<synfin-widget>` custom element.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @synfin/widget 0.1.
|
|
1
|
+
/*! @synfin/widget 0.1.1 | MIT | https://synfin.xyz/docs/sdk */
|
|
2
2
|
"use strict";(()=>{var W=Object.defineProperty;var D=(t,n,e)=>n in t?W(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e;var d=(t,n,e)=>D(t,typeof n!="symbol"?n+"":n,e);var p=class extends Error{constructor(e,i,s){super(s);d(this,"status");d(this,"code");this.name="SynfinApiError",this.status=e,this.code=i}};function V(t){if(t!==void 0)return t;let n=globalThis.fetch;if(n===void 0)throw new Error("no global fetch available; pass { fetch } to createClient (Node 18+ and browsers have it built in)");return n}function F(t){let n=[];for(let[e,i]of Object.entries(t))i!==void 0&&n.push(`${encodeURIComponent(e)}=${encodeURIComponent(String(i))}`);return n.length>0?`?${n.join("&")}`:""}async function S(t){let n;try{n=await t.json()}catch{let e=await t.text().catch(()=>"");throw new p(t.status,"bad_response",e.length>0?e:"non-JSON response from the Synfin API")}if(!t.ok){let e=n;throw new p(t.status,e.code??"error",e.error??`HTTP ${t.status}`)}return n}var O="https://synfin.xyz";function E(t){if(t.apiKey===void 0||t.apiKey==="")throw new Error("createClient requires an apiKey");let n={baseUrl:(t.baseUrl??O).replace(/\/+$/,""),apiKey:t.apiKey,fetch:V(t.fetch)};return{getQuote:e=>j(n,e),createPlan:e=>G(n,e)}}async function j(t,n){let e=F({from:n.from,to:n.to,amount:String(n.amount),slippageBps:n.slippageBps,feeBps:n.feeBps,feeRecipient:n.feeRecipient}),i=await t.fetch(`${t.baseUrl}/api/quote${e}`,{method:"GET",headers:{"x-api-key":t.apiKey}});return S(i)}async function G(t,n){let e={from:n.from,to:n.to,amount:String(n.amount),venueId:n.venueId,takerParty:n.takerParty,idempotencyKey:n.idempotencyKey};n.slippageBps!==void 0&&(e.slippageBps=n.slippageBps),n.feeBps!==void 0&&(e.feeBps=n.feeBps),n.feeRecipient!==void 0&&(e.feeRecipient=n.feeRecipient);let i=await t.fetch(`${t.baseUrl}/api/execute/plan`,{method:"POST",headers:{"x-api-key":t.apiKey,"content-type":"application/json"},body:JSON.stringify(e)});return S(i)}function Y(t){let n=[];for(let[e,i]of Object.entries(t))i!==void 0&&n.push(`${encodeURIComponent(e)}=${encodeURIComponent(String(i))}`);return n.length>0?`?${n.join("&")}`:""}function J(t){if(t!==void 0)return t;let n=globalThis.fetch;if(n===void 0)throw new p(0,"network","no fetch available in this runtime");return n}async function P(t,n){let e=Y({from:n.from,to:n.to,amount:String(n.amount),slippageBps:n.slippageBps,feeBps:n.feeBps,feeRecipient:n.feeRecipient}),i={};t.apiKey!==null&&t.apiKey!==""&&(i["x-api-key"]=t.apiKey);let s=await J(t.fetch)(`${t.baseUrl}/api/quote${e}`,{method:"GET",headers:i}),o;try{o=await s.json()}catch{let r=await s.text().catch(()=>"");throw new p(s.status,"bad_response",r.length>0?r:"non-JSON response from the Synfin API")}if(!s.ok){let r=o;throw new p(s.status,r.code??"error",r.error??`HTTP ${s.status}`)}return o}var y=[{symbol:"CC",name:"Canton Coin",instrumentId:"Amulet",decimals:10},{symbol:"USDCx",name:"USDC (interchain)",instrumentId:"USDCx",decimals:6},{symbol:"CBTC",name:"Canton BTC",instrumentId:"CBTC",decimals:8}];function x(t){let n=t.trim().toLowerCase();return y.find(e=>e.symbol.toLowerCase()===n)}function w(t){let n=t.trim(),e=n.toLowerCase(),i=y.find(o=>o.instrumentId.toLowerCase()===e);if(i)return i.symbol;let s=y.find(o=>o.symbol.toLowerCase()===e);return s?s.symbol:n}var X={CC:{label:"CC",hue:20},AMULET:{label:"CC",hue:20},USDCX:{label:"USDC",hue:212},CBTC:{label:"BTC",hue:33},CETH:{label:"ETH",hue:250},CUSD:{label:"USD",hue:150}};function Z(t){let n=0;for(let e=0;e<t.length;e++)n=n*31+t.charCodeAt(e)>>>0;return n%360}function R(t){let n=w(t).toUpperCase(),e=X[n]??{label:n.slice(0,3),hue:Z(n)},i=(e.hue+24)%360,s=`sfic${e.hue}`,o=e.label.length>=4?6.5:e.label.length===3?8:9.5;return`<svg class="asset__icon" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><defs><linearGradient id="${s}" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="hsl(${e.hue} 78% 58%)"></stop><stop offset="1" stop-color="hsl(${i} 72% 44%)"></stop></linearGradient></defs><circle cx="12" cy="12" r="11" fill="url(#${s})"></circle><text x="12" y="12" dy="0.35em" text-anchor="middle" font-size="${o}" font-weight="700" fill="#fff">${e.label}</text></svg>`}function A(t){let n=t.trim().toLowerCase();return n===""?y:y.filter(e=>e.symbol.toLowerCase().includes(n)||e.name.toLowerCase().includes(n))}function g(t,n=6){if(t===null)return"-";if(!/^-?\d+(\.\d+)?$/.test(t))return t;let[e="0",i=""]=t.split(".");if(i==="")return e;let s=i.slice(0,n).replace(/0+$/,"");return s===""?e:`${e}.${s}`}function ee(t,n){let e=/^\d+(\.\d+)?$/;if(!e.test(t)||!e.test(n))return t;let i=_=>{let[K="0",Q=""]=_.split(".");return[K,Q]},[s,o]=i(t),[r,a]=i(n),l=Math.max(o.length,a.length),u=(BigInt(s+o.padEnd(l,"0"))+BigInt(r+a.padEnd(l,"0"))).toString().padStart(l+1,"0"),h=u.slice(0,u.length-l),m=l>0?u.slice(u.length-l):"";return m===""?h:`${h}.${m}`}function B(t){return{service:{label:"Synfin service",bps:t.service.bps,amount:t.service.amount},integrator:t.integrator===null?null:{label:"Integrator fee",bps:t.integrator.bps,amount:t.integrator.amount,partnerShare:t.integrator.partnerShare,synfinShare:t.integrator.synfinShare},userReceives:t.userReceives,total:t.integrator===null?t.service.amount:ee(t.service.amount,t.integrator.amount)}}var I=100,te=15e3;function C(t){let n=[],e=(t.from??"CC").trim(),i=(t.to??"USDCx").trim();x(e)===void 0&&n.push({field:"from",message:`unknown asset "${e}"`}),x(i)===void 0&&n.push({field:"to",message:`unknown asset "${i}"`}),e.toLowerCase()===i.toLowerCase()&&n.push({field:"to",message:"from and to must differ"});let s=(t.amount??"100").trim();(!/^\d+(\.\d+)?$/.test(s)||Number(s)<=0)&&n.push({field:"amount",message:"amount must be a positive number"});let o=null,r=null;if(t.feeBps!==void 0||t.feeRecipient!==void 0)if(t.feeBps===void 0||t.feeRecipient===void 0)n.push({field:"fee",message:"feeBps and feeRecipient must be set together"});else{let m=Number(t.feeBps);!Number.isInteger(m)||m<0||m>I?n.push({field:"feeBps",message:`feeBps must be an integer 0 to ${I}`}):o=m;let _=String(t.feeRecipient).trim();_===""?n.push({field:"feeRecipient",message:"feeRecipient required"}):r=_}let l=t.appearance==="light"?"light":"dark",f=(t.baseUrl??"https://synfin.xyz").replace(/\/+$/,""),u=typeof t.refreshMs=="number"&&t.refreshMs>=3e3?t.refreshMs:te,h=(t.apiKey??"").trim();return{config:{apiKey:h===""?null:h,feeBps:o,feeRecipient:r,from:e,to:i,amount:s,appearance:l,baseUrl:f,refreshMs:u,showFeeBreakdown:t.showFeeBreakdown===!0,showAttribution:t.showAttribution!==!1},issues:n}}var v={quote:"synfin:quote",asset:"synfin:asset",venue:"synfin:venue",plan:"synfin:plan",status:"synfin:status",error:"synfin:error"};function b(t,n,e){t.dispatchEvent(new CustomEvent(n,{detail:e,bubbles:!0,composed:!0}))}function $(t,n){let e=t.venues.filter(i=>i.available);return e.find(i=>i.venueId===n)??t.best??e[0]??null}function c(t){return t.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n]??n)}function z(t){return t.charAt(0).toUpperCase()+t.slice(1)}function N(t,n,e=null,i=null){switch(t.kind){case"idle":return"";case"loading":return ne();case"invalid":return L("!",t.title,c(t.message),"");case"error":return L("!","Could not load a quote",c(t.message),"error");case"no-route":return L("\u2205","No route right now",`No venue can fill ${c(t.pair.give)} to ${c(t.pair.want)} at this size. Try a different amount or pair.`,"");case"quoted":return ie(t,n,e,i)}}function ne(){return`<div class="quote" aria-busy="true" aria-label="Loading a quote">
|
|
3
3
|
<div class="skel skel-big"></div>
|
|
4
4
|
<div class="skel skel-row"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synfin/widget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The Synfin widget: an embeddable, framework-agnostic quote-and-fee widget (a <synfin-widget> custom element, plus a React wrapper) built on @synfin/client. Live best-execution quotes across Canton venues with the partner's disclosed fees. Non-custodial: it never holds keys.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"test": "vitest run"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@synfin/client": "^0.1.
|
|
62
|
+
"@synfin/client": "^0.1.1"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"react": ">=18"
|