@bitpal/checkout 0.3.0 → 0.6.0

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/MIGRATION_v0.2.md DELETED
@@ -1,135 +0,0 @@
1
- # @bitpal/checkout — Migration Guide v0.1.x → v0.2.0
2
-
3
- > Audit doc 11 §3 C-01 option 2 (PaymentAuthorization 이중방어) 적용으로 인한 SDK 메이저 bump.
4
-
5
- ## Why this change
6
-
7
- v0.1.x 까지의 `payWithAuthorization` 흐름은 buyer 의 EIP-3009 USDC sig 만 받았다. 이 sig 는
8
- `(from, to, value, validAfter, validBefore, nonce)` 만 바인딩하므로, **paymentId / merchant /
9
- amount / fee / reserve / duration** 은 호출자(BitPal gateway)가 자유롭게 지정 가능했다.
10
-
11
- → gateway 키 탈취 시 공격자가 (a) buyer 의 EIP-3009 sig 입수 후 (b) 자기 주소를 merchant 로 설정,
12
- (c) `depositWithAuthorization` 호출 → buyer 자금이 attacker merchant 로 흘러간다.
13
-
14
- v0.2.0 는 buyer 가 **결제 의도 전체** 에 별도 EIP-712 서명 (`PaymentAuthorization`) 을 한다. gateway
15
- 키 탈취 시에도 buyer 의도 밖 결제 생성 불가 (이중방어).
16
-
17
- ## Breaking changes
18
-
19
- ### `BitPal.checkout.payWithAuthorization(sessionId, params)`
20
-
21
- `params.payment_auth` 필드가 **필수** 가 됐다.
22
-
23
- **Before (v0.1.x):**
24
- ```ts
25
- await bp.checkout.payWithAuthorization(sessionId, {
26
- session_token: 'xyz...',
27
- chain: 'base',
28
- authorization: {
29
- from: buyer.address,
30
- validAfter: '0',
31
- validBefore: String(Math.floor(Date.now()/1000) + 3600),
32
- authNonce: '0x...',
33
- v: 27, r: '0x...', s: '0x...',
34
- },
35
- });
36
- ```
37
-
38
- **After (v0.2.0):**
39
- ```ts
40
- import {
41
- buildPaymentAuthTypedData,
42
- sessionIdToPaymentId,
43
- } from '@bitpal/checkout';
44
-
45
- // 1. PaymentAuthorization nonce 조회 (CheckoutEscrow.paymentAuthNonce)
46
- const nonce = await escrow.read.paymentAuthNonce([buyer.address]);
47
-
48
- // 2. PaymentAuthorization typed-data sig
49
- const paymentAuthDeadline = Math.floor(Date.now()/1000) + 3600;
50
- const paymentId = sessionIdToPaymentId(sessionId);
51
- const paymentAuthTd = buildPaymentAuthTypedData({
52
- escrowAddress: escrow.address,
53
- chainId: 8453,
54
- paymentId,
55
- payer: buyer.address,
56
- merchant: session.seller_wallet,
57
- token: session.token_address,
58
- amount: session.amount_total,
59
- feeAmount: '0',
60
- reserveAmount: '0',
61
- duration: '0',
62
- deadline: String(paymentAuthDeadline),
63
- nonce: String(nonce),
64
- });
65
- const paymentAuthSig = await wallet.signTypedData(paymentAuthTd);
66
- const paymentAuthParsed = parseSignature(paymentAuthSig); // viem helper
67
-
68
- // 3. USDC EIP-3009 sig (변경 없음 — 기존 흐름 그대로)
69
- const usdcSig = await wallet.signTypedData({ /* TransferWithAuthorization ... */ });
70
- const usdcParsed = parseSignature(usdcSig);
71
-
72
- // 4. payWithAuthorization 호출 — payment_auth 필드 추가
73
- await bp.checkout.payWithAuthorization(sessionId, {
74
- session_token: 'xyz...',
75
- chain: 'base',
76
- authorization: {
77
- from: buyer.address,
78
- validAfter: '0',
79
- validBefore: String(Math.floor(Date.now()/1000) + 3600),
80
- authNonce: '0x...',
81
- v: Number(usdcParsed.v), r: usdcParsed.r, s: usdcParsed.s,
82
- },
83
- // ← 신규 필수
84
- payment_auth: {
85
- deadline: String(paymentAuthDeadline),
86
- duration: '0',
87
- v: Number(paymentAuthParsed.v),
88
- r: paymentAuthParsed.r,
89
- s: paymentAuthParsed.s,
90
- },
91
- });
92
- ```
93
-
94
- ### 백엔드 응답에서 `payment_auth_nonce` 노출
95
-
96
- 서버는 `GET /v1/checkout/sessions/:id/public` 응답에 `payment_auth_nonce` 필드를 포함한다
97
- (Q5 적용 후). buyer UI 가 컨트랙트를 직접 호출하지 않고도 nonce 를 얻을 수 있다. 단,
98
- `merchant_wallet` (seller_wallet) 도 sig 에 들어가므로 public response 에서 확인할 수 있어야 한다.
99
-
100
- ## Non-breaking changes
101
-
102
- 다음 SDK 흐름은 변경 없음:
103
-
104
- - `createSession()`, `getSession()`, `listSessions()`, `previewFee()`
105
- - `refundSession()`, `recordRefund()`, `listRefunds()`
106
- - `submitExternalPayment()` (Mode A — buyer 가 본인 지갑으로 직접 deposit)
107
- - Webhook helpers (`verifyWebhookSignature`, `parseWebhookEvent`)
108
- - Amount helpers (`toAtomicUSDC`, `fromAtomicUSDC`)
109
-
110
- ## Why `payment_auth` is required (no opt-out)
111
-
112
- Q4 PR 적용 후 `CheckoutEscrow.depositWithAuthorization` 가 PaymentAuthorization sig 를 강제한다
113
- (컨트랙트 require). SDK 가 sig 없이 호출 시 백엔드가 `PAYMENT_AUTH_REQUIRED` (400) 로 거부.
114
-
115
- ## Compatibility matrix
116
-
117
- | SDK version | Backend (CheckoutEscrow contract) | Result |
118
- |---|---|---|
119
- | v0.1.x | post-Q5 (PaymentAuthorization 필수) | ❌ `PAYMENT_AUTH_REQUIRED` 400 |
120
- | v0.2.0 | post-Q5 | ✅ OK |
121
- | v0.2.0 | pre-Q5 (legacy 미배포 contract) | ❌ contract revert (signature 추가 인자 없음) |
122
-
123
- → SDK v0.2.0 와 컨트랙트 Q4+Q5 적용은 **동시 배포** 가 원칙. testnet 부터 함께 갈아끼움.
124
-
125
- ## New helpers
126
-
127
- - `buildPaymentAuthTypedData(args)` — `signTypedData` 호환 객체 생성
128
- - `buildConfirmReceiptTypedData(args)` — Q4 H-01 `confirmReceiptWithSignature` 용 (off-chain receipt confirmation 직접 구현 시 사용. 기본 흐름에서는 BitPal hosted page 가 처리)
129
- - `sessionIdToPaymentId(sessionId)` — 32-byte hex 변환 (= 백엔드 `toBytes32()`)
130
-
131
- ## See also
132
-
133
- - `docs/_dan/b2b-spec/2026-05-14-11-smart-contract-security-audit.md` §3 C-01
134
- - `docs/_dan/b2b-spec/2026-05-18-14-post-audit-remaining-hardening-plan.md` §4 (PR-C 실행 가이드)
135
- - README.md §"Gasless lane (Hosted / Gasless)"