npm package: @springmint/sdk
Description: Cppay SDK for cryptocurrency payments - supports React and Vue
Author: Cppay Team
Latest version: 0.1.1

# CPPay SDK

CPPay SDK 是一个支持多链加密货币支付的前端 SDK，支持一次性支付和订阅支付。

## 📦 安装

```bash
npm install @springmint/sdk
# 或
yarn add @springmint/sdk
# 或
pnpm add @springmint/sdk
```

## 🚀 快速开始

### React 使用

#### 方式一：使用 Provider + Hook（推荐）

这是最灵活的方式，适合需要在多个组件中调用支付功能的场景。

**1. 配置 Provider**

```tsx
// App.tsx
import { CppayProvider } from "@springmint/sdk/react";

function App() {
  return (
    <CppayProvider>
      <YourApp />
    </CppayProvider>
  );
}
```

**2. 使用 Hook 调用支付**

```tsx
// PaymentButton.tsx
import { useCppayPayment } from "@springmint/sdk/react";

function PaymentButton() {
  const { showPayment, closePayment } = useCppayPayment();

  const handlePay = () => {
    showPayment({
      apikey: "your-api-key",
      plain: "instant", // instant | 'subscription'
      orderId: "ORD-0000001",
      amount: "100", // USD
      onSuccess: (order) => {
        console.log("支付成功", order);
      },
      onError: (error) => {
        console.error("支付失败", error);
      },
      onExpired: (order) => {
        console.log("支付已过期", order);
      },
      onFailed: (order) => {
        console.log("支付失败", order);
      },
    });
  };

  return <button onClick={handlePay}>支付</button>;
}
```

#### 方式二：使用 PaymentDialog 组件

适合需要手动控制弹框显示隐藏的场景。

```tsx
import { useState } from "react";
import { PaymentDialog } from "@springmint/sdk/react";

function App() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button onClick={() => setOpen(true)}>支付</button>

      <PaymentDialog
        open={open}
        onClose={() => setOpen(false)}
        apikey="your-api-key"
        plain="instant"
        orderId="order-123"
        amount="100"
        onSuccess={(order) => {
          console.log("支付成功", order);
          setOpen(false);
        }}
        onError={(error) => {
          console.error("支付失败", error);
        }}
      />
    </>
  );
}
```

#### 方式三：使用 PaymentContent 组件

适合需要自定义页面布局，不使用弹框的场景。

```tsx
import { PaymentContent } from "@springmint/sdk/react";

function PaymentPage() {
  return (
    <div className="payment-page">
      <h1>支付页面</h1>
      <PaymentContent
        apikey="your-api-key"
        plain="instant"
        orderId="order-123"
        amount="100"
        onSuccess={(order) => {
          console.log("支付成功", order);
        }}
        onError={(error) => {
          console.error("支付失败", error);
        }}
      />
    </div>
  );
}
```

---

### Vue 使用

#### 方式一：使用 Plugin + Composable（推荐）

**1. 安装插件**

```typescript
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { CppayPlugin } from "@springmint/sdk/vue";

const app = createApp(App);

app.use(CppayPlugin);

app.mount("#app");
```

**2. 使用 Composable 调用支付**

```vue
<script setup lang="ts">
import { useCppayPayment } from "@springmint/sdk/vue";

const { showPayment, closePayment } = useCppayPayment();

const handlePay = () => {
  showPayment({
    apikey: "your-api-key",
    plain: "instant",
    orderId: "order-123",
    amount: "100",
    onSuccess: (order) => {
      console.log("支付成功", order);
    },
    onError: (error) => {
      console.error("支付失败", error);
    },
  });
};
</script>

<template>
  <button @click="handlePay">支付</button>
</template>
```

**3. 或使用全局方法**

```vue
<script setup lang="ts">
import { getCurrentInstance } from "vue";

const instance = getCurrentInstance();

const handlePay = () => {
  instance?.proxy?.$showPayment({
    apikey: "your-api-key",
    plain: "instant",
    orderId: "order-123",
    amount: "100",
    onSuccess: (order) => {
      console.log("支付成功", order);
    },
  });
};
</script>

<template>
  <button @click="handlePay">支付</button>
</template>
```

#### 方式二：使用 PaymentDialog 组件

```vue
<script setup lang="ts">
import { ref } from "vue";
import { PaymentDialog } from "@springmint/sdk/vue";

const dialogOpen = ref(false);

const handleSuccess = (order: any) => {
  console.log("支付成功", order);
  dialogOpen.value = false;
};
</script>

<template>
  <button @click="dialogOpen = true">支付</button>

  <PaymentDialog
    v-model="dialogOpen"
    apikey="your-api-key"
    plain="instant"
    order-id="order-123"
    amount="100"
    @success="handleSuccess"
    @error="(error) => console.error(error)"
  />
</template>
```

#### 方式三：使用 PaymentContent 组件

```vue
<script setup lang="ts">
import { PaymentContent } from "@springmint/sdk/vue";

const handleSuccess = (order: any) => {
  console.log("支付成功", order);
};
</script>

<template>
  <div class="payment-page">
    <h1>支付页面</h1>
    <PaymentContent
      apikey="your-api-key"
      plain="instant"
      order-id="order-123"
      amount="100"
      @success="handleSuccess"
      @error="(error) => console.error(error)"
    />
  </div>
</template>
```

---

## 🔧 直接使用 API（不使用组件）

如果你不想使用我们提供的 UI 组件，可以直接调用底层 API 来实现自定义的支付流程。

### 安装和初始化

```typescript
import Cppay from "@springmint/sdk";

// 使用 API Key 初始化
const cppay = new Cppay("your-api-key");
```

### 1. 获取支持的链和代币

```typescript
const chains = await cppay.getSupportedChains();

console.log(chains);
// [
//   {
//     chain: 'Ethereum',
//     chainId: 1,
//     icon: 'https://...',
//     tokens: [
//       {
//         symbol: 'USDT',
//         decimals: 6,
//         address: '0x...',
//         icon: 'https://...',
//         price: '1.00'
//       },
//       // ...
//     ]
//   },
//   // ...
// ]
```

### 2. 创建一次性支付

```typescript
const paymentInfo = await cppay.createOnetimePayment({
  paymentChain: "Ethereum",
  paymentToken: "USDT",
  orderId: "order-123",
  amount: "0.0001", // Token Amount
  remark: "商品购买",
});

console.log(paymentInfo);
// {
//   orderId: 'order-123',
//   paymentId: 'pay-xxx',
//   paymentAmount: '0.0001',
//   paymentChain: 'Ethereum',
//   paymentToken: 'USDT',
//   receiveAddress: '0x...',
//   expireAt: 1234567890
// }
```

### 3. 创建订阅支付

```typescript
const subscriptionInfo = await cppay.createSubscriptionPayment({
  paymentChain: "BSC",
  paymentToken: "USDT",
  orderId: "subscription-123",
  amountOfUsd: "9.99",
  intervalDays: 30,
});

console.log(subscriptionInfo);
// {
//   orderId: 'subscription-123',
//   subscriptionId: 'sub-xxx',
//   approveAmount: '299.70',
//   spenderAddress: '0x...',
//   expireAt: 1234567890,
//   paymentChain: 'BSC',
//   paymentToken: 'USDT',
//   amountOfUsd: '9.99',
//   intervalDays: 30
// }
```

### 4. 查询支付状态

```typescript
// 查询一次性支付状态
const status = await cppay.checkOnetimePaymentStatus({
  paymentId: "pay-xxx",
});

console.log(status);
// {
//   orderId: 'order-123',
//   paymentId: 'pay-xxx',
//   status: 'paid', // 'pending' | 'paid' | 'expired' | 'failed'
//   chain: 'Ethereum',
//   token: 'USDT',
//   baseAmount: '100',
//   payAmount: '100.00',
//   receiveAddress: '0x...',
//   expireAt: 1234567890
// }

// 查询订阅支付状态
const subscriptionStatus = await cppay.checkSubscriptionPaymentStatus({
  subscriptionId: "sub-xxx",
});

console.log(subscriptionStatus);
// {
//   orderId: 'subscription-123',
//   subscriptionId: 'sub-xxx',
//   status: 'approved', // 'pending' | 'approved' | 'expired' | 'failed'
//   chain: 'BSC',
//   token: 'USDT',
//   approvedAddress: '0x...',
//   txHash: '0x...',
//   approveAmount: '299.70',
//   amountOfUsd: '9.99',
//   expireAt: 1234567890
// }
```

### 完整的自定义支付流程示例

```typescript
import Cppay from "@springmint/sdk";

const cppay = new Cppay("your-api-key", undefined);

async function customPaymentFlow() {
  try {
    // 1. 获取支持的链和代币
    const chains = await cppay.getSupportedChains();
    console.log("支持的链:", chains);

    // 2. 用户选择链和代币
    const selectedChain = "Ethereum";
    const selectedToken = "USDT";

    // 3. 创建支付
    const paymentInfo = await cppay.createOnetimePayment({
      paymentChain: selectedChain,
      paymentToken: selectedToken,
      orderId: `order-${Date.now()}`,
      amount: "0.1",
      // remark: "商品购买",
    });

    console.log("支付信息:", paymentInfo);
    console.log("请向地址转账:", paymentInfo.receiveAddress);
    console.log("金额:", paymentInfo.paymentAmount);

    // 4. 轮询检查支付状态
    const checkPayment = setInterval(async () => {
      const status = await cppay.checkOnetimePaymentStatus({
        paymentId: paymentInfo.paymentId,
      });

      console.log("支付状态:", status.status);

      if (status.status === "paid") {
        console.log("支付成功！");
        clearInterval(checkPayment);
      } else if (status.status === "expired" || status.status === "failed") {
        console.log("支付失败或过期");
        clearInterval(checkPayment);
      }
    }, 3000); // 每3秒检查一次
  } catch (error) {
    console.error("支付流程错误:", error);
  }
}

customPaymentFlow();
```

---

## 📖 API 参数说明

### 通用参数

| 参数           | 类型                          | 必填 | 说明                                                    |
| -------------- | ----------------------------- | ---- | ------------------------------------------------------- |
| `apikey`       | `string`                      | 是   | API 密钥.                                              |
| `plain`        | `'instant' \| 'subscription'` | 是   | 支付类型：`instant` 一次性支付，`subscription` 订阅支付 |
| `orderId`      | `string`                      | 是   | 订单 ID（唯一标识）                                     |
| `amount`       | `string`                      | 是   | 支付金额（USD）                                         |
| `intervalDays` | `number`                      | 否   | 订阅间隔天数（订阅支付时必填）                          |
| `remark`       | `string`                      | 否   | 备注信息                                                |
| `locale`       | `'en' \| 'zh-CN'`             | 否   | 语言设置，默认 `'en'`                                   |

### 回调函数

| 回调        | 参数类型          | 说明         |
| ----------- | ----------------- | ------------ |
| `onSuccess` | `(order) => void` | 支付成功回调 |
| `onError`   | `(error) => void` | 支付错误回调 |
| `onExpired` | `(order) => void` | 支付过期回调 |
| `onFailed`  | `(order) => void` | 支付失败回调 |

### PaymentDialog 特有参数（React）

| 参数      | 类型         | 必填 | 说明              |
| --------- | ------------ | ---- | ----------------- |
| `open`    | `boolean`    | 是   | 控制弹框显示/隐藏 |
| `onClose` | `() => void` | 是   | 关闭弹框回调      |

### PaymentDialog 特有参数（Vue）

| 参数                     | 类型      | 必填 | 说明              |
| ------------------------ | --------- | ---- | ----------------- |
| `v-model` / `modelValue` | `boolean` | 是   | 控制弹框显示/隐藏 |

---

## 🎨 自定义插槽（Slots）

组件支持自定义插槽，可以替换默认的 UI 展示。

### React 示例

```tsx
<PaymentDialog
  open={open}
  onClose={() => setOpen(false)}
  apikey="your-api-key"
  plain="instant"
  orderId="order-123"
  amount="100"
  Slots={{
    Success: ({ paymentInfo }) => (
      <div>
        <h2>支付成功！</h2>
        <p>订单号: {paymentInfo.orderId}</p>
      </div>
    ),
    Error: ({ paymentInfo }) => (
      <div>
        <h2>支付出错</h2>
        <p>请稍后重试</p>
      </div>
    ),
  }}
/>
```

### 可用插槽

- `ChooseTop`: 选择支付方式页面顶部内容
- `ChooseBottom`: 选择支付方式页面底部内容
- `Success`: 支付成功页面
- `Expired`: 支付过期页面
- `Failed`: 支付失败页面
- `Error`: 支付错误页面

---

## 🌍 支持的链和代币

SDK 支持多个主流区块链网络：

- **Ethereum**（以太坊）
- **BSC**（币安智能链）
- **Polygon**（马蹄链）
- **Tron**（波场）
- **Solana**（索拉纳）

支持的代币：

- USDT
- USDC
- ETH
- BNB
- TRX
- SOL

具体支持的链和代币可通过 `getSupportedChains()` API 动态获取。

---

## 📝 类型定义

```typescript
// 支付类型
type PaymentPlain = "instant" | "subscription";

// 支付状态
type PaymentStatus = "pending" | "paid" | "expired" | "failed";

// 订阅支付状态
type SubscriptionPaymentStatus = "pending" | "approved" | "expired" | "failed";

// 一次性支付信息
interface OnetimePaymentInfo {
  orderId: string;
  paymentId: string;
  paymentAmount: string;
  paymentChain: string;
  paymentToken: string;
  receiveAddress: string;
  expireAt: number;
}

// 订阅支付信息
interface SubscriptionPaymentInfo {
  orderId: string;
  subscriptionId: string;
  approveAmount: string;
  spenderAddress: string;
  expireAt: number;
  paymentChain: string;
  paymentToken: string;
  amountOfUsd: string;
  intervalDays: number;
}

// 链信息
interface ChainInfo {
  chain: string;
  chainId: number;
  icon?: string;
  tokens: TokenInfo[];
}

// 代币信息
interface TokenInfo {
  symbol: string;
  decimals: number;
  address: string;
  icon?: string;
  price: string;
}
```

---

## ⚠️ 注意事项

1. **API Key 安全性**：请勿在前端代码中直接暴露 API Key，建议使用环境变量或后端代理。
2. **支付轮询**：使用组件时会自动轮询支付状态，直接使用 API 时需要自行实现轮询逻辑。
3. **订阅支付**：订阅支付需要用户授权代币使用权限，首次支付会有两笔交易（授权 + 支付）。
4. **过期时间**：支付订单有过期时间限制，请在 `expireAt` 之前完成支付。

---

## 🔗 相关链接

- [官方文档](https://docs.cppay.io)
- [API 参考](https://api.cppay.io/docs)
- [示例项目](https://github.com/cppay/examples)

---

## 📄 License

MIT License