Skip to content

Commit 8718d6e

Browse files
victhorbiLuca Bandini
andauthored
feat: switch fiat onramp to Transak (native VET support) (#649)
* feat: add fiat and crypto subscription payment components - Add useBuyCrypto, useFiatCheckout, useSubscription, useSubscriptionCheckout hooks - Add FiatCheckoutModal, PayWithFiatButton, SubscribeButton, SubscriptionCheckoutModal components - Add FiatOnramp content in AccountModal - Add subscription demo in PaymentsDemo example - Add crypto payment method to SubscriptionCheckout (VET/ERC20) - Extend SubscriptionPlan type with optional cryptoPayment field - Add i18n translation keys for fiat/crypto payments - Fix Privy v3 compatibility (optional clientId, cross-app-connect deps) - Mock fallback for useSubscription when API base URL not configured - Add Solana deps to root workspace (Privy v3 transitive) * feat: switch fiat onramp from Privy/Stripe to Transak (native VET support) BREAKS: Replaces useBuyCrypto, useFiatCheckout, FiatCheckoutModal, PayWithFiatButton, FiatOnrampContent with Transak equivalents. Adds: - useTransakCheckout hook (dual-mode widget URL: apiKey-only for sandbox, widgetUrlBuilder for production) - TransakCheckoutModal, PayWithTransakButton components - TransakOnrampContent in AccountModal - @transak/ui-js-sdk dependency - transak config on VeChainKitProvider - Subscription fiat path opens Transak to fund, then creates sub Removes: - Privy useAddFunds / useBuyCrypto dependency - @stripe/crypto peer dep - All Privy/Stripe-specific translations * fix: keep Transak modal open on success + remove dead code in subscribe - PayWithTransakButton: isOpen stays true on 'success' so the success screen is visible; only closes when user dismisses - useSubscriptionCheckout: removed unreachable createSubscription fallthrough (was only reachable for crypto-without-cryptoPayment, an impossible UI state); replaced with a clear error * fix: auto-hide 'Buy' quick action when transak.apiKey is not configured Without this, the Buy button rendered unconditionally and only threw 'Transak is not configured' after the user filled the form and clicked Continue. Now it stays hidden unless the developer passes a transak config to VeChainKitProvider. * feat: gate 'Pay with Card' on transak.apiKey presence When the developer does not pass a Transak API key to VeChainKitProvider, kit-internal UI no longer surfaces fiat-only options: - useSubscriptionCheckout: derives hasFiat from config; default paymentMethod for non-crypto plans is 'crypto' when fiat is unavailable - SubscriptionCheckoutModal: 'Pay with Card' tab hidden unless hasFiat; plans with neither crypto nor fiat show an info note instead of the Subscribe button - en.json: 'No payment method available for this plan.' key * feat: require Transak Secure Widget URL flow Transak deprecated direct widget URLs (apiKey in the query string); widgets now only load from a sessionId-based URL minted by the Create Widget URL API (POST /api/v2/auth/session), called from the partner backend with the API secret. - TransakConfig.widgetUrlBuilder is now required; apiKey optional - useTransakCheckout: removed buildDirectUrl fallback, errors clearly when widgetUrlBuilder is missing - hasFiat / Buy quick-action gating now checks widgetUrlBuilder - example: /api/transak/widget-url route does refresh-token -> create-widget-url with x-user-ip; wrapper wires widgetUrlBuilder - .env.example: TRANSAK_API_KEY / TRANSAK_API_SECRET server vars * fix: embed Transak widget in host modal to stop focus flicker The Transak SDK's default behavior appends its own full-screen overlay to document.body, outside the Chakra modal. Chakra's focus trap then detects focus escaping the modal and pulls it back whenever the user clicks into Transak's inputs, causing the email field to constantly lose focus. - useTransakCheckout: pass containerId so the widget renders as an iframe inside the host modal; expose TRANSAK_WIDGET_CONTAINER_ID; replace the SDK's close() with cleanup() (which actually removes the iframe in container mode) and clear the container on open/close/unmount - TransakCheckoutModal: render the embed container during processing and disable the modal focus trap (allowExternalFocus) while the widget is active * fix: lower demo amount to Transak minimum and fix widget scrollbars - Demo/button/hook/modal defaults changed from $50 to $20 (Transak's minimum card order), so sandbox testing is cheaper - TransakCheckoutModal: widget container height is now viewport-aware (calc(100vh - 240px), 420-620px) and mobile uses a near-fullscreen bottom sheet, so the widget's own scroll is the only scrollbar instead of a double scrollbar (modal + iframe) * fix: lower default Transak amount to $10 minimum Transak's minimum order with light KYC is $10; the demo and component defaults now use it instead of $20. * fix: theme standalone Transak/subscription modals and fix cross-app-connect Privy config * feat: auto-derive Transak environment from connected network * docs: add Transak on-ramp backend setup guide * chore: remove half-implemented subscription flow, revert Privy to v2, restore typecheck gate - Remove useSubscription, useSubscriptionCheckout, SubscriptionModal, SubscriptionCheckoutModal, SubscribeButton and stripe-subscriptions docs (full signed-typed-message subscription flow lands in a follow-up PR) - Revert @privy-io/react-auth to 2.25.0 and @privy-io/cross-app-provider to ^0.3.4 in kit and cross-app-connect; drop root Solana deps; restore v2 provider shapes (Privy v3 bump deferred to its own PR) - Restore tsc --noEmit gate in kit build and add Typecheck step to CI - Remove subscription-only i18n keys * fix: address CodeRabbit findings on Transak checkout and reference route - Add 10s timeouts to outbound Transak API calls and an in-memory rate limit on the widget-url route (unauthenticated minting protection) - Guard instanceRef assignment with the generation counter so a stale widget never overwrites the active instance - Validate walletAddress with isAddress before building the widget URL - Return to the form step when the Transak widget closes without success - Fix docs: fence language and valid JSON request example * feat(next-template): allow overriding the Transak mini-server URL via NEXT_PUBLIC_TRANSAK_API_URL * feat(homepage): wire Transak onramp + pass env vars to preview deploy - Add transak prop to homepage VechainKitProviderWrapper (same pattern as next-template): Buy VET button appears in AccountModal when NEXT_PUBLIC_TRANSAK_API_KEY is set, calling the mini-server at NEXT_PUBLIC_TRANSAK_API_URL - Pass NEXT_PUBLIC_TRANSAK_API_KEY and NEXT_PUBLIC_TRANSAK_API_URL through deploy-preview.yaml so the homepage preview build inlines them - Document both vars in examples/homepage/.env.example * chore: trigger preview redeploy with Transak env vars * feat: wire Transak environment + add mandatory integration requirements docs - Both providers (homepage + next-template) pass NEXT_PUBLIC_TRANSAK_ENVIRONMENT in the fetch body (not as top-level config prop) to the mini-server - deploy-preview.yaml: NEXT_PUBLIC_TRANSAK_ENVIRONMENT='staging' - deploy-cloudfront.yaml: NEXT_PUBLIC_TRANSAK_ENVIRONMENT='production' - docs/recipes/transak-onramp.md: section 6 with credential isolation, x-api-key, x-user-ip, backend IP whitelisting, CORS, rate limiting, partner onboarding checklist; env vars table updated * ci: split Transak API key secret per environment - deploy-preview uses NEXT_PUBLIC_TRANSAK_API_KEY_STAGING - deploy-cloudfront uses NEXT_PUBLIC_TRANSAK_API_KEY_PROD Keeps the prod site inert (Buy hidden) until the production key exists. Re-applies 808f04a, lost when #653 was folded into this branch. * fix: harden rate-limit IP resolution + guard stale generation in transak checkout catch - widget-url route: resolveClientIp prefers x-real-ip (written by trusted proxies, unspoofable from the client) over the leftmost x-forwarded-for entry; falls back to 'unknown' bucket when no public IP is available so attackers cannot trivially rotate headers to bypass the rate limit. - useTransakCheckout open(): guard the catch block with genRef.current !== gen so a superseded generation does not overwrite the active generation's error/status (matches the guard already used before instance assignment). --------- Co-authored-by: Luca Bandini <luca.bandini@vechain.org>
1 parent 37b39a9 commit 8718d6e

33 files changed

Lines changed: 1448 additions & 65 deletions

File tree

‎.github/workflows/deploy-cloudfront.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ jobs:
2828
NEXT_PUBLIC_PRIVY_APP_ID: ${{ secrets.NEXT_PUBLIC_PRIVY_APP_ID }}
2929
NEXT_PUBLIC_PRIVY_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_PRIVY_CLIENT_ID }}
3030
NEXT_PUBLIC_DELEGATOR_URL: ${{ secrets.NEXT_PUBLIC_DELEGATOR_URL }}
31+
NEXT_PUBLIC_TRANSAK_API_KEY: ${{ secrets.NEXT_PUBLIC_TRANSAK_API_KEY_PROD }}
32+
NEXT_PUBLIC_TRANSAK_API_URL: ${{ secrets.NEXT_PUBLIC_TRANSAK_API_URL }}
33+
NEXT_PUBLIC_TRANSAK_ENVIRONMENT: 'production'
3134
NEXT_PUBLIC_NETWORK_TYPE: 'main'
3235
AWS_REGION: eu-west-1
3336
steps:

‎.github/workflows/deploy-preview.yaml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ jobs:
6969
NEXT_PUBLIC_PRIVY_APP_ID: ${{ secrets.NEXT_PUBLIC_PRIVY_APP_ID }}
7070
NEXT_PUBLIC_PRIVY_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_PRIVY_CLIENT_ID }}
7171
NEXT_PUBLIC_DELEGATOR_URL: ${{ secrets.NEXT_PUBLIC_DELEGATOR_URL }}
72-
NEXT_PUBLIC_TRANSAK_API_KEY: ${{ secrets.NEXT_PUBLIC_TRANSAK_API_KEY }}
72+
NEXT_PUBLIC_TRANSAK_API_KEY: ${{ secrets.NEXT_PUBLIC_TRANSAK_API_KEY_STAGING }}
7373
NEXT_PUBLIC_TRANSAK_API_URL: ${{ secrets.NEXT_PUBLIC_TRANSAK_API_URL }}
74+
NEXT_PUBLIC_TRANSAK_ENVIRONMENT: 'staging'
7475
NEXT_PUBLIC_NETWORK_TYPE: 'main'
7576
AWS_REGION: eu-west-1
7677
BRANCH_NAME: ${{ github.event.pull_request.head.ref }}

‎.github/workflows/lint-build-test.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ jobs:
6464
- name: Install
6565
run: yarn && yarn install:all
6666

67+
- name: Typecheck
68+
run: yarn kit:typecheck
69+
6770
- name: Build
6871
run: yarn build
6972

‎docs/recipes/transak-onramp.md‎

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Transak On-Ramp Backend API
2+
3+
This document describes the backend required by vechain-kit's fiat on-ramp feature (`PayWithTransakButton`, `TransakCheckoutModal`).
4+
5+
## Why a backend is required
6+
7+
Transak deprecated direct widget URLs (API key in the query string). Widgets now only load from a **Secure Widget URL** minted by Transak's Create Widget URL API, which is authenticated with your **API secret**. That secret must never be exposed in the browser, so a small server endpoint is required.
8+
9+
The flow is:
10+
11+
```text
12+
Browser (vechain-kit) Your backend Transak
13+
┌──────────────────┐ POST ┌──────────────────┐ POST ┌──────────────────┐
14+
│ widgetUrlBuilder │ ───────► │ /api/transak/ │ ──────► │ /api/v2/ │
15+
│ (kit passes │ │ widget-url │ ①token │ auth/session │
16+
│ walletAddress, │ │ │ │ │
17+
│ fiat, env...) │ │ ② POST widget │ ◄────── │ returns │
18+
│ │ │ (server-to- │ widget │ secure widget │
19+
│ │ ◄─────── │ server) │ URL │ URL (5 min TTL) │
20+
└──────────────────┘ widget └──────────────────┘ └──────────────────┘
21+
URL returned ▲
22+
└─► Transak SDK loads │ ① access token via POST /partners/api/v2/refresh-token
23+
│ (7-day validity, cache it)
24+
```
25+
26+
## 1. Create Transak API credentials
27+
28+
1. Go to the [Transak Partner Dashboard](https://dashboard.transak.com) and create a partner account.
29+
2. Generate an **API key** and **API secret**. Credentials are environment-specific:
30+
- **Sandbox** credentials (for testing) — work against the `staging` endpoints.
31+
- **Production** credentials — work against the `production` endpoints.
32+
3. Add the `referrerDomain` of your app (the domain the widget will be served from) as an allowed referrer, otherwise session creation fails with `403`.
33+
4. Transak requires the end user's real IP on its authenticated APIs (`x-user-ip` header) — your server must forward the caller's IP.
34+
35+
## 2. Server and client environment variables
36+
37+
| Variable | Scope | Description |
38+
| --- | --- | --- |
39+
| `TRANSAK_API_KEY` | Server only | Partner API key. Never in the browser bundle. |
40+
| `TRANSAK_API_SECRET` | Server only | Partner API secret. Keep it on the backend only. |
41+
| `NEXT_PUBLIC_TRANSAK_API_KEY` | Client | Same API key, safe to expose (works only with the server-side secret). |
42+
| `NEXT_PUBLIC_TRANSAK_API_URL` | Client | Base URL of your mini-server (leave empty for same-origin). |
43+
| `NEXT_PUBLIC_TRANSAK_ENVIRONMENT` | Client | `'staging'` or `'production'`. Overrides the kit's auto-derived value. Set to `'staging'` for preview deployments and `'production'` for live. |
44+
45+
## 3. Endpoint contract
46+
47+
### `POST /api/transak/widget-url`
48+
49+
**Request:**
50+
```json
51+
{
52+
"environment": "staging",
53+
"widgetParams": {
54+
"apiKey": "your_transak_api_key",
55+
"referrerDomain": "https://yourapp.com",
56+
"walletAddress": "0x...",
57+
"fiatAmount": "10",
58+
"fiatCurrency": "USD",
59+
"cryptoCurrencyCode": "VET",
60+
"network": "vechain",
61+
"defaultCryptoCurrency": "VET",
62+
"disableWalletAddressForm": true
63+
}
64+
}
65+
```
66+
67+
| Field | Description |
68+
| --- | --- |
69+
| `environment` | Which Transak environment to use. vechain-kit derives it automatically from the connected VeChain network (`main` → `production`, `test`/`solo` → `staging`) unless overridden via `TransakConfig.environment` on `VeChainKitProvider`. Your endpoint should trust this value and select the matching Transak base URLs. |
70+
| `widgetParams` | Transak widget configuration, see the [Transak query parameters docs](https://docs.transak.com/customization/query-parameters). |
71+
72+
**Server behavior:**
73+
74+
1. Obtain a partner access token via `POST https://api-stg.transak.com/partners/api/v2/refresh-token` (staging) or `POST https://api.transak.com/partners/api/v2/refresh-token` (production), with headers `x-api-key` and `api-secret` and body `{ "apiKey": ... }`. The token is valid for **7 days** — cache it and reuse it. Cache per environment; a staging token must never be sent to production endpoints.
75+
2. Mint the widget session via `POST https://api-gateway-stg.transak.com/api/v2/auth/session` (staging) or `POST https://api-gateway.transak.com/api/v2/auth/session` (production), with headers `x-api-key`, `access-token` and `x-user-ip` (the caller's real IP, e.g. from `x-forwarded-for`), and body `{ "widgetParams": ... }`.
76+
3. Return Transak's response.
77+
78+
**Response (200):**
79+
```json
80+
{
81+
"data": {
82+
"widgetUrl": "https://global-stg.transak.com/...?sessionId=..."
83+
}
84+
}
85+
```
86+
87+
The widget URL is valid for **5 minutes** and single-use — mint a fresh one per checkout.
88+
89+
## 4. Wire it into vechain-kit
90+
91+
```tsx
92+
<VeChainKitProvider
93+
transak={{
94+
apiKey: process.env.NEXT_PUBLIC_TRANSAK_API_KEY,
95+
widgetUrlBuilder: async ({
96+
walletAddress,
97+
fiatAmount,
98+
fiatCurrency,
99+
cryptoCurrency,
100+
network,
101+
}) => {
102+
const res = await fetch('/api/transak/widget-url', {
103+
method: 'POST',
104+
headers: { 'Content-Type': 'application/json' },
105+
body: JSON.stringify({
106+
environment: process.env.NEXT_PUBLIC_TRANSAK_ENVIRONMENT as
107+
| 'staging'
108+
| 'production'
109+
| undefined,
110+
widgetParams: {
111+
apiKey: process.env.NEXT_PUBLIC_TRANSAK_API_KEY,
112+
referrerDomain: window.location.origin,
113+
walletAddress,
114+
fiatAmount,
115+
fiatCurrency,
116+
cryptoCurrencyCode: cryptoCurrency,
117+
network,
118+
defaultCryptoCurrency: 'VET',
119+
disableWalletAddressForm: true,
120+
},
121+
}),
122+
});
123+
const json = await res.json();
124+
if (!res.ok) throw new Error(json?.error ?? 'Failed to create Transak widget URL');
125+
return json.data.widgetUrl;
126+
},
127+
}}
128+
>
129+
```
130+
131+
The `environment` parameter is passed through to your `widgetUrlBuilder` — your backend uses it to select the correct Transak endpoints. Set `transak.environment` explicitly (e.g. `NEXT_PUBLIC_TRANSAK_ENVIRONMENT='staging'` for previews, `'production'` for live) when you want to force the value regardless of the connected VeChain network. Omit it to let the kit auto-derive (`main` → `production`, `test`/`solo` → `staging`).
132+
133+
## 5. Reference implementation
134+
135+
A complete, working Next.js implementation ships in the repo:
136+
137+
- Route: `examples/next-template/src/app/api/transak/widget-url/route.ts`
138+
- Provider wiring: `examples/next-template/src/app/providers/VechainKitProviderWrapper.tsx`
139+
- Env vars: `examples/next-template/.env.example`
140+
141+
## 6. Mandatory Transak integration requirements
142+
143+
These are **architectural prerequisites** for any production deployment of the on-ramp feature, regardless of the backend framework you choose. Transak enforces them server-side; missing any of them results in `403` / `401` errors from the Transak API.
144+
145+
### 6.1 Credential isolation
146+
147+
| Property | Value | Where |
148+
| --- | --- | --- |
149+
| `TRANSAK_API_KEY` | Partner API key | Server env only — never in the browser bundle |
150+
| `TRANSAK_API_SECRET` | Partner API secret | Server env only — never sent to the client under any circumstance |
151+
| `NEXT_PUBLIC_TRANSAK_API_KEY` | Same API key, safe to expose | Client bundle (used by the kit to pass through to your backend) |
152+
153+
The **API key** is safe to ship in the client bundle — it only works together with the **API secret**, which must stay server-side. The kit never needs the secret.
154+
155+
### 6.2 `x-api-key` header (server-to-Transak only)
156+
157+
Transak requires `x-api-key` on every authenticated API call (`refresh-token` and `auth/session`). Set it from `TRANSAK_API_KEY` **on the backend**, never from a client-supplied value. The `apiKey` in `widgetParams` is the partner-config value for the widget session, not the authentication key — do not conflate them.
158+
159+
### 6.3 `x-user-ip` header (forward the real caller IP)
160+
161+
Transak needs the end user's real IP for fraud detection and geo-compliance. Your backend **must** forward it as `x-user-ip` on the `auth/session` call. Use the leftmost public IP from:
162+
163+
```
164+
x-forwarded-for: 203.0.113.42, 10.0.0.1
165+
```
166+
167+
Do not send your server's own IP — Transak will reject shared/NAT IPs in production. If you run behind a CDN or proxy, ensure the chain preserves the original client IP (e.g. CloudFront → `X-Forwarded-For`, ALB → `X-Forwarded-For`).
168+
169+
### 6.4 Backend IP whitelisting
170+
171+
Transak's production API can be locked to a set of **whitelisted source IPs** (configured in the Partner Dashboard under *API Settings → IP Whitelisting*). Your backend must have a **fixed egress IP** (or a small known range). This is mandatory for production — staging does not enforce it.
172+
173+
Checklist:
174+
175+
- [ ] Deploy the backend on infrastructure with a static NAT / elastic IP (Lambda behind API Gateway, a fixed-IP container, or a VPS with a static IP)
176+
- [ ] Add every backend egress IP to the Transak IP whitelist in the Partner Dashboard
177+
- [ ] If you use a serverless platform with rotating IPs (e.g. Vercel functions without a NAT gateway), put a proxy with a fixed IP in front, or move the endpoint to infra that provides one
178+
179+
### 6.5 CORS — restrict to your domains only
180+
181+
Your `/api/transak/widget-url` endpoint must set CORS headers that allow **only your own origins**:
182+
183+
```http
184+
Access-Control-Allow-Origin: https://yourapp.com
185+
Access-Control-Allow-Methods: POST
186+
Access-Control-Allow-Headers: Content-Type
187+
```
188+
189+
Never use `Access-Control-Allow-Origin: *` — any website could then mint Transak sessions on your billing account. For multiple environments, maintain an explicit allow-list:
190+
191+
```js
192+
const ALLOWED_ORIGINS = new Set([
193+
'https://yourapp.com',
194+
'https://preview.vechainkit.vechain.org',
195+
]);
196+
const origin = req.headers.get('origin');
197+
if (ALLOWED_ORIGINS.has(origin)) {
198+
res.headers.set('Access-Control-Allow-Origin', origin);
199+
}
200+
```
201+
202+
The `referrerDomain` sent in `widgetParams` must also match one of the domains registered in your Transak Partner Dashboard (see step 3 in section 1 above). Transak checks it server-side; a mismatch yields `403`.
203+
204+
### 6.6 Rate limiting
205+
206+
Your endpoint is unauthenticated from the client's perspective — protect it with an in-memory or distributed rate limit so a single caller cannot mint unlimited Transak sessions against your credentials. The reference implementation in the repo uses a simple in-memory cap (20 requests/minute/IP). For horizontally-scaled backends, use a shared store (Redis, DynamoDB, etc.).
207+
208+
### 6.7 Partner onboarding checklist
209+
210+
Before going live, confirm every item in the Transak Partner Dashboard:
211+
212+
- [ ] Production API key + secret generated (not the sandbox ones)
213+
- [ ] All frontend domains added to **Allowed Referrer Domains** (production + any preview subdomains)
214+
- [ ] All backend egress IPs added to **IP Whitelisting** (production only)
215+
- [ ] KYC/AML settings configured (required countries, default fiat currency, default crypto)
216+
- [ ] Wallet address validation enabled (`disableWalletAddressForm: true` — the kit passes the connected wallet address directly; do not let users type an arbitrary address)
217+
- [ ] Webhook URL configured (for order status callbacks — not handled by the kit, must be on your backend)
218+
- [ ] Test purchase completed end-to-end on staging before switching to production credentials

‎examples/homepage/.env.example‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
66
NEXT_PUBLIC_DELEGATOR_URL=
77
# Network Configuration -- main | test | solo
88
NEXT_PUBLIC_NETWORK_TYPE=
9+
# Transak onramp -- staging key from dashboard.transak.com (leave empty to hide the Buy button)
10+
NEXT_PUBLIC_TRANSAK_API_KEY=
11+
# Mini-server base URL that mints the Secure Widget URL (leave empty to use the same origin)
12+
NEXT_PUBLIC_TRANSAK_API_URL=
913

1014
#For translations
1115
OPENAI_API_KEY=

‎examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,62 @@ export function VechainKitProviderWrapper({ children }: Props) {
202202
// nodeUrl: 'http://localhost:8669',
203203
}}
204204
allowCustomTokens={true}
205+
transak={
206+
process.env.NEXT_PUBLIC_TRANSAK_API_KEY
207+
? {
208+
apiKey: process.env.NEXT_PUBLIC_TRANSAK_API_KEY,
209+
widgetUrlBuilder: async ({
210+
walletAddress,
211+
fiatAmount,
212+
fiatCurrency,
213+
cryptoCurrency,
214+
network,
215+
}) => {
216+
const apiUrl =
217+
process.env.NEXT_PUBLIC_TRANSAK_API_URL ?? '';
218+
const res = await fetch(
219+
`${apiUrl}/api/transak/widget-url`,
220+
{
221+
method: 'POST',
222+
headers: {
223+
'Content-Type': 'application/json',
224+
},
225+
body: JSON.stringify({
226+
environment:
227+
process.env
228+
.NEXT_PUBLIC_TRANSAK_ENVIRONMENT as
229+
| 'staging'
230+
| 'production'
231+
| undefined,
232+
widgetParams: {
233+
apiKey: process.env.NEXT_PUBLIC_TRANSAK_API_KEY,
234+
referrerDomain:
235+
typeof window !== 'undefined'
236+
? window.location.origin
237+
: '',
238+
walletAddress,
239+
fiatAmount,
240+
fiatCurrency,
241+
cryptoCurrencyCode: cryptoCurrency,
242+
network,
243+
defaultCryptoCurrency: 'VET',
244+
disableWalletAddressForm: true,
245+
},
246+
}),
247+
},
248+
);
249+
const json = await res.json();
250+
if (!res.ok) {
251+
throw new Error(
252+
json?.error ??
253+
'Failed to create Transak widget URL',
254+
);
255+
}
256+
return json.data.widgetUrl as string;
257+
},
258+
}
259+
: undefined
260+
}
205261
>
206262
<LanguageSync>{children}</LanguageSync>
207263
</VeChainKitProvider>

‎examples/next-template/.env.example‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@ NEXT_PUBLIC_PRIVY_CLIENT_ID=
55
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
66
NEXT_PUBLIC_DELEGATOR_URL=
77
# Network Configuration -- main | test | solo
8-
NEXT_PUBLIC_NETWORK_TYPE=
8+
NEXT_PUBLIC_NETWORK_TYPE=
9+
# Transak onramp -- staging key from dashboard.transak.com (leave empty to disable)
10+
NEXT_PUBLIC_TRANSAK_API_KEY=
11+
# Mini-server base URL -- where /api/transak/widget-url lives. Leave empty to
12+
# use the same origin (e.g. https://my-preview.example.com in previews).
13+
NEXT_PUBLIC_TRANSAK_API_URL=
14+
# Transak backend credentials -- used by /api/transak/widget-url to mint a Secure Widget URL
15+
TRANSAK_API_KEY=
16+
TRANSAK_API_SECRET=

0 commit comments

Comments
 (0)