@@ -330,6 +330,257 @@ const [tonConnectUI] = useTonConnectUI();
330
330
await tonConnectUI .disconnect ();
331
331
` ` `
332
332
333
+ ## Wrappers
334
+
335
+ Wrappers are classes that simplify interaction with the contract, allowing you to work without concerning yourself with the underlying details.
336
+
337
+ - When developing a contract in ` funC ` , you need to write the wrapper yourself.
338
+ - When using the ` Tact ` language, wrappers are automatically generated for you.
339
+
340
+ :::tip
341
+ Check out [blueprint](https://github.com/ton-org/blueprint) documentation how to develop and deploy contracts
342
+ :::
343
+
344
+ Let's take a look at the default ` Blueprint ` Counter wrapper example and how we can use it:
345
+
346
+ <details>
347
+ <summary>Wrapper usage</summary>
348
+ Counter wrapper class:
349
+
350
+ ` ` ` ts
351
+ import { Address , beginCell , Cell , Contract , contractAddress , ContractProvider , Sender , SendMode } from ' @ton/core' ;
352
+
353
+ export type CounterConfig = {
354
+ id: number ;
355
+ counter : number ;
356
+ };
357
+
358
+ export function counterConfigToCell(config : CounterConfig ): Cell {
359
+ return beginCell ().storeUint (config .id , 32 ).storeUint (config .counter , 32 ).endCell ();
360
+ }
361
+
362
+ export const Opcodes = {
363
+ increase: 0x7e8764ef ,
364
+ };
365
+
366
+ export class Counter implements Contract {
367
+ constructor (
368
+ readonly address : Address ,
369
+ readonly init ? : { code: Cell ; data: Cell },
370
+ ) {}
371
+
372
+ static createFromAddress(address : Address ) {
373
+ return new Counter (address );
374
+ }
375
+
376
+ static createFromConfig(config : CounterConfig , code : Cell , workchain = 0 ) {
377
+ const data = counterConfigToCell (config );
378
+ const init = { code , data };
379
+ return new Counter (contractAddress (workchain , init ), init );
380
+ }
381
+
382
+ async sendDeploy(provider : ContractProvider , via : Sender , value : bigint ) {
383
+ await provider .internal (via , {
384
+ value ,
385
+ sendMode: SendMode .PAY_GAS_SEPARATELY ,
386
+ body: beginCell ().endCell (),
387
+ });
388
+ }
389
+
390
+ async sendIncrease(
391
+ provider : ContractProvider ,
392
+ via : Sender ,
393
+ opts : {
394
+ increaseBy: number ;
395
+ value: bigint ;
396
+ queryID? : number ;
397
+ },
398
+ ) {
399
+ await provider .internal (via , {
400
+ value: opts .value ,
401
+ sendMode: SendMode .PAY_GAS_SEPARATELY ,
402
+ body: beginCell ()
403
+ .storeUint (Opcodes .increase , 32 )
404
+ .storeUint (opts .queryID ?? 0 , 64 )
405
+ .storeUint (opts .increaseBy , 32 )
406
+ .endCell (),
407
+ });
408
+ }
409
+
410
+ async getCounter(provider : ContractProvider ) {
411
+ const result = await provider .get (' get_counter' , []);
412
+ return result .stack .readNumber ();
413
+ }
414
+
415
+ async getID(provider : ContractProvider ) {
416
+ const result = await provider .get (' get_id' , []);
417
+ return result .stack .readNumber ();
418
+ }
419
+ }
420
+
421
+ ` ` `
422
+
423
+ Then you can use this class in your react component:
424
+
425
+ ` ` ` ts
426
+
427
+ import " buffer" ;
428
+ import {
429
+ TonConnectUI ,
430
+ useTonConnectUI ,
431
+ useTonWallet ,
432
+ } from " @tonconnect/ui-react" ;
433
+ import {
434
+ Address ,
435
+ beginCell ,
436
+ Sender ,
437
+ SenderArguments ,
438
+ storeStateInit ,
439
+ toNano ,
440
+ TonClient ,
441
+ } from " @ton/ton" ;
442
+
443
+ class TonConnectProvider implements Sender {
444
+ /**
445
+ * The TonConnect UI instance.
446
+ * @private
447
+ */
448
+ private readonly provider: TonConnectUI ;
449
+
450
+ /**
451
+ * The address of the current account.
452
+ */
453
+ public get address(): Address | undefined {
454
+ const address = this .provider .account ?.address ;
455
+ return address ? Address .parse (address ) : undefined ;
456
+ }
457
+
458
+ /**
459
+ * Creates a new TonConnectProvider.
460
+ * @param provider
461
+ */
462
+ public constructor (provider : TonConnectUI ) {
463
+ this .provider = provider ;
464
+ }
465
+
466
+ /**
467
+ * Sends a message using the TonConnect UI.
468
+ * @param args
469
+ */
470
+ public async send(args : SenderArguments ): Promise <void > {
471
+ // The transaction is valid for 10 minutes.
472
+ const validUntil = Math .floor (Date .now () / 1000 ) + 600 ;
473
+
474
+ // The address of the recipient, should be in bounceable format for all smart contracts.
475
+ const address = args .to .toString ({ urlSafe: true , bounceable: true });
476
+
477
+ // The address of the sender, if available.
478
+ const from = this .address ?.toRawString ();
479
+
480
+ // The amount to send in nano tokens.
481
+ const amount = args .value .toString ();
482
+
483
+ // The state init cell for the contract.
484
+ let stateInit: string | undefined ;
485
+ if (args .init ) {
486
+ // State init cell for the contract.
487
+ const stateInitCell = beginCell ()
488
+ .store (storeStateInit (args .init ))
489
+ .endCell ();
490
+ // Convert the state init cell to boc base64.
491
+ stateInit = stateInitCell .toBoc ().toString (" base64" );
492
+ }
493
+
494
+ // The payload for the message.
495
+ let payload: string | undefined ;
496
+ if (args .body ) {
497
+ // Convert the message body to boc base64.
498
+ payload = args .body .toBoc ().toString (" base64" );
499
+ }
500
+
501
+ // Send the message using the TonConnect UI and wait for the message to be sent.
502
+ await this .provider .sendTransaction ({
503
+ validUntil: validUntil ,
504
+ from: from ,
505
+ messages: [
506
+ {
507
+ address: address ,
508
+ amount: amount ,
509
+ stateInit: stateInit ,
510
+ payload: payload ,
511
+ },
512
+ ],
513
+ });
514
+ }
515
+ }
516
+
517
+ const CONTRACT_ADDRESS = " EQAYLhGmznkBlPxpnOaGXda41eEkliJCTPF6BHtz8KXieLSc" ;
518
+
519
+ const getCounterInstance = async () => {
520
+ const client = new TonClient ({
521
+ endpoint: " https://testnet.toncenter.com/api/v2/jsonRPC" ,
522
+ });
523
+
524
+ // OR you can use createApi from @ton-community/assets-sdk
525
+ // import {
526
+ // createApi,
527
+ // } from "@ton-community/assets-sdk";
528
+
529
+ // const NETWORK = "testnet";
530
+ // const client = await createApi(NETWORK);
531
+
532
+
533
+ const address = Address .parse (CONTRACT_ADDRESS );
534
+ const counterInstance = client .open (Counter .createFromAddress (address ));
535
+
536
+ return counterInstance ;
537
+ };
538
+
539
+ export const Header = () => {
540
+ const [tonConnectUI, setOptions] = useTonConnectUI ();
541
+ const wallet = useTonWallet ();
542
+
543
+ const increaseCount = async () => {
544
+ const counterInstance = await getCounterInstance ();
545
+ const sender = new TonConnectProvider (tonConnectUI );
546
+
547
+ await counterInstance .sendIncrease (sender , {
548
+ increaseBy: 1 ,
549
+ value: toNano (" 0.05" ),
550
+ });
551
+ };
552
+
553
+ const getCount = async () => {
554
+ const counterInstance = await getCounterInstance ();
555
+
556
+ const count = await counterInstance .getCounter ();
557
+ console .log (" count" , count );
558
+ };
559
+
560
+ return (
561
+ <main >
562
+ { ! wallet && (
563
+ <button onClick = { () => tonConnectUI .openModal ()} >Connect Wallet</button >
564
+ )}
565
+ { wallet && (
566
+ <>
567
+ <button onClick = { increaseCount } >Increase count</button >
568
+ <button onClick = { getCount } >Get count</button >
569
+ </>
570
+ )}
571
+ </main >
572
+ );
573
+ };
574
+
575
+ ` ` `
576
+ </details>
577
+
578
+
579
+ ### Wrappers for Jettons and NFTs
580
+
581
+ To interact with jettons or NFTs you can use [assets-sdk](https://github.com/ton-community/assets-sdk).
582
+ This SDK provides wrappers that simplify interaction with these assets. For practical examples, please check our [examples](https://github.com/ton-community/assets-sdk/tree/main/examples) section.
583
+
333
584
## API Documentation
334
585
335
586
[Latest API documentation](https://ton-connect.github.io/sdk/modules/_tonconnect_ui_react.html)
0 commit comments