Skip to content

Commit

Permalink
fix: Ton improvements & tests (#589)
Browse files Browse the repository at this point in the history
* fix: Ton related reports

* fix: Update tests
  • Loading branch information
y3fers0n authored Dec 13, 2024
1 parent fdcad03 commit 27eff91
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 42 deletions.
14 changes: 7 additions & 7 deletions android/lib/src/main/res/raw/trust_min.js

Large diffs are not rendered by default.

Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions packages/android-web3-provider/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import nodePolyfills from 'rollup-plugin-polyfill-node';
import inject from '@rollup/plugin-inject';
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import json from '@rollup/plugin-json';

const input = './src/index.ts';
const plugins = [
json(),
nodePolyfills(),
resolve({ browser: true, preferBuiltins: false }),
commonjs(),
Expand Down
2 changes: 2 additions & 0 deletions packages/ios-web3-provider/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import commonjs from '@rollup/plugin-commonjs';
import { name, dependencies } from './package.json';
import nodePolyfills from 'rollup-plugin-polyfill-node';
import inject from '@rollup/plugin-inject';
import json from '@rollup/plugin-json';

const input = './index.ts';
const plugins = [
json(),
nodeResolve({ preferBuiltins: false, browser: true }),
commonjs(),
inject({
Expand Down
4 changes: 2 additions & 2 deletions packages/ios-web3-provider/swift/trust-min.js
Git LFS file not shown
2 changes: 2 additions & 0 deletions packages/solana/SolanaProvider.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'rpc-websockets/dist/lib/client';

import {
BaseProvider,
IRequestArguments,
Expand Down
3 changes: 2 additions & 1 deletion packages/solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"@wallet-standard/base": "1.1.0",
"@wallet-standard/features": "1.0.3",
"bs58": "4.0.1",
"@trustwallet/web3-provider-core": "workspace:*"
"@trustwallet/web3-provider-core": "workspace:*",
"rpc-websockets": "7.11.0"
},
"devDependencies": {
"@types/bs58": "^4.0.1"
Expand Down
130 changes: 119 additions & 11 deletions packages/ton/MobileAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Address, WalletContractV4 } from '@ton/ton';
import { TonConnectError } from './exceptions/TonConnectError';
import { TonProvider } from './TonProvider';
import {
ConnectItemReply,
Expand All @@ -7,7 +9,21 @@ import {

interface ITransaction {
valid_until: number;
messages: { state_init: string; address: string }[];
messages: {
stateInit: string;
state_init: string;
address: string;
amount: string;
}[];
network: string;
from: string;
}

interface TransformedTransaction {
messages: ITransaction['messages'];
valid_until: number;
network: string;
from: string;
}

/**
Expand All @@ -19,21 +35,23 @@ interface ITransaction {
export class MobileAdapter {
provider: TonProvider;

private rawAddress: string | null = null;

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

static mapToCamelCase(transaction: ITransaction) {
static mapToCamelCase(transaction: ITransaction): TransformedTransaction {
return {
...transaction,
...(transaction?.messages
? {
messages: (transaction?.messages || []).map(
({ state_init, ...message }) => ({
...message,
stateInit: state_init,
}),
),
messages: (transaction?.messages || []).map((message) => ({
...message,
...('state_init' in message || 'stateInit' in message
? { stateInit: message.state_init || message.stateInit }
: {}),
})),
}
: {}),
};
Expand All @@ -60,11 +78,16 @@ export class MobileAdapter {
console.warn('type parameter removed from request');
}

this.rawAddress = rest.address;

return rest;
}

if (item.name === 'ton_proof') {
const response = item as TonProofItemReplySuccess;
const { type, ...response } = item as TonProofItemReplySuccess & {
type?: string;
};

return {
...response,
proof: {
Expand All @@ -83,17 +106,35 @@ export class MobileAdapter {
'tonConnect_reconnect',
params,
);
return JSON.parse(res);

const parsedResponse = JSON.parse(res);

const { nonBounceable, type, ...rest } =
parsedResponse[0] as TonAddressItemReply & {
nonBounceable: string;
type?: string;
};

this.rawAddress = rest.address;

return [rest] as T;
}

case 'ton_rawSign':
return this.provider.internalRequest<T>('signMessage', params);

case 'ton_sendTransaction':
case 'tonConnect_sendTransaction': {
const tx = (params as object[])[0] as ITransaction;

this.validateNetwork(tx);
this.validateMessagesAddresses(tx);
this.validateFromAddress(tx);
this.validateTransaction(MobileAdapter.mapToCamelCase(tx));

const res = await this.provider.internalRequest<string>(
'signTransaction',
MobileAdapter.mapToCamelCase((params as object[])[0] as ITransaction),
MobileAdapter.mapToCamelCase(tx),
);

const { nonce, hash } = JSON.parse(res);
Expand Down Expand Up @@ -132,4 +173,71 @@ export class MobileAdapter {
return this.provider.internalRequest(method, params);
}
}

validateTransaction(tx: TransformedTransaction) {
// throw error if there is a message with empty state init
if (
tx.messages.some(
(message) => 'stateInit' in message && message.stateInit.length === 0,
)
) {
console.error('Empty state init in message');
throw new TonConnectError('Bad request', 1);
}

// throw error if there is a message with amount not being a string
if (tx.messages.some((message) => typeof message.amount !== 'string')) {
console.error('Invalid amount type');
throw new TonConnectError('Bad request', 1);
}

// throw error if valid until is not a number
if (typeof tx.valid_until !== 'number') {
console.error('Invalid valid_until type');
throw new TonConnectError('Bad request', 1);
}
}

validateFromAddress(tx: ITransaction) {
if (!this.rawAddress) {
console.error('Trying to execute transaction with invalid address');
throw new TonConnectError('Bad request', 1);
}

const address = Address.parseRaw(this.rawAddress);

const collection = [
address.toRawString(),
address.toString({ bounceable: true }),
address.toString({ bounceable: false }),
];

if (!collection.includes(tx.from)) {
console.error('from field does not match any user address');
throw new TonConnectError('Bad request', 1);
}
}

/**
* Validation on messages
* @param tx
*/
validateMessagesAddresses(tx: ITransaction) {
// Message addresses can not be raw
if (tx.messages.some((e) => e.address.includes(':'))) {
console.error('Bad request, message address is invalid');
throw new TonConnectError('Bad request', 1);
}
}

/**
* Enforce mainnet
* @param tx
*/
validateNetwork(tx: ITransaction) {
if (tx.network !== '-239') {
console.error('Bad request, network id is invalid');
throw new TonConnectError('Bad request', 1);
}
}
}
32 changes: 21 additions & 11 deletions packages/ton/TonBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,21 @@ export class TonBridge implements TonConnectBridge {
this.connectionAttempts += 1;

if ((items as any)?.event === 'connect_error') {
return this.emit({ ...(items as any), id: this.connectionAttempts });
return this.emit({
...(items as any),
id: this.connectionAttempts.toString(),
});
} else {
return this.emit({
id: this.connectionAttempts,
id: this.connectionAttempts.toString(),
event: 'connect',
payload: { items, device: this.deviceInfo },
});
}
} catch (e) {
return this.parseError(e, { id: this.connectionAttempts });
return this.parseError(e, {
id: this.connectionAttempts.toString(),
}) as WalletResponseError;
}
}

Expand Down Expand Up @@ -129,11 +134,14 @@ export class TonBridge implements TonConnectBridge {
this.connectionAttempts += 1;

if ((items as any)?.event === 'connect_error') {
return this.emit({ ...(items as any), id: this.connectionAttempts });
return this.emit({
...(items as any),
id: this.connectionAttempts.toString(),
});
}

return this.emit({
id: this.connectionAttempts,
id: this.connectionAttempts.toString(),
event: 'connect',
payload: {
items,
Expand Down Expand Up @@ -169,7 +177,9 @@ export class TonBridge implements TonConnectBridge {

return { result, id: message.id.toString() };
} catch (e) {
return this.parseError(e, { id: message.id });
return this.parseError(e, {
id: message.id.toString(),
}) as WalletResponseError;
}
}

Expand All @@ -193,7 +203,7 @@ export class TonBridge implements TonConnectBridge {
message: 'User declined the transaction',
code: 300,
},
id: String(message.id) ?? 0,
id: String(message.id) ?? '0',
};
}

Expand All @@ -204,7 +214,7 @@ export class TonBridge implements TonConnectBridge {
message: 'Bad request, a transaction is already pending',
code: 1,
},
id: String(message.id) ?? 0,
id: String(message.id) ?? '0',
};
}

Expand All @@ -218,13 +228,13 @@ export class TonBridge implements TonConnectBridge {
message: 'User declined the transaction',
code: 300,
},
id: String(message.id) ?? 0,
id: String(message.id) ?? '0',
};
}

return {
error: e as WalletResponseError['error'],
id: String(message.id) ?? 0,
error: formatConnectEventError(e as TonConnectError),
id: String(message.id) ?? '0',
};
}
}
2 changes: 2 additions & 0 deletions packages/ton/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
},
"peerDependencies": {},
"dependencies": {
"@ton/crypto": "3.3.0",
"@ton/ton": "15.1.0",
"@trustwallet/web3-provider-core": "workspace:*"
}
}
Loading

0 comments on commit 27eff91

Please sign in to comment.