Skip to content

Commit 27eff91

Browse files
authored
fix: Ton improvements & tests (#589)
* fix: Ton related reports * fix: Update tests
1 parent fdcad03 commit 27eff91

File tree

12 files changed

+186
-42
lines changed

12 files changed

+186
-42
lines changed

android/lib/src/main/res/raw/trust_min.js

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bun.lockb

-5.31 KB
Binary file not shown.

packages/android-web3-provider/rollup.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import nodePolyfills from 'rollup-plugin-polyfill-node';
44
import inject from '@rollup/plugin-inject';
55
import babel from '@rollup/plugin-babel';
66
import resolve from '@rollup/plugin-node-resolve';
7+
import json from '@rollup/plugin-json';
78

89
const input = './src/index.ts';
910
const plugins = [
11+
json(),
1012
nodePolyfills(),
1113
resolve({ browser: true, preferBuiltins: false }),
1214
commonjs(),

packages/ios-web3-provider/rollup.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import commonjs from '@rollup/plugin-commonjs';
44
import { name, dependencies } from './package.json';
55
import nodePolyfills from 'rollup-plugin-polyfill-node';
66
import inject from '@rollup/plugin-inject';
7+
import json from '@rollup/plugin-json';
78

89
const input = './index.ts';
910
const plugins = [
11+
json(),
1012
nodeResolve({ preferBuiltins: false, browser: true }),
1113
commonjs(),
1214
inject({
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:22fd4dc4e47e287bfd169b531f87ec5c5ccd895d16d2b643900a2d90590b57f4
3-
size 669879
2+
oid sha256:896679567d498617820f725ae9427c7da33b080cab827431ed9bbcda8a539bd8
3+
size 1123201

packages/solana/SolanaProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'rpc-websockets/dist/lib/client';
2+
13
import {
24
BaseProvider,
35
IRequestArguments,

packages/solana/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"@wallet-standard/base": "1.1.0",
2525
"@wallet-standard/features": "1.0.3",
2626
"bs58": "4.0.1",
27-
"@trustwallet/web3-provider-core": "workspace:*"
27+
"@trustwallet/web3-provider-core": "workspace:*",
28+
"rpc-websockets": "7.11.0"
2829
},
2930
"devDependencies": {
3031
"@types/bs58": "^4.0.1"

packages/ton/MobileAdapter.ts

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Address, WalletContractV4 } from '@ton/ton';
2+
import { TonConnectError } from './exceptions/TonConnectError';
13
import { TonProvider } from './TonProvider';
24
import {
35
ConnectItemReply,
@@ -7,7 +9,21 @@ import {
79

810
interface ITransaction {
911
valid_until: number;
10-
messages: { state_init: string; address: string }[];
12+
messages: {
13+
stateInit: string;
14+
state_init: string;
15+
address: string;
16+
amount: string;
17+
}[];
18+
network: string;
19+
from: string;
20+
}
21+
22+
interface TransformedTransaction {
23+
messages: ITransaction['messages'];
24+
valid_until: number;
25+
network: string;
26+
from: string;
1127
}
1228

1329
/**
@@ -19,21 +35,23 @@ interface ITransaction {
1935
export class MobileAdapter {
2036
provider: TonProvider;
2137

38+
private rawAddress: string | null = null;
39+
2240
constructor(provider: TonProvider) {
2341
this.provider = provider;
2442
}
2543

26-
static mapToCamelCase(transaction: ITransaction) {
44+
static mapToCamelCase(transaction: ITransaction): TransformedTransaction {
2745
return {
2846
...transaction,
2947
...(transaction?.messages
3048
? {
31-
messages: (transaction?.messages || []).map(
32-
({ state_init, ...message }) => ({
33-
...message,
34-
stateInit: state_init,
35-
}),
36-
),
49+
messages: (transaction?.messages || []).map((message) => ({
50+
...message,
51+
...('state_init' in message || 'stateInit' in message
52+
? { stateInit: message.state_init || message.stateInit }
53+
: {}),
54+
})),
3755
}
3856
: {}),
3957
};
@@ -60,11 +78,16 @@ export class MobileAdapter {
6078
console.warn('type parameter removed from request');
6179
}
6280

81+
this.rawAddress = rest.address;
82+
6383
return rest;
6484
}
6585

6686
if (item.name === 'ton_proof') {
67-
const response = item as TonProofItemReplySuccess;
87+
const { type, ...response } = item as TonProofItemReplySuccess & {
88+
type?: string;
89+
};
90+
6891
return {
6992
...response,
7093
proof: {
@@ -83,17 +106,35 @@ export class MobileAdapter {
83106
'tonConnect_reconnect',
84107
params,
85108
);
86-
return JSON.parse(res);
109+
110+
const parsedResponse = JSON.parse(res);
111+
112+
const { nonBounceable, type, ...rest } =
113+
parsedResponse[0] as TonAddressItemReply & {
114+
nonBounceable: string;
115+
type?: string;
116+
};
117+
118+
this.rawAddress = rest.address;
119+
120+
return [rest] as T;
87121
}
88122

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

92126
case 'ton_sendTransaction':
93127
case 'tonConnect_sendTransaction': {
128+
const tx = (params as object[])[0] as ITransaction;
129+
130+
this.validateNetwork(tx);
131+
this.validateMessagesAddresses(tx);
132+
this.validateFromAddress(tx);
133+
this.validateTransaction(MobileAdapter.mapToCamelCase(tx));
134+
94135
const res = await this.provider.internalRequest<string>(
95136
'signTransaction',
96-
MobileAdapter.mapToCamelCase((params as object[])[0] as ITransaction),
137+
MobileAdapter.mapToCamelCase(tx),
97138
);
98139

99140
const { nonce, hash } = JSON.parse(res);
@@ -132,4 +173,71 @@ export class MobileAdapter {
132173
return this.provider.internalRequest(method, params);
133174
}
134175
}
176+
177+
validateTransaction(tx: TransformedTransaction) {
178+
// throw error if there is a message with empty state init
179+
if (
180+
tx.messages.some(
181+
(message) => 'stateInit' in message && message.stateInit.length === 0,
182+
)
183+
) {
184+
console.error('Empty state init in message');
185+
throw new TonConnectError('Bad request', 1);
186+
}
187+
188+
// throw error if there is a message with amount not being a string
189+
if (tx.messages.some((message) => typeof message.amount !== 'string')) {
190+
console.error('Invalid amount type');
191+
throw new TonConnectError('Bad request', 1);
192+
}
193+
194+
// throw error if valid until is not a number
195+
if (typeof tx.valid_until !== 'number') {
196+
console.error('Invalid valid_until type');
197+
throw new TonConnectError('Bad request', 1);
198+
}
199+
}
200+
201+
validateFromAddress(tx: ITransaction) {
202+
if (!this.rawAddress) {
203+
console.error('Trying to execute transaction with invalid address');
204+
throw new TonConnectError('Bad request', 1);
205+
}
206+
207+
const address = Address.parseRaw(this.rawAddress);
208+
209+
const collection = [
210+
address.toRawString(),
211+
address.toString({ bounceable: true }),
212+
address.toString({ bounceable: false }),
213+
];
214+
215+
if (!collection.includes(tx.from)) {
216+
console.error('from field does not match any user address');
217+
throw new TonConnectError('Bad request', 1);
218+
}
219+
}
220+
221+
/**
222+
* Validation on messages
223+
* @param tx
224+
*/
225+
validateMessagesAddresses(tx: ITransaction) {
226+
// Message addresses can not be raw
227+
if (tx.messages.some((e) => e.address.includes(':'))) {
228+
console.error('Bad request, message address is invalid');
229+
throw new TonConnectError('Bad request', 1);
230+
}
231+
}
232+
233+
/**
234+
* Enforce mainnet
235+
* @param tx
236+
*/
237+
validateNetwork(tx: ITransaction) {
238+
if (tx.network !== '-239') {
239+
console.error('Bad request, network id is invalid');
240+
throw new TonConnectError('Bad request', 1);
241+
}
242+
}
135243
}

packages/ton/TonBridge.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,21 @@ export class TonBridge implements TonConnectBridge {
8383
this.connectionAttempts += 1;
8484

8585
if ((items as any)?.event === 'connect_error') {
86-
return this.emit({ ...(items as any), id: this.connectionAttempts });
86+
return this.emit({
87+
...(items as any),
88+
id: this.connectionAttempts.toString(),
89+
});
8790
} else {
8891
return this.emit({
89-
id: this.connectionAttempts,
92+
id: this.connectionAttempts.toString(),
9093
event: 'connect',
9194
payload: { items, device: this.deviceInfo },
9295
});
9396
}
9497
} catch (e) {
95-
return this.parseError(e, { id: this.connectionAttempts });
98+
return this.parseError(e, {
99+
id: this.connectionAttempts.toString(),
100+
}) as WalletResponseError;
96101
}
97102
}
98103

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

131136
if ((items as any)?.event === 'connect_error') {
132-
return this.emit({ ...(items as any), id: this.connectionAttempts });
137+
return this.emit({
138+
...(items as any),
139+
id: this.connectionAttempts.toString(),
140+
});
133141
}
134142

135143
return this.emit({
136-
id: this.connectionAttempts,
144+
id: this.connectionAttempts.toString(),
137145
event: 'connect',
138146
payload: {
139147
items,
@@ -169,7 +177,9 @@ export class TonBridge implements TonConnectBridge {
169177

170178
return { result, id: message.id.toString() };
171179
} catch (e) {
172-
return this.parseError(e, { id: message.id });
180+
return this.parseError(e, {
181+
id: message.id.toString(),
182+
}) as WalletResponseError;
173183
}
174184
}
175185

@@ -193,7 +203,7 @@ export class TonBridge implements TonConnectBridge {
193203
message: 'User declined the transaction',
194204
code: 300,
195205
},
196-
id: String(message.id) ?? 0,
206+
id: String(message.id) ?? '0',
197207
};
198208
}
199209

@@ -204,7 +214,7 @@ export class TonBridge implements TonConnectBridge {
204214
message: 'Bad request, a transaction is already pending',
205215
code: 1,
206216
},
207-
id: String(message.id) ?? 0,
217+
id: String(message.id) ?? '0',
208218
};
209219
}
210220

@@ -218,13 +228,13 @@ export class TonBridge implements TonConnectBridge {
218228
message: 'User declined the transaction',
219229
code: 300,
220230
},
221-
id: String(message.id) ?? 0,
231+
id: String(message.id) ?? '0',
222232
};
223233
}
224234

225235
return {
226-
error: e as WalletResponseError['error'],
227-
id: String(message.id) ?? 0,
236+
error: formatConnectEventError(e as TonConnectError),
237+
id: String(message.id) ?? '0',
228238
};
229239
}
230240
}

packages/ton/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
},
2121
"peerDependencies": {},
2222
"dependencies": {
23+
"@ton/crypto": "3.3.0",
24+
"@ton/ton": "15.1.0",
2325
"@trustwallet/web3-provider-core": "workspace:*"
2426
}
2527
}

0 commit comments

Comments
 (0)