Skip to content

Commit

Permalink
feat: add ton connect provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Ikari-Shinji-re committed Nov 27, 2024
1 parent 25f4b7a commit a8c4183
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 9 deletions.
1 change: 1 addition & 0 deletions wallets/provider-all/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@rango-dev/provider-taho": "^0.39.0",
"@rango-dev/provider-tokenpocket": "^0.39.0",
"@rango-dev/provider-tomo": "^0.6.0",
"@rango-dev/provider-tonconnect": "^0.1.0",
"@rango-dev/provider-mytonwallet": "^0.24.1-next.0",
"@rango-dev/provider-trezor": "^0.6.0",
"@rango-dev/provider-tron-link": "^0.39.1-next.0",
Expand Down
17 changes: 15 additions & 2 deletions wallets/provider-all/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Environments as MyTonWalletEnvironments } from '@rango-dev/provider-mytonwallet';
import type { Environments as TonConnectEnvironments } from '@rango-dev/provider-tonconnect';
import type { Environments as TrezorEnvironments } from '@rango-dev/provider-trezor';
import type { Environments as WalletConnectEnvironments } from '@rango-dev/provider-walletconnect-2';
import type { ProviderInterface } from '@rango-dev/wallets-react';
Expand Down Expand Up @@ -32,6 +32,7 @@ import * as solflareSnap from '@rango-dev/provider-solflare-snap';
import * as taho from '@rango-dev/provider-taho';
import * as tokenpocket from '@rango-dev/provider-tokenpocket';
import * as tomo from '@rango-dev/provider-tomo';
import * as tonconnect from '@rango-dev/provider-tonconnect';
import * as trezor from '@rango-dev/provider-trezor';
import * as tronLink from '@rango-dev/provider-tron-link';
import * as trustwallet from '@rango-dev/provider-trustwallet';
Expand All @@ -45,7 +46,7 @@ interface Options {
walletconnect2: WalletConnectEnvironments;
selectedProviders?: (WalletType | ProviderInterface)[];
trezor?: TrezorEnvironments;
tonConnect?: MyTonWalletEnvironments;
tonConnect?: TonConnectEnvironments;
}

export const allProviders = (options?: Options) => {
Expand Down Expand Up @@ -88,12 +89,24 @@ export const allProviders = (options?: Options) => {
}
}

if (
!isWalletExcluded(providers, {
type: WalletTypes.TON_CONNECT,
name: 'tonconnect',
})
) {
if (!!options?.tonConnect?.manifestUrl) {
tonconnect.init(options.tonConnect);
}
}

return [
safe,
defaultInjected,
metamask,
solflareSnap,
walletconnect2,
tonconnect,
keplr,
phantom,
argentx,
Expand Down
36 changes: 36 additions & 0 deletions wallets/provider-tonconnect/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@rango-dev/provider-tonconnect",
"version": "0.1.0",
"license": "MIT",
"type": "module",
"source": "./src/index.ts",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"typings": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"build": "node ../../scripts/build/command.mjs --path wallets/provider-tonconnect",
"ts-check": "tsc --declaration --emitDeclarationOnly -p ./tsconfig.json",
"clean": "rimraf dist",
"format": "prettier --write '{.,src}/**/*.{ts,tsx}'",
"lint": "eslint \"**/*.{ts,tsx}\" --ignore-path ../../.eslintignore"
},
"dependencies": {
"@rango-dev/wallets-shared": "^0.39.0",
"@ton/core": "^0.59.0",
"@ton/crypto": "^3.3.0",
"@tonconnect/ui": "^2.0.9",
"rango-types": "^0.1.75"
},
"publishConfig": {
"access": "public"
}
}
3 changes: 3 additions & 0 deletions wallets/provider-tonconnect/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @rango-dev/provider-tonconnect

TonConnect
47 changes: 47 additions & 0 deletions wallets/provider-tonconnect/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { TonConnectUI } from '@tonconnect/ui';

export async function getTonConnectUIModule() {
const tonConnectUI = await import('@tonconnect/ui');
return tonConnectUI;
}

export async function getTonCoreModule() {
const tonCore = await import('@ton/core');
return tonCore;
}

export async function waitForConnection(
tonConnectUI: TonConnectUI
): Promise<string> {
return new Promise((resolve, reject) => {
const unsubscribeStatusChange = tonConnectUI.onStatusChange(
(state) => {
const walletConnected = !!state?.account.address;

if (walletConnected) {
unsubscribeStatusChange();
resolve(state.account.address);
}
},
(error) => {
unsubscribeStatusChange();
reject(error);
}
);

const unsubscribeModalStateChange = tonConnectUI.onModalStateChange(
(modalState) => {
if (modalState.closeReason === 'action-cancelled') {
unsubscribeStatusChange();
unsubscribeModalStateChange();
reject(new Error('The action was canceled by the user'));
}
}
);
});
}

export async function parseAddress(rawAddress: string): Promise<string> {
const tonCore = await getTonCoreModule();
return tonCore.Address.parse(rawAddress).toString({ bounceable: false });
}
97 changes: 97 additions & 0 deletions wallets/provider-tonconnect/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { Environments } from './types.js';
import type {
CanEagerConnect,
CanSwitchNetwork,
Connect,
Disconnect,
GetInstance,
WalletInfo,
} from '@rango-dev/wallets-shared';
import type { TonConnectUI } from '@tonconnect/ui';
import type { BlockchainMeta, SignerFactory } from 'rango-types';

import { Networks, WalletTypes } from '@rango-dev/wallets-shared';
import { tonBlockchain } from 'rango-types';

import {
getTonConnectUIModule,
parseAddress,
waitForConnection,
} from './helpers.js';
import signer from './signer.js';

let envs: Environments = {
manifestUrl: '',
};

const WALLET = WalletTypes.TON_CONNECT;

export const config = {
type: WALLET,
isAsyncInstance: true,
checkInstallation: false,
};

export type { Environments };

export const init = (environments: Environments) => {
envs = environments;
};

let instance: TonConnectUI | null = null;

export const getInstance: GetInstance = async () => {
if (!instance) {
const { TonConnectUI } = await getTonConnectUIModule();
instance = new TonConnectUI(envs);
}
return instance;
};

export const connect: Connect = async ({ instance }) => {
const tonConnectUI: TonConnectUI = instance;
const connectionRestored = await tonConnectUI.connectionRestored;

if (connectionRestored && tonConnectUI.account?.address) {
const parsedAddress = await parseAddress(tonConnectUI.account.address);
return { accounts: [parsedAddress], chainId: Networks.TON };
}

await tonConnectUI.openModal();
const result = await waitForConnection(tonConnectUI);
const parsedAddress = await parseAddress(result);

return {
accounts: [parsedAddress],
chainId: Networks.TON,
};
};

export const canEagerConnect: CanEagerConnect = async ({ instance }) => {
const tonConnectUI = instance as TonConnectUI;
const connectionRestored = await tonConnectUI.connectionRestored;
return connectionRestored;
};

export const canSwitchNetworkTo: CanSwitchNetwork = () => false;

export const getSigners: (provider: TonConnectUI) => Promise<SignerFactory> =
signer;

export const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (
allBlockChains
) => {
const ton = tonBlockchain(allBlockChains);
return {
name: 'TON Connect',
img: 'https://raw.githubusercontent.com/rango-exchange/assets/7fb19ed5d5019b4d6a41ce91b39cde64f86af4c6/wallets/tonconnect/icon.svg',
installLink: '',
color: '#fff',
supportedChains: ton,
};
};

export const disconnect: Disconnect = async ({ instance }) => {
const tonConnectUI = instance as TonConnectUI;
await tonConnectUI.disconnect();
};
13 changes: 13 additions & 0 deletions wallets/provider-tonconnect/src/signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { TonConnectUI } from '@tonconnect/ui';
import type { SignerFactory } from 'rango-types';

import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';

export default async function getSigners(
provider: TonConnectUI
): Promise<SignerFactory> {
const signers = new DefaultSignerFactory();
const { CustomTonSigner } = await import('./ton-signer.js');
signers.registerSigner(TxType.TON, new CustomTonSigner(provider));
return signers;
}
29 changes: 29 additions & 0 deletions wallets/provider-tonconnect/src/ton-signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { TonConnectUI } from '@tonconnect/ui';
import type { GenericSigner, TonTransaction } from 'rango-types';

import { Cell } from '@ton/core';
import { CHAIN } from '@tonconnect/ui';
import { SignerError } from 'rango-types';

export class CustomTonSigner implements GenericSigner<TonTransaction> {
private provider: TonConnectUI;

constructor(provider: TonConnectUI) {
this.provider = provider;
}

async signMessage(): Promise<string> {
throw SignerError.UnimplementedError('signMessage');
}

async signAndSendTx(tx: TonTransaction): Promise<{ hash: string }> {
const { blockChain, type, ...txObjectForSign } = tx;
const result = await this.provider.sendTransaction({
...txObjectForSign,
network: CHAIN.MAINNET,
});

const hash = Cell.fromBase64(result.boc).hash().toString('hex');
return { hash };
}
}
3 changes: 3 additions & 0 deletions wallets/provider-tonconnect/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Environments extends Record<string, string | undefined> {
manifestUrl: string;
}
9 changes: 9 additions & 0 deletions wallets/provider-tonconnect/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.libnext.json",
"include": ["src", "types", "../../global-wallets-env.d.ts"],
"compilerOptions": {
"outDir": "dist",
"rootDir": "./src",
"lib": ["dom", "esnext"]
}
}
1 change: 1 addition & 0 deletions wallets/provider-tonconnect/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "extends": "./tsconfig.build.json", "include": ["src", "tests"] }
1 change: 1 addition & 0 deletions wallets/shared/src/rango.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export enum WalletTypes {
TOMO = 'tomo',
TREZOR = 'trezor',
SOLFLARE = 'solflare',
TON_CONNECT = 'tonconnect',
}

export const namespaces: Record<
Expand Down
10 changes: 10 additions & 0 deletions widget/playground/src/utils/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ export function filterConfig(
filteredConfigForExport.tonConnect = config.tonConnect;
}

const isTonconnectNeeded = isWalletConfigNeeded(
filteredConfigForExport,
'tonConnect',
'tonconnect'
);

if (isTonconnectNeeded) {
filteredConfigForExport.tonConnect = config.tonConnect;
}

return { userSelectedConfig, filteredConfigForExport };
}

Expand Down
Loading

0 comments on commit a8c4183

Please sign in to comment.