Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,35 @@ donationRate = 10
```
<!-- tabs:end -->

## token-id

> **The ‘tokenId’ parameter defines the eToken that will be used in the button or widget.**

?> The token ID parameter is optional. It accepts a string containing the token ID. Default value is null.


**Example:**
<!-- tabs:start -->

#### **HTML**

```html
token-id="c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **JavaScript**

```javascript
tokenId: "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **React**

```react
tokenId = "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```
<!-- tabs:end -->

# Contribute

PayButton is a community-driven open-source initiative. Contributions from the community are _crucial_ to the success of the project.
Expand Down
2 changes: 2 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
- [disable-sound](/?id=disable-sound)
- [size](/?id=size)
- [donation-rate](/?id=donation-rate)
- [token-id](/?id=token-id)


- [Contribute](/?id=contribute)
- [Developer Quick Start](/?id=developer-quick-start)
Expand Down
30 changes: 30 additions & 0 deletions docs/zh-cn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,36 @@ donationRate = 10
```
<!-- tabs:end -->

## token-id

> **「tokenId」 参数用于定义在按钮或小组件中使用的 eToken。**

?> tokenId 参数是可选的。它接受一个包含 token ID 的字符串。默认值为 null。


**Example:**
<!-- tabs:start -->

#### **HTML**

```html
token-id="c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **JavaScript**

```javascript
tokenId: "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **React**

```react
tokenId = "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```
<!-- tabs:end -->

Comment on lines 1129 to 1157
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the actual file and look at the specific lines
cat -n docs/zh-cn/README.md | sed -n '1129,1157p'

Repository: PayButton/paybutton

Length of output: 761


🏁 Script executed:

# Also check if markdownlint is available and what it reports for this section
which markdownlint && markdownlint docs/zh-cn/README.md | grep -E "1129|1130|1131|1132|1133|1134|1135|1136|1137|1138|1139|1140|1141|1142|1143|1144|1145|1146|1147|1148|1149|1150|1151|1152|1153|1154|1155|1156|1157" || echo "markdownlint not available"

Repository: PayButton/paybutton

Length of output: 150


🏁 Script executed:

# Alternative: Check if there are linting tools in the repo
find . -name ".markdownlintrc*" -o -name "markdownlint*" -o -name ".lintrc*" | head -20

Repository: PayButton/paybutton

Length of output: 45


Fix markdown linting violations: spaces in tab heading emphasis markers and heading level increment.

The section contains formatting issues in the tab headings:

  • Lines 1139, 1145, 1151: Spaces inside emphasis markers (#### ** HTML ** should be #### **HTML**, etc.)
  • Heading structure jumps from h2 to h4, skipping h3 level
🤖 Prompt for AI Agents
In docs/zh-cn/README.md around lines 1129 to 1157, the tab heading emphasis
markers contain extraneous spaces and the heading level jumps from h2 to h4;
remove the spaces inside the emphasis markers so headings read like "####
**HTML**", "#### **JavaScript**", "#### **React**" (no spaces between ** and
text) and adjust the heading levels to follow the document structure (use h3 if
the section should be one level below the current h2, or otherwise ensure
headings increment sequentially) so linting and document hierarchy are correct.



# 贡献

Expand Down
2 changes: 2 additions & 0 deletions docs/zh-cn/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
- [disable-sound](/zh-cn/?id=disable-sound)
- [size](/zh-cn/?id=size)
- [donation-rate](/zh-cn/?id=donation-rate)
- [token-id](/zh-cn/?id=token-id)

- [贡献](/zh-cn/?id=贡献)
- [开发人员快速入门](/zh-cn/?id=开发人员快速入门)
- [入门](/zh-cn/?id=入门)
Expand Down
31 changes: 31 additions & 0 deletions docs/zh-tw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,37 @@ donationRate = 10
```
<!-- tabs:end -->

## token-id

> **「tokenId」 參數用於定義在按鈕或小工具中使用的 eToken。**

?> tokenId 參數為選填。它接受一個包含 token ID 的字串。預設值為 null。


**Example:**
<!-- tabs:start -->

#### **HTML**

```html
token-id="c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **JavaScript**

```javascript
tokenId: "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```

#### **React**

```react
tokenId = "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4"
```
<!-- tabs:end -->

Comment on lines 1125 to 1153
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check if markdownlint is available, if not install it
if ! command -v markdownlint &> /dev/null; then
    npm install -g markdownlint-cli 2>/dev/null || pip install markdownlint-md 2>/dev/null || echo "Installing markdownlint..."
fi

# Check markdown files exist
echo "=== Checking files ===" 
ls -la docs/zh-tw/README.md docs/zh-cn/README.md 2>&1 | head -20

# Get line counts for context
echo -e "\n=== File line counts ===" 
wc -l docs/zh-tw/README.md docs/zh-cn/README.md

# Extract the token-id section from zh-tw file (lines 1125-1153)
echo -e "\n=== zh-tw token-id section (lines 1125-1153) ===" 
sed -n '1125,1153p' docs/zh-tw/README.md | cat -n

# Extract the same section from zh-cn for comparison
echo -e "\n=== zh-cn token-id section (approx same location) ===" 
sed -n '1125,1153p' docs/zh-cn/README.md | cat -n

Repository: PayButton/paybutton

Length of output: 149


🏁 Script executed:

#!/bin/bash
# Try to run markdownlint on the specific files if available
if command -v markdownlint &> /dev/null; then
    echo "=== Markdown linting results for zh-tw ===" 
    markdownlint docs/zh-tw/README.md 2>&1 | grep -A 10 "token-id" || markdownlint docs/zh-tw/README.md 2>&1 | grep -A 10 "1131\|1137\|1143" || markdownlint docs/zh-tw/README.md 2>&1 | head -50
fi

# Check for markdownlint configuration files
echo -e "\n=== Looking for markdownlint config ===" 
find . -maxdepth 3 -name ".markdownlint*" -o -name "markdownlint*" | head -10

Repository: PayButton/paybutton

Length of output: 103


🏁 Script executed:

#!/bin/bash
# Read specific lines from zh-tw README
echo "=== Lines 1125-1153 from docs/zh-tw/README.md ===" 
sed -n '1125,1153p' docs/zh-tw/README.md

echo -e "\n=== Checking line 1131 specifically ===" 
sed -n '1131p' docs/zh-tw/README.md | cat -A

echo -e "\n=== Lines around emphasis markers (1131, 1137, 1143) ===" 
sed -n '1130,1145p' docs/zh-tw/README.md | cat -n

Repository: PayButton/paybutton

Length of output: 1078


🏁 Script executed:

#!/bin/bash
# Compare with zh-cn version
echo "=== Lines 1125-1153 from docs/zh-cn/README.md ===" 
sed -n '1125,1153p' docs/zh-cn/README.md

echo -e "\n=== Check line 1131 in zh-cn ===" 
sed -n '1131p' docs/zh-cn/README.md | cat -A

echo -e "\n=== Lines around emphasis markers in zh-cn (1131, 1137, 1143) ===" 
sed -n '1130,1145p' docs/zh-cn/README.md | cat -n

Repository: PayButton/paybutton

Length of output: 1248


Fix markdown linting violations in the token-id section.

The file contains markdown linting violations:

  • MD001: Heading level jump from ## to #### without intermediate ###
  • MD037: Spaces inside emphasis markers in ** HTML **, ** JavaScript **, and ** React **

These match the same violations present in the Simplified Chinese version.

🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 1138-1138: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 1144-1144: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 1150-1150: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 markdownlint-cli2 (0.18.1)

1135-1135: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)


1135-1135: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


1135-1135: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


1141-1141: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


1141-1141: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


1147-1147: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


1147-1147: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)

🤖 Prompt for AI Agents
In docs/zh-tw/README.md around lines 1125 to 1153, the token-id section has
markdown lint issues: the subheadings jump from ## to #### and the bold labels
contain spaces inside the emphasis markers. Fix by adjusting the subheading
levels to follow ## -> ### (or add a ### level before the current ####) so
headings increment by one level, and remove spaces inside the bold markers
(change "** HTML **", "** JavaScript **", "** React **" to "**HTML**",
"**JavaScript**", "**React**") to satisfy MD001 and MD037.




# 貢獻

Expand Down
3 changes: 3 additions & 0 deletions docs/zh-tw/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
- [auto-close](/zh-tw/?id=auto-close)
- [disable-sound](/zh-tw/?id=disable-sound)
- [size](/zh-tw/?id=size)
- [donation-rate](/zh-tw/?id=donation-rate)
- [token-id](/zh-tw/?id=token-id)

- [貢獻](/zh-tw/?id=貢獻)
- [開發人員快速入門](/zh-tw/?id=開發人員快速入門)
- [入門](/zh-tw/?id=入門)
Expand Down
1 change: 1 addition & 0 deletions paybutton/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const allowedProps = [
'transactionText',
'size',
'donationRate',
'tokenId'
];

const requiredProps = [
Expand Down
8 changes: 6 additions & 2 deletions react/lib/components/PayButton/PayButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface PayButtonProps extends ButtonProps {
sizeScaleAlreadyApplied?: boolean;
donationAddress?: string;
donationRate?: number;
tokenId?: string;
}

export const PayButton = ({
Expand Down Expand Up @@ -92,7 +93,8 @@ export const PayButton = ({
size = 'md',
sizeScaleAlreadyApplied = false,
donationRate = DEFAULT_DONATION_RATE,
donationAddress = config.donationAddress
donationAddress = config.donationAddress,
tokenId,
}: PayButtonProps): React.ReactElement => {
const [dialogOpen, setDialogOpen] = useState(false);
const [disabled, setDisabled] = useState(false);
Expand Down Expand Up @@ -310,7 +312,8 @@ export const PayButton = ({
expectedPaymentId: paymentId,
currencyObj,
donationRate
}
},
tokenId,
})
}
if (altpaymentSocket === undefined && useAltpayment) {
Expand Down Expand Up @@ -466,6 +469,7 @@ export const PayButton = ({
donationRate={donationRate}
convertedCurrencyObj={convertedCurrencyObj}
setConvertedCurrencyObj={setConvertedCurrencyObj}
tokenId={tokenId}
/>
{errorMsg && (
<p
Expand Down
5 changes: 4 additions & 1 deletion react/lib/components/PaymentDialog/PaymentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface PaymentDialogProps extends ButtonProps {
transactionText?: string
convertedCurrencyObj?: CurrencyObject;
setConvertedCurrencyObj?: Function;
tokenId?: string;
}

export const PaymentDialog = ({
Expand Down Expand Up @@ -129,7 +130,8 @@ export const PaymentDialog = ({
setConvertedCurrencyObj,
theme: themeProp,
donationAddress,
donationRate
donationRate,
tokenId,
}: PaymentDialogProps): React.ReactElement => {
const [success, setSuccess] = useState(false);
const [internalDisabled, setInternalDisabled] = useState(false);
Expand Down Expand Up @@ -259,6 +261,7 @@ export const PaymentDialog = ({
donationRate={donationRate}
convertedCurrencyObj={convertedCurrencyObj}
setConvertedCurrencyObj={setConvertedCurrencyObj}
tokenId={tokenId}
foot={success && (
<ButtonComponent
onClick={handleWidgetClose}
Expand Down
68 changes: 55 additions & 13 deletions react/lib/components/Widget/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
MINIMUM_ALTPAYMENT_CAD_AMOUNT,
} from '../../altpayment'

import { getTokenInfo } from '../../util/chronik'

export interface WidgetProps {
to: string
Expand Down Expand Up @@ -116,6 +117,7 @@ export interface WidgetProps {
convertedCurrencyObj?: CurrencyObject;
setConvertedCurrencyObj?: Function;
setPaymentId?: Function;
tokenId?: string;
}

interface StyleProps {
Expand Down Expand Up @@ -176,6 +178,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
donationRate = DEFAULT_DONATION_RATE,
setConvertedCurrencyObj = () => {},
setPaymentId,
tokenId,
} = props;
const [loading, setLoading] = useState(true);
const [draftAmount, setDraftAmount] = useState<string>("")
Expand Down Expand Up @@ -331,6 +334,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {

const [thisAmount, setThisAmount] = useState(props.amount)
const [thisCurrencyObject, setThisCurrencyObject] = useState(props.currencyObject)
const [tokenName, setTokenName] = useState<string | null>(null)

const blurCSS = isPropsTrue(disabled) ? { filter: 'blur(5px)' } : {}
// inject keyframes once (replacement for @global in makeStyles)
Expand Down Expand Up @@ -500,6 +504,10 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
)}' stroke='%23fff' stroke-width='.6'/%3E%3Cpath d='m7.2979 14.697-2.6964-2.6966 0.89292-0.8934c0.49111-0.49137 0.90364-0.88958 0.91675-0.88491 0.013104 0.0047 0.71923 0.69866 1.5692 1.5422 0.84994 0.84354 1.6548 1.6397 1.7886 1.7692l0.24322 0.23547 7.5834-7.5832 1.8033 1.8033-9.4045 9.4045z' fill='%23fff' stroke-width='.033708'/%3E%3C/svg%3E%0A`
}, [theme])

const getTokenIconUrl = useCallback((tokenId: string): string => {
return `https://icons.etokens.cash/128/${tokenId}.png`
}, [])

useEffect(() => {
if (thisCurrencyObject?.string !== undefined) {
const raw = stripFormatting(thisCurrencyObject.string);
Expand Down Expand Up @@ -541,6 +549,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
wsBaseUrl,
setTxsSocket: setThisTxsSocket,
setNewTxs: setThisNewTxs,
tokenId,
})
if (thisUseAltpayment) {
await setupAltpaymentSocket({
Expand Down Expand Up @@ -589,6 +598,26 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
})()
}, [thisNewTxs, to, apiBaseUrl])

useEffect(() => {
;(async (): Promise<void> => {
if (tokenId && tokenId !== '') {
try {
const tokenInfo = await getTokenInfo(tokenId, to)
const name = tokenInfo.genesisInfo.tokenTicker ?? null
setTokenName(name)
} catch (err) {
console.error('Failed to fetch token info:', err)
setTokenName(null)
setErrorMsg('Unable to load token information')
} finally {
setLoading(false)
}
return
}
setLoading(false)
})()
}, [tokenId, to])

useEffect(() => {
if (
isChild ||
Expand Down Expand Up @@ -805,7 +834,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
setText(
`Send ${amountToDisplay} ${thisCurrencyObject.currency} = ${convertedAmountToDisplay} ${thisAddressType}`,
)
const url = resolveUrl(thisAddressType, convertedObj.float)
const url = resolveUrl(thisAddressType, convertedObj.float, tokenId)
setUrl(url ?? "")
}
} else {
Expand All @@ -830,16 +859,16 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
amountToDisplay = amountWithDonationObj.string
}

setText(`Send ${amountToDisplay} ${cur}`)
setText(`Send ${amountToDisplay} ${tokenId ? tokenName : cur}`)
// Pass base amount (without donation) to resolveUrl
nextUrl = resolveUrl(cur, baseAmount)
nextUrl = resolveUrl(cur, baseAmount, tokenId)
} else {
setText(`Send any amount of ${thisAddressType}`)
nextUrl = resolveUrl(thisAddressType)
setText(`Send any amount of ${tokenId ? tokenName : thisAddressType}`)
nextUrl = resolveUrl(thisAddressType, undefined, tokenId)
}
setUrl(nextUrl ?? '')
}
}, [to, thisCurrencyObject, price, thisAmount, opReturn, hasPrice, isCashtabAvailable, userDonationRate, donationEnabled, disabled, donationAddress, currency, randomSatoshis, thisAddressType, shouldApplyDonation])
}, [to, thisCurrencyObject, price, thisAmount, opReturn, hasPrice, isCashtabAvailable, userDonationRate, donationEnabled, disabled, donationAddress, currency, randomSatoshis, thisAddressType, shouldApplyDonation, tokenName, tokenId])

useEffect(() => {
try {
Expand Down Expand Up @@ -961,7 +990,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
setRecentlyCopied(true)
}, [disabled, to, url, setCopied, setRecentlyCopied, qrLoading])

const resolveUrl = useCallback((currency: string, amount?: number) => {
const resolveUrl = useCallback((currency: string, amount?: number, tokenId?: string) => {
if (disabled || !to) return;

const prefix = CURRENCY_PREFIXES_MAP[currency.toLowerCase() as typeof CRYPTO_CURRENCIES[number]];
Expand All @@ -978,11 +1007,18 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
const donationPercent = userDonationRate / 100
// Calculate donation amount from base amount
const thisDonationAmount = amount * donationPercent

thisUrl += `?amount=${amount}`
thisUrl += `&addr=${donationAddress}&amount=${thisDonationAmount.toFixed(decimals)}`;
if (tokenId) {
thisUrl += `?token_decimalized_qty=${amount}`
} else {
thisUrl += `?amount=${amount}`
thisUrl += `&addr=${donationAddress}&amount=${thisDonationAmount.toFixed(decimals)}`;
}
} else {
thisUrl += `?amount=${amount}`
if (tokenId) {
thisUrl += `?token_decimalized_qty=${amount}`
} else {
thisUrl += `?amount=${amount}`
}
}
}

Expand All @@ -991,9 +1027,14 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
thisUrl += `${separator}op_return_raw=${opReturn}`;
}

if (tokenId) {
const separator = thisUrl.includes('?') ? '&' : '?';
thisUrl += `${separator}token_id=${tokenId}`;
}

return thisUrl;
},
[disabled, to, opReturn, userDonationRate, donationAddress, donationEnabled, shouldApplyDonation]
[disabled, to, opReturn, userDonationRate, donationAddress, donationEnabled, shouldApplyDonation, tokenId]
)
const stripFormatting = (s: string) => {
return s.replace(/,/g, '').replace(/(\.\d*?[1-9])0+$/, '$1').replace(/\.0+$/, '');
Expand Down Expand Up @@ -1033,6 +1074,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
}
}


const qrCode = (
<Box sx={classes.qrAnimations}>
<QRCodeSVG
Expand All @@ -1043,7 +1085,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
bgColor={isDarkMode ? '#1a1a1a' : '#ffffff'}
fgColor={theme.palette.tertiary as unknown as string}
imageSettings={{
src: success ? checkSvg : isValidCashAddress(to) ? bchSvg : xecSvg,
src: success ? checkSvg : tokenId ? getTokenIconUrl(tokenId) : isValidCashAddress(to) ? bchSvg : xecSvg,
excavate: false,
height: 112,
width: 112,
Expand Down
Loading