Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ton integration #12

Merged
merged 31 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d751f50
add: ton config
soumyaRouterP Aug 29, 2024
447313d
add: tonkeeper wallet connector
soumyaRouterP Aug 31, 2024
6b40905
fix: installed check in walletslist
soumyaRouterP Sep 1, 2024
4442ac0
add: disconnect
soumyaRouterP Sep 1, 2024
cf4aeac
add: manifesturl & wallet subscription
soumyaRouterP Sep 2, 2024
d135df7
update: connect handler
soumyaRouterP Sep 9, 2024
c6502de
fix: setConnectors logic
soumyaRouterP Sep 10, 2024
e2aa800
update: README.md
soumyaRouterP Sep 11, 2024
526b850
add: sendTransaction for ton chain
soumyaRouterP Sep 12, 2024
8a5100e
update: sendTransaction response tx.boc to hex
soumyaRouterP Sep 12, 2024
672b8f2
add: waitForTransaction action for ton chain
soumyaRouterP Sep 13, 2024
20de2e8
update: ton types
soumyaRouterP Sep 13, 2024
ad44aa2
add: tonClient to tonStore & updated the params for waitTx
soumyaRouterP Sep 13, 2024
7ef6268
fix: createTonStore props
soumyaRouterP Sep 13, 2024
2416439
Merge remote-tracking branch 'origin/main' into ton
soumyaRouterP Sep 13, 2024
d0d87ae
update: transactionParams
soumyaRouterP Sep 13, 2024
3029229
add: token metadata & balance fetch
soumyaRouterP Sep 13, 2024
caae9c3
fix: lint error
soumyaRouterP Sep 16, 2024
7942c31
update: chainId, mobile connection
soumyaRouterP Sep 17, 2024
8510e8e
update: chain id in tokens list (build error)
soumyaRouterP Sep 17, 2024
90faba8
fix: modal external wallet connection
soumyaRouterP Sep 18, 2024
1357b00
Merge remote-tracking branch 'origin/main' into ton
soumyaRouterP Sep 18, 2024
53a5b07
update: chain types
soumyaRouterP Sep 18, 2024
3ddda52
Merge remote-tracking branch 'origin/main' into ton
soumyaRouterP Sep 19, 2024
4e5f0cc
update: README.md
soumyaRouterP Sep 19, 2024
e2ff763
fix: moved walletslist to `TonProvider`
soumyaRouterP Sep 19, 2024
6c9daf3
fix: installed check & connection logic for different wallet options
soumyaRouterP Sep 19, 2024
035bdcc
fix: disconnect before connecting new wallet
soumyaRouterP Sep 19, 2024
8a2e3f8
remove: @ton/core & disconnect method type
soumyaRouterP Sep 20, 2024
1183ca8
Merge remote-tracking branch 'origin/main' into ton
soumyaRouterP Sep 20, 2024
6f19309
update: sendTransaction action return type
soumyaRouterP Sep 20, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function App({ Component, pageProps }) {
| Near | :x: | :x: | :x: | :x: | :x: |
| Bitcoin | :x: | :x: | :x: | :x: | :x: |
| Casper | :x: | :x: | :x: | :x: | :x: |
| Ton | :x: | :x: | :x: | :x: | :x: |
| Ton | :white_check_mark: | :x: | :x: | :x: | :x: |
| Algorand | :x: | :x: | :x: | :x: | :x: |

#### Hooks
Expand Down
5 changes: 5 additions & 0 deletions example-next/public/tonconnect-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"url": "http://localhost:3000",
"name": "Tangled3 Next Example",
"iconUrl": "https://ton.vote/logo.png"
}
2 changes: 2 additions & 0 deletions example-next/src/components/Providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const Providers = ({ children }: { children: ReactNode }) => {
},

projectId: '41980758771052df3f01be0a46f172a5',

tonconnectManifestUrl: `${window.location.origin}/tonconnect-manifest.json`,
}}
>
{children}
Expand Down
13 changes: 10 additions & 3 deletions example-next/src/components/Tokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,18 @@ const tokens: TokenMetadata[] = [
chainId: 'alephZero',
},
{
address: '5CMdxZDuprVZKnw6tEWjhEtK17Z52PUJo2dj1JLdyKeuUcfH',
address: ETH_ADDRESS,
decimals: 9,
name: 'Toncoin',
symbol: 'TON',
chainId: '-239',
},
{
address: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
decimals: 6,
name: 'USDT',
name: 'Tether USD',
symbol: 'USDT',
chainId: 'alephZero',
chainId: '-239',
},
];

Expand Down
2 changes: 1 addition & 1 deletion packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function App({ Component, pageProps }) {
| Near | :x: | :x: | :x: | :x: | :x: |
| Bitcoin | :x: | :x: | :x: | :x: | :x: |
| Casper | :x: | :x: | :x: | :x: | :x: |
| Ton | :x: | :x: | :x: | :x: | :x: |
| Ton | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Algorand | :x: | :x: | :x: | :x: | :x: |

#### Hooks
Expand Down
2 changes: 2 additions & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"@solana/web3.js": "^1.94.0",
"@tangled3/solana-react": "workspace:*",
"@tanstack/react-query": "^5.44.0",
"@ton/ton": "^15.0.0",
"@tonconnect/ui-react": "^2.0.9",
"@tronweb3/tronwallet-abstract-adapter": "^1.1.6",
"@tronweb3/tronwallet-adapters": "^1.2.1",
"@wagmi/core": "^2.11.0",
Expand Down
21 changes: 21 additions & 0 deletions packages/react/src/actions/getToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { areTokensEqual } from '../utils/index.js';
import { getAlephZeroTokenBalanceAndAllowance, getAlephZeroTokenMetadata } from './alephZero/getAlephZeroToken.js';
import { getEVMTokenBalanceAndAllowance, getEVMTokenMetadata } from './evm/getEVMToken.js';
import { getSolanaTokenBalanceAndAllowance } from './solana/getSolanaToken.js';
import { getTonTokenBalanceAndAllowance, getTonTokenMetadata } from './ton/getTonToken.js';

/**
* Get token metadata
Expand Down Expand Up @@ -83,6 +84,17 @@ export const getTokenMetadata = async ({ token, chain, config }: GetTokenMetadat
};
}

if (chain.type === 'ton') {
if (areTokensEqual(token, ETH_ADDRESS)) {
return { ...chain.nativeCurrency, address: ETH_ADDRESS, chainId: chain.id };
}
const res = await getTonTokenMetadata({ token, chainId: chain.id });
return {
...res,
chainId: chain.id,
};
}

throw new Error('Chain type not supported');
};

Expand Down Expand Up @@ -177,5 +189,14 @@ export const getTokenBalanceAndAllowance = (async (params) => {
});
}

if (chain.type === 'ton') {
return getTonTokenBalanceAndAllowance({
account,
token,
spender,
config,
});
}

throw new Error('Chain type not supported');
}) as GetTokenBalanceAndAllowanceFunction;
46 changes: 45 additions & 1 deletion packages/react/src/actions/sendTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Signer, SubmittableExtrinsic } from '@polkadot/api/types';
import { VersionedTransaction as SolanaVersionedTransaction } from '@solana/web3.js';
import { Cell } from '@ton/ton';
import { CHAIN } from '@tonconnect/ui-react';
import { sendTransaction as sendEVMTransaction } from '@wagmi/core';
import { Address as EVMAddress } from 'viem';
import { ChainData, ChainType, ConnectionOrConfig } from '../types/index.js';
Expand Down Expand Up @@ -29,7 +31,16 @@ type TransactionArgs<CType extends ChainType> = CType extends 'evm' | 'tron'
? {
submittableExtrinsic: SubmittableExtrinsic<'promise' | 'rxjs'>;
}
: never;
: CType extends 'ton'
? {
tonArgs: {
validUntil: number; // transaction deadline in unix epoch seconds.
network?: CHAIN; // (MAINNET: "-239" & TESTNET: "-3")
payload?: string;
stateInit?: string;
};
}
: never;

type SendTransactionReturnType<C extends ChainType> = C extends 'alephZero'
? {
Expand Down Expand Up @@ -136,5 +147,38 @@ export const sendTransactionToChain = (async ({ chain, to, from, value, args, co
};
}

if (chain.type === 'ton') {
const { tonArgs } = args as TransactionArgs<'ton'>;
const messages: Array<{
address: string;
amount: string;
payload?: string;
stateInit?: string;
}> = [
{
address: to,
amount: value.toString(),
payload: tonArgs.payload,
stateInit: tonArgs.stateInit,
},
];
const transaction = {
from,
messages,
network: tonArgs.network,
validUntil: tonArgs.validUntil,
};

const walletConnector = config.connector as WalletInstance<'ton'>;
// send transaction to TON chain
const tx = await walletConnector.sendTransaction(transaction);

const cell = Cell.fromBase64(tx.boc);
const buffer = cell.hash();
const hashHex = buffer.toString('hex');

return { txHash: hashHex };
}

throw new Error('Chain not supported');
}) as SendTransactionToChainFunction;
9 changes: 9 additions & 0 deletions packages/react/src/actions/ton/getTonClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TonClient } from '@ton/ton';
import { OtherChainData } from '../../types/index.js';

export const getTonClient = (chain: OtherChainData<'ton'>) => {
const tonClient = new TonClient({
endpoint: chain.rpcUrls.default.http[0] ?? '',
});
return tonClient;
};
54 changes: 54 additions & 0 deletions packages/react/src/actions/ton/getTonToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Address, JettonMaster } from '@ton/ton';
import { CHAIN } from '@tonconnect/ui-react';
import { ChainId, ConnectionOrConfig } from '../../types/index.js';

export const getTonTokenMetadata = async ({ token, chainId }: { token: string; chainId: ChainId }) => {
const data = await (
await fetch(
chainId === CHAIN.MAINNET
? `https://toncenter.com/api/v3/jetton/masters?address=${token}&limit=128&offset=0`
: `https://testnet.toncenter.com/api/v3/jetton/masters?address=${token}&limit=128&offset=0`,
)
).json();

const jettonContent = data.jetton_masters[0].jetton_content;

return {
symbol: jettonContent.symbol ?? 'USDT',
name: jettonContent.name ?? 'Tether USD',
decimals: Number(jettonContent.decimals),
address: jettonContent.address ?? token,
};
};

export const getTonTokenBalanceAndAllowance = async ({
account,
token,
config,
}: {
account: string;
token: string;
spender: string | undefined;
config: ConnectionOrConfig;
}) => {
let balance = 0n;
const allowance = 0n;

try {
const jettonMaster = new JettonMaster(Address.parse(token));
const contractProvider = config.tonClient.provider(Address.parse(token));

const walletAddress = await jettonMaster.getWalletAddress(contractProvider, Address.parse(account));

const walletAddressContractCallResult = await config.tonClient.runMethod(walletAddress, 'get_wallet_data');
const accountBalance = walletAddressContractCallResult.stack.readNumber();
balance = BigInt(accountBalance);
} catch (error) {
console.error('error - ', error);
}

return {
balance,
allowance,
};
};
28 changes: 27 additions & 1 deletion packages/react/src/actions/waitForTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Address } from '@ton/ton';
import { waitForTransactionReceipt } from '@wagmi/core';
import { ReplacementReturnType } from 'viem';
import { ChainData, ChainType, ConnectionOrConfig, TransactionReceipt } from '../types/index.js';
Expand All @@ -19,7 +20,12 @@ export type WatchTransactionOverrides<C extends ChainType> = DefaultOverrides &
? {
maxSupportedTransactionVersion: number;
}
: any);
: C extends 'ton'
? {
accountAddress: string;
lt: string;
}
: any);

export type DefaultTransactionParams = {
txHash: string;
Expand Down Expand Up @@ -157,5 +163,25 @@ export const waitForTransaction = (async ({ chain, config, overrides, transactio
return receipt;
}

if (chain.type === 'ton') {
const _overrides = (overrides || {}) as WatchTransactionOverrides<'ton'>;
const { txHash } = transactionParams as TransactionParams<'ton'>;

const receipt = await pollCallback(
async () => {
return await config.tonClient.getTransaction(Address.parse(_overrides.accountAddress), _overrides.lt, txHash);
},
{
interval: overrides?.interval || DEFAULT_POLLING_INTERVAL,
timeout: overrides?.timeout,
},
);

if (!receipt) {
throw new Error('Transaction not found');
}
return receipt;
}

throw new Error('Chain not supported');
}) as WatchTransactionFunction;
1 change: 1 addition & 0 deletions packages/react/src/chains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export * from './evm.testnet.js';
export * from './solana.devnet.js';
export * from './solana.js';
export * from './solana.testnet.js';
export * from './ton.js';
export * from './tron.js';
export * from './tron.shasta.js';
25 changes: 25 additions & 0 deletions packages/react/src/chains/ton.testnet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { CHAIN } from '@tonconnect/ui-react';
import { ChainData } from '../types/index.js';

export const tonTestnet: ChainData = {
id: CHAIN.TESTNET, // '-3'
name: 'Ton Testnet',
type: 'ton',
nativeCurrency: {
name: 'TON',
symbol: 'TON',
decimals: 9,
},
rpcUrls: {
default: {
http: ['https://testnet.toncenter.com/api/v2/jsonRPC'],
webSocket: [''],
},
},
blockExplorers: {
default: {
name: 'Tonscan',
url: 'https://testnet.tonscan.org/',
},
},
} as const;
25 changes: 25 additions & 0 deletions packages/react/src/chains/ton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { CHAIN } from '@tonconnect/ui-react';
import { OtherChainData } from '../types/index.js';

export const tonMainnet: OtherChainData<'ton'> = {
id: CHAIN.MAINNET, // '-239'
name: 'Ton',
type: 'ton',
nativeCurrency: {
name: 'TON',
symbol: 'TON',
decimals: 9,
},
rpcUrls: {
default: {
http: ['https://toncenter.com/api/v2/jsonRPC'],
webSocket: [''],
},
},
blockExplorers: {
default: {
name: 'Tonscan',
url: 'https://tonscan.org/',
},
},
} as const;
Loading
Loading