Skip to content

Commit 7e94d1f

Browse files
committed
feat(sdk): add fields
1 parent d535f0a commit 7e94d1f

File tree

7 files changed

+320
-9
lines changed

7 files changed

+320
-9
lines changed

apps/demo-dapp-with-react-ui/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SignDataTester } from './components/SignDataTester/SignDataTester';
1111
import { MerkleExample } from './components/MerkleExample/MerkleExample';
1212
import { FindTransactionDemo } from './components/FindTransactionDemo/FindTransactionDemo';
1313
import { TransferUsdt } from './components/TransferUsdt/TransferUsdt';
14+
import { SubscriptionForm } from './components/SubscriptionForm/SubscriptionForm';
1415

1516
function HomePage() {
1617
return (
@@ -21,9 +22,10 @@ function HomePage() {
2122
<SignDataTester />
2223
<TransferUsdt />
2324
<CreateJettonDemo />
24-
<TonProofDemo />
25+
{/* <TonProofDemo /> */}
2526
<FindTransactionDemo />
2627
<MerkleExample />
28+
<SubscriptionForm />
2729
<Footer />
2830
</div>
2931
);
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { useCallback, useState } from 'react';
2+
import ReactJson from 'react-json-view';
3+
import './style.scss';
4+
import {
5+
CreateSubscriptionV2Request,
6+
CreateSubscriptionV2Response,
7+
useTonConnectUI,
8+
useTonWallet,
9+
} from '@tonconnect/ui-react';
10+
11+
const baseSubscriptionPayload: CreateSubscriptionV2Request = {
12+
validUntil: Math.floor(Date.now() / 1000) + 600, // 10 minutes from now
13+
subscription: {
14+
beneficiary: 'UQCae11h9N5znylEPRjmuLYGvIwnxkcCw4zVW4BJjVASi5eL',
15+
id: 0,
16+
period: 1209600, // 2 week
17+
amount: '100000000',
18+
// firstChargeDate: Math.floor(Date.now() / 1000) + 86400, // 1 day from now
19+
withdrawAddress: 'UQCae11h9N5znylEPRjmuLYGvIwnxkcCw4zVW4BJjVASi5eL',
20+
withdrawMsgBody: 'asdsadasdasda',
21+
metadata: {
22+
logo: 'https://myapp.com/logo.png',
23+
name: 'Example Subscription',
24+
description: 'This is an example subscription service.',
25+
link: 'https://myapp.com',
26+
tos: 'https://myapp.com/tos',
27+
merchant: 'Example Merchant',
28+
website: 'https://myapp.com',
29+
},
30+
},
31+
};
32+
33+
export function SubscriptionForm() {
34+
const [subscription, setSubscription] =
35+
useState<CreateSubscriptionV2Request>(baseSubscriptionPayload);
36+
const [subscriptionRes, setSubscriptionRes] =
37+
useState<CreateSubscriptionV2Response | null>(null);
38+
39+
const wallet = useTonWallet();
40+
const [tonConnectUi] = useTonConnectUI();
41+
42+
const onChange = useCallback((value: object) => {
43+
setSubscription(
44+
(value as { updated_src: typeof subscription }).updated_src
45+
);
46+
}, []);
47+
48+
// const loadTemplate = (template: CreateSubscriptionV2Request) => {
49+
// setSubscription(template);
50+
// };
51+
52+
const onSend = () =>
53+
tonConnectUi
54+
.createSubscription(subscription, { version: 'v2' })
55+
.then((res) => setSubscriptionRes(res));
56+
57+
return (
58+
<div className="create-subscription-form">
59+
<h3>Configure and create subsciption</h3>
60+
<h4>Subscription data </h4>
61+
62+
{/* <div className="template-buttons">
63+
<button onClick={() => loadTemplate(defaultTextData)}>
64+
Text
65+
</button>
66+
<button onClick={() => loadTemplate(defaultBinaryData)}>
67+
Binary
68+
</button>
69+
<button onClick={() => loadTemplate(defaultCellData)}>
70+
Cell
71+
</button>
72+
</div> */}
73+
<ReactJson
74+
name={false}
75+
src={subscription}
76+
theme="ocean"
77+
onEdit={onChange}
78+
onAdd={onChange}
79+
onDelete={onChange}
80+
/>
81+
{subscriptionRes && (
82+
<>
83+
<h4>Create subscription response</h4>
84+
<ReactJson
85+
name={false}
86+
src={subscriptionRes}
87+
theme="ocean"
88+
/>
89+
</>
90+
)}
91+
{wallet && (
92+
<div className="buttons-container">
93+
<button onClick={onSend}>Create subscription</button>
94+
{subscriptionRes && <button>Cancel subscription</button>}
95+
</div>
96+
)}
97+
</div>
98+
);
99+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
.create-subscription-form {
2+
flex: 1;
3+
display: flex;
4+
width: 100%;
5+
flex-direction: column;
6+
gap: 20px;
7+
padding: 20px;
8+
align-items: center;
9+
10+
h3 {
11+
color: white;
12+
opacity: 0.8;
13+
font-size: 28px;
14+
}
15+
16+
h4 {
17+
color: white;
18+
opacity: 0.8;
19+
font-size: 20px;
20+
margin: 0;
21+
}
22+
23+
> div {
24+
width: 100%;
25+
26+
span {
27+
word-break: break-word;
28+
}
29+
}
30+
31+
.buttons-container {
32+
display: flex;
33+
gap: 10px;
34+
margin-top: 16px;
35+
justify-content: center;
36+
37+
> button {
38+
border: none;
39+
padding: 7px 15px;
40+
border-radius: 15px;
41+
cursor: pointer;
42+
43+
background-color: rgba(102, 170, 238, 0.91);
44+
color: white;
45+
font-size: 16px;
46+
line-height: 20px;
47+
48+
transition: transform 0.1s ease-in-out;
49+
50+
&:hover {
51+
transform: scale(1.03);
52+
}
53+
54+
&:active {
55+
transform: scale(0.97);
56+
}
57+
}
58+
}
59+
60+
.verification-result {
61+
margin-top: 16px;
62+
padding: 10px;
63+
border-radius: 4px;
64+
font-weight: bold;
65+
66+
&.success {
67+
background-color: rgba(0, 255, 0, 0.1);
68+
color: #00ff00;
69+
}
70+
71+
&.error {
72+
background-color: rgba(255, 0, 0, 0.1);
73+
color: #ff0000;
74+
}
75+
}
76+
}

packages/sdk/src/models/methods/create-subscription-v2/create-subscription-v2-request.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export interface SubscriptionV2Metadata {
2323
}
2424

2525
export interface CreateSubscriptionV2Details {
26-
/** Subscription UUID defined by merchant */
27-
id: string;
26+
/** Subscription identifier (uint32) */
27+
id: number;
2828
/** Beneficiary address */
2929
beneficiary: string;
3030
/** Amount in nanoTON */
@@ -33,6 +33,10 @@ export interface CreateSubscriptionV2Details {
3333
period: number;
3434
/** First charging date (optional) */
3535
firstChargeDate?: number;
36+
/** Address that will receive the subscription payment */
37+
withdrawAddress: string;
38+
/** Message body that will be sent to the withdraw address */
39+
withdrawMsgBody?: string;
3640
/** Subscription metadata */
3741
metadata: SubscriptionV2Metadata;
3842
}

packages/sdk/src/parsers/create-subscription-v2-parser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ export class CreateSubscriptionV2Parser extends RpcParser<'createSubscriptionV2'
2626
convertToRpcRequest(
2727
request: Omit<CreateSubscriptionV2Request, 'validUntil' | 'subscription'> & {
2828
valid_until: number;
29-
subscription: Omit<CreateSubscriptionV2Request['subscription'], 'firstChargeDate'> & {
29+
subscription: Omit<CreateSubscriptionV2Request['subscription'], 'firstChargeDate' | 'withdrawAddress' | 'withdrawMsgBody'> & {
3030
first_charge_date?: CreateSubscriptionV2Request['subscription']['firstChargeDate'];
31+
withdraw_address: CreateSubscriptionV2Request['subscription']['withdrawAddress'];
32+
withdraw_msg_body?: CreateSubscriptionV2Request['subscription']['withdrawMsgBody'];
3133
};
3234
}
3335
): WithoutId<CreateSubscriptionV2RpcRequest> {

packages/sdk/src/ton-connect.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ import {
7070
validateSendTransactionRequest,
7171
validateSignDataPayload,
7272
validateConnectAdditionalRequest,
73-
validateTonProofItemReply
73+
validateTonProofItemReply,
74+
validateCreateSubscriptionV2Request
7475
} from './validation/schemas';
7576
import { isQaModeEnabled } from './utils/qa-mode';
7677
import { normalizeBase64 } from './utils/base64';
@@ -604,6 +605,12 @@ export class TonConnect implements ITonConnect {
604605
throw new TonConnectError('Subscription V2 creation was aborted');
605606
}
606607

608+
// Validate the request
609+
const validationError = validateCreateSubscriptionV2Request(data);
610+
if (validationError) {
611+
throw new TonConnectError(validationError);
612+
}
613+
607614
this.checkConnection();
608615
checkSubscriptionSupport(this.wallet!.device.features);
609616

@@ -625,17 +632,19 @@ export class TonConnect implements ITonConnect {
625632
const from = data.from ?? this.account!.address; // TODO: verify if data.from is needed or can be removed in favor of always using this.account!.address
626633
const network = data.network ?? this.account!.chain;
627634

635+
const { firstChargeDate, withdrawAddress, withdrawMsgBody, ...subscriptionRest } = data.subscription;
636+
628637
const response = await this.provider!.sendRequest(
629638
createSubscriptionV2Parser.convertToRpcRequest({
630639
...data,
631640
from,
632641
network,
633642
valid_until: data.validUntil,
634643
subscription: {
635-
...data.subscription,
636-
...(data.subscription.firstChargeDate !== undefined && {
637-
first_charge_date: data.subscription.firstChargeDate
638-
})
644+
...subscriptionRest,
645+
...(firstChargeDate !== undefined && { first_charge_date: firstChargeDate }),
646+
withdraw_address: withdrawAddress,
647+
withdraw_msg_body: withdrawMsgBody
639648
}
640649
}),
641650
{

0 commit comments

Comments
 (0)