Skip to content

Commit 5eb3818

Browse files
authored
feat: enable custom fee address and fee amount (#140)
1 parent c26d150 commit 5eb3818

File tree

4 files changed

+214
-55
lines changed

4 files changed

+214
-55
lines changed

packages/payment-widget/src/lib/components/payment-confirmation.svelte

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
} from "../utils/request";
2121
import Spinner from "./spinner.svelte";
2222
import WalletInfo from "./wallet-info.svelte";
23+
import { ethers } from "ethers";
2324
2425
export let selectedCurrency: Currency;
2526
export let amountInUSD: number;
@@ -36,6 +37,8 @@
3637
export let onPaymentSuccess: (request: any) => void;
3738
export let onPaymentError: (error: string) => void;
3839
export let invoiceNumber: string | undefined;
40+
export let feeAddress: string;
41+
export let feeAmountInUSD: number;
3942
4043
const COUNTDOWN_INTERVAL = 30;
4144
@@ -44,9 +47,11 @@
4447
let intervalId: NodeJS.Timeout;
4548
let exchangeRate: number = 0;
4649
let error: string = "";
50+
let feeAmountInCrypto: number = 0;
4751
4852
$: isLoadingPrice = true;
4953
$: isPaying = false;
54+
$: totalPayment = amountInCrypto + feeAmountInCrypto;
5055
5156
const currencySymbol = selectedCurrency.symbol.includes(
5257
selectedCurrency.network
@@ -72,6 +77,7 @@
7277
const rate = data.data.rates[lookupSymbol];
7378
exchangeRate = parseFloat(rate);
7479
amountInCrypto = amountInUSD * exchangeRate;
80+
feeAmountInCrypto = feeAmountInUSD * exchangeRate;
7581
} catch (error) {
7682
alert("Unable to fetch exchange rate. Please try again later");
7783
} finally {
@@ -145,29 +151,58 @@
145151
>
146152
</div>
147153
</div>
148-
<div class="payment-confirmation-tab payment-confirmation-seller-address">
154+
<div class="payment-confirmation-tab payment-confirmation-address">
149155
<h4>Payment to</h4>
150-
<a
151-
href={getExplorerUrl(selectedCurrency.network, sellerAddress)}
152-
target="_blank"
153-
>
154-
<span>{sellerAddress}</span>
155-
</a>
156-
<button
157-
on:click={() => {
158-
navigator.clipboard.writeText(sellerAddress);
159-
}}
160-
>
161-
<CopyIcon />
162-
</button>
156+
<div class="address-container">
157+
<a
158+
href={getExplorerUrl(selectedCurrency.network, sellerAddress)}
159+
target="_blank"
160+
>
161+
<span>{sellerAddress}</span>
162+
</a>
163+
<button
164+
on:click={() => {
165+
navigator.clipboard.writeText(sellerAddress);
166+
}}
167+
>
168+
<CopyIcon />
169+
</button>
170+
</div>
163171
</div>
172+
{#if feeAddress !== ethers.constants.AddressZero && feeAmountInUSD > 0}
173+
<div class="payment-confirmation-tab payment-confirmation-address">
174+
<h4>Fee to</h4>
175+
<div class="address-container">
176+
<a
177+
href={getExplorerUrl(selectedCurrency.network, feeAddress)}
178+
target="_blank"
179+
>
180+
<span>{feeAddress}</span>
181+
</a>
182+
<button
183+
on:click={() => {
184+
navigator.clipboard.writeText(feeAddress);
185+
}}
186+
>
187+
<CopyIcon />
188+
</button>
189+
</div>
190+
</div>
191+
<div class="payment-confirmation-tab">
192+
<h4>Fee Amount</h4>
193+
<span>
194+
${feeAmountInUSD} USD / {trimTrailingDecimalZeros(feeAmountInCrypto)}
195+
{currencySymbol}
196+
</span>
197+
</div>
198+
{/if}
164199
<div class="payment-confirmation-tab">
165200
<h4>Payment network</h4>
166201
<span>{NETWORK_LABEL[selectedCurrency.network]}</span>
167202
</div>
168203
<div class="payment-confirmation-tab">
169204
<h4>Total</h4>
170-
<span>{trimTrailingDecimalZeros(amountInCrypto)} {currencySymbol}</span>
205+
<span>{trimTrailingDecimalZeros(totalPayment)} {currencySymbol}</span>
171206
</div>
172207

173208
{#if !isPaying}
@@ -216,11 +251,15 @@
216251
try {
217252
const requestParameters = prepareRequestParameters({
218253
currency: selectedCurrency,
254+
feeAddress,
255+
feeAmountInUSD,
256+
feeAmountInCrypto,
219257
productInfo,
220258
sellerInfo,
221259
buyerInfo,
222260
payerAddress,
223261
amountInCrypto,
262+
totalAmountInCrypto: totalPayment,
224263
exchangeRate,
225264
amountInUSD,
226265
builderId,
@@ -286,23 +325,6 @@
286325
width: 100%;
287326
gap: 16px;
288327
289-
.payment-confirmation-seller-address {
290-
display: flex;
291-
align-items: center;
292-
gap: 2px;
293-
font-size: 12px;
294-
295-
button {
296-
background: none;
297-
border: none;
298-
padding: 0;
299-
margin: 0;
300-
cursor: pointer;
301-
display: inline-flex;
302-
align-items: center;
303-
justify-content: center;
304-
}
305-
}
306328
&-amount-info {
307329
display: flex;
308330
align-items: center;
@@ -351,6 +373,49 @@
351373
font-weight: 500;
352374
font-size: 14px;
353375
}
376+
377+
&.payment-confirmation-address {
378+
flex-direction: column;
379+
align-items: flex-start;
380+
gap: 8px;
381+
382+
h4 {
383+
margin: 0;
384+
}
385+
386+
.address-container {
387+
display: flex;
388+
align-items: center;
389+
gap: 8px;
390+
width: 100%;
391+
392+
a {
393+
flex-grow: 1;
394+
text-decoration: none;
395+
color: inherit;
396+
font-size: 14px;
397+
398+
span {
399+
display: inline-block;
400+
width: 100%;
401+
overflow: hidden;
402+
text-overflow: ellipsis;
403+
white-space: nowrap;
404+
}
405+
}
406+
407+
button {
408+
background: none;
409+
border: none;
410+
padding: 0;
411+
margin: 0;
412+
cursor: pointer;
413+
display: flex;
414+
align-items: center;
415+
justify-content: center;
416+
}
417+
}
418+
}
354419
}
355420
356421
&-warning {

packages/payment-widget/src/lib/payment-widget.svelte

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
<svelte:options customElement="payment-widget" />
22

33
<script lang="ts">
4-
import { Button } from "@requestnetwork/shared-components/button";
54
import Modal from "@requestnetwork/shared-components/modal.svelte";
5+
import PoweredBy from "@requestnetwork/shared-components/powered-by.svelte";
66
import type { EventsControllerState } from "@web3modal/core";
77
import type { Web3Modal } from "@web3modal/ethers5";
8+
import { ethers } from "ethers";
89
import { onDestroy, onMount } from "svelte";
10+
import BuyerInfoForm from "./components/buyer-info-form.svelte";
911
import CurrencySelector from "./components/currency-selector.svelte";
1012
import PaymentComplete from "./components/payment-complete.svelte";
1113
import PaymentConfirmation from "./components/payment-confirmation.svelte";
12-
import PoweredBy from "@requestnetwork/shared-components/powered-by.svelte";
1314
import type {
1415
AmountInUSD,
1516
BuyerInfo,
@@ -21,7 +22,6 @@
2122
} from "./types";
2223
import { getSupportedCurrencies } from "./utils/currencies";
2324
import { initWalletConnector } from "./utils/walletConnector";
24-
import BuyerInfoForm from "./components/buyer-info-form.svelte";
2525
2626
// Props
2727
export let sellerInfo: SellerInfo;
@@ -37,6 +37,8 @@
3737
export let buyerInfo: BuyerInfo | undefined = undefined;
3838
export let enableBuyerInfo: boolean = true;
3939
export let invoiceNumber: string | undefined = undefined;
40+
export let feeAddress: string = ethers.constants.AddressZero;
41+
export let feeAmountInUSD: number = 0;
4042
4143
// State
4244
let web3Modal: Web3Modal | null = null;
@@ -193,7 +195,7 @@
193195

194196
<section class="rn-payment-widget-body">
195197
<h2>Pay with crypto</h2>
196-
<Button
198+
<button
197199
disabled={!amountInUSD ||
198200
!sellerAddress ||
199201
amountInUSD === 0 ||
@@ -204,7 +206,7 @@
204206
} else {
205207
isModalOpen = true;
206208
}
207-
}}>Pay</Button
209+
}}>Pay</button
208210
>
209211
</section>
210212
<Modal
@@ -230,6 +232,8 @@
230232
/>
231233
{:else if selectedCurrency && currentPaymentStep === "confirmation"}
232234
<PaymentConfirmation
235+
{feeAddress}
236+
{feeAmountInUSD}
233237
{enableBuyerInfo}
234238
{productInfo}
235239
{amountInUSD}
@@ -367,6 +371,41 @@
367371
height: 100%;
368372
border-radius: 0px 0px 20px 20px;
369373
374+
button {
375+
display: inline-flex;
376+
cursor: pointer;
377+
align-items: center;
378+
justify-content: center;
379+
white-space: nowrap;
380+
border-radius: 0.375rem;
381+
font-size: 0.875rem;
382+
font-weight: 500;
383+
transition-property: color, background-color, border-color,
384+
text-decoration-color, fill, stroke;
385+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
386+
transition-duration: 150ms;
387+
background-color: #0bb489;
388+
color: white;
389+
padding: 0.5rem 1rem;
390+
border: none;
391+
outline: none;
392+
393+
&:focus-visible {
394+
outline: 2px solid transparent;
395+
outline-offset: 2px;
396+
box-shadow: 0 0 0 2px var(--ring-color, #000);
397+
}
398+
399+
&:disabled {
400+
pointer-events: none;
401+
opacity: 0.5;
402+
}
403+
404+
&:hover {
405+
background-color: rgba($color: #0bb489, $alpha: 0.8);
406+
}
407+
}
408+
370409
h2 {
371410
color: black;
372411
font-size: 18px;

packages/payment-widget/src/lib/react/PaymentWidget.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface PaymentWidgetProps {
2121
buyerInfo?: BuyerInfo;
2222
enableBuyerInfo?: boolean;
2323
invoiceNumber?: string;
24+
feeAddress?: string;
25+
feeAmountInUSD?: number;
2426
}
2527

2628
/**
@@ -70,6 +72,8 @@ export interface PaymentWidgetProps {
7072
* onError={(error) => {
7173
* console.error(error);
7274
* }}
75+
* feeAddress="0x1234567890123456789012345678901234567890
76+
* feeAmountInUSD={22}
7377
* />
7478
*/
7579
declare const PaymentWidget: React.FC<PaymentWidgetProps>;

0 commit comments

Comments
 (0)