Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
db62a43
feat(onekey): support Sui, Stellar, TON, TRON, Cardano and NEAR
hippocampusSK Oct 28, 2026
65fad9e
refactor(wallet-extensions): share the TON Connect flow between OKX a…
hippocampusSK Oct 29, 2026
c1f469f
Merge remote-tracking branch 'origin/develop' into feature/onekey-mul…
hippocampusSK Nov 3, 2026
64941e0
fix(onekey): connect one network at a time and stop when the user can…
hippocampusSK Nov 3, 2026
5de1d66
test(onekey): reset the TON Connect manifest after the manifest error…
hippocampusSK Nov 3, 2026
3aa83bd
fix(onekey): read the TRON address from OneKey instead of its injecte…
hippocampusSK Nov 3, 2026
aabb2f0
refactor(onekey): move Sui support to its own pull request
hippocampusSK Nov 3, 2026
968de86
feat(onekey): support Sui
hippocampusSK Nov 3, 2026
f210ab9
refactor(onekey): move Cardano support to its own pull request
hippocampusSK Nov 3, 2026
a8d462e
Merge branch 'feature/onekey-multichain-support' into feature/onekey-…
hippocampusSK Nov 3, 2026
160f5ea
fix(onekey): stop the connection on EVM cancels and only on real reje…
hippocampusSK Nov 3, 2026
e9ce17f
Merge branch 'feature/onekey-multichain-support' into feature/onekey-…
hippocampusSK Nov 3, 2026
3e95b22
fix(onekey): connect TRON after OneKey's first approval and sign with…
hippocampusSK Nov 3, 2026
34ce3ae
Merge branch 'feature/onekey-multichain-support' into feature/onekey-…
hippocampusSK Nov 3, 2026
24d1522
fix(onekey): keep TRON's signature check on the transaction that was …
hippocampusSK Nov 3, 2026
dd034f4
Merge branch 'feature/onekey-multichain-support' into feature/onekey-…
hippocampusSK Nov 3, 2026
5aa894c
Merge remote-tracking branch 'origin/develop' into feature/onekey-mul…
hippocampusSK Nov 3, 2026
290f2cd
Merge branch 'feature/onekey-multichain-support' into feature/onekey-…
hippocampusSK Nov 3, 2026
56d26d1
Merge branch 'develop' into feature/onekey-sui-support
hippocampusSK Nov 4, 2026
0af4606
refactor(onekey): compare the Sui bytes OneKey signed directly
hippocampusSK Nov 4, 2026
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
5 changes: 5 additions & 0 deletions .changeset/onekey-sui-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@swapkit/wallet-extensions": minor
---

OneKey now connects Sui on mainnet. A Sui signature from OneKey is rejected if it covers a different transaction than the one requested.
34 changes: 34 additions & 0 deletions packages/wallet-extensions/src/onekey/__tests__/onekey.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Chain, SKConfig } from "@swapkit/helpers";
import { getWalletMethods } from "../helpers";
import { onekeyWallet } from "../index";

const SUI_ADDRESS = `0x${"ab".repeat(32)}`;
const TRON_ADDRESS = "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8";

afterEach(() => {
Expand All @@ -34,6 +35,39 @@ function stellarPayment(source: Keypair, amount: string) {
.build();
}

describe("OneKey Sui signer", () => {
function mockSui(signTransaction) {
globalThis.window = {
$onekey: { sui: { getAccounts: async () => [{ address: SUI_ADDRESS, publicKey: "" }], signTransaction } },
};
}

test("sends the exact transaction bytes and returns the wallet signature", async () => {
const txBytes = new Uint8Array([1, 2, 3, 4]);
let request: Record<string, any> | undefined;
mockSui((input) => {
request = input;
return Promise.resolve({ bytes: input.transaction.serialize(), signature: "wallet-signature" });
});

const wallet = await getWalletMethods(Chain.Sui);
const signed = await wallet.signTransaction(txBytes);

expect(request.chain).toBe("sui:mainnet");
expect(request.account.address).toBe(SUI_ADDRESS);
expect(base64.decode(request.transaction.serialize())).toEqual(txBytes);
expect(signed).toEqual({ bytes: base64.encode(txBytes), signature: "wallet-signature" });
});

test("rejects a signature over different bytes", async () => {
mockSui(async () => ({ bytes: base64.encode(new Uint8Array([9, 9])), signature: "wallet-signature" }));

const wallet = await getWalletMethods(Chain.Sui);

await expect(wallet.signTransaction(new Uint8Array([1, 2, 3, 4]))).rejects.toThrow("different transaction");
});
});

describe("OneKey Tron signer", () => {
function mockTron(sign, requestAccountsCode = 200) {
globalThis.window = {
Expand Down
34 changes: 34 additions & 0 deletions packages/wallet-extensions/src/onekey/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { base64, hex } from "@scure/base";
import { Chain, type EVMChain, EVMChains, prepareNetworkSwitch, SwapKitError, WalletOption } from "@swapkit/helpers";
import type { NearSigner } from "@swapkit/toolboxes/near";
import type { StellarSigner } from "@swapkit/toolboxes/stellar";
import type { SuiChainSigner } from "@swapkit/toolboxes/sui";
import type { TronSigner } from "@swapkit/toolboxes/tron";
import { Transaction } from "@swapkit/utxo-signer";
import { getTonConnectWallet } from "../helpers/tonConnect";
import { getUtxoScriptTypeParams } from "../helpers/utxoScriptType";

const SUI_MAINNET = "sui:mainnet";

type WalletMethodsWithAddress = Record<string, unknown> & { address: string };

const TRON_USER_REJECTED = 4000;
Expand Down Expand Up @@ -86,6 +89,35 @@ async function getEvmWalletMethods(chain: EVMChain) {
return { address, ...prepareNetworkSwitch({ chain, provider, toolbox }) };
}

async function getSuiWalletMethods() {
const provider = getProvider("sui", Chain.Sui);
const [account] = await provider.getAccounts();
if (!account?.address) throw connectionRejectedError(Chain.Sui);

const { getSuiToolbox } = await import("@swapkit/toolboxes/sui");

const signer: SuiChainSigner = {
getAddress: () => Promise.resolve(account.address),
signTransaction: async (txBytes: Uint8Array) => {
const serialized = base64.encode(txBytes);
const result = await provider.signTransaction({
account,
chain: SUI_MAINNET,
transaction: { serialize: () => serialized },
});

if (result.bytes !== serialized) {
throw signingError(Chain.Sui, "OneKey signed a different transaction than the one requested");
}

return { bytes: serialized, signature: result.signature };
},
toSuiAddress: () => account.address,
};

return { ...getSuiToolbox({ signer }), address: account.address };
}

async function getTronWalletMethods() {
const provider = getProvider("tron", Chain.Tron);
const response = await provider.request({ method: "tron_requestAccounts" });
Expand Down Expand Up @@ -217,6 +249,8 @@ export function getWalletMethods(chain: Chain): Promise<WalletMethodsWithAddress
return getSolanaWalletMethods();
case Chain.Stellar:
return getStellarWalletMethods();
case Chain.Sui:
return getSuiWalletMethods();
case Chain.Ton:
return getTonWalletMethods();
case Chain.Tron:
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet-extensions/src/onekey/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const onekeyWallet: ExtensionWallet<"connectOnekeyWallet"> = createWallet
[Chain.Polygon]: { direct: true, typedData: true },
[Chain.Solana]: { direct: true },
[Chain.Stellar]: { direct: true },
[Chain.Sui]: { direct: true },
[Chain.Ton]: { direct: true },
[Chain.Tron]: { direct: true },
[Chain.XLayer]: { direct: true, typedData: true },
Expand All @@ -66,6 +67,7 @@ export const onekeyWallet: ExtensionWallet<"connectOnekeyWallet"> = createWallet
Chain.Polygon,
Chain.Solana,
Chain.Stellar,
Chain.Sui,
Chain.Ton,
Chain.Tron,
Chain.XLayer,
Expand Down
12 changes: 12 additions & 0 deletions packages/wallet-extensions/src/onekey/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ export type OneKeyBtcProvider = {
signPsbt: (psbtHex: string, options: { autoFinalized: boolean }) => Promise<string>;
};

export type OneKeySuiAccount = { address: string; publicKey: string };

export type OneKeySuiProvider = {
getAccounts: () => Promise<OneKeySuiAccount[]>;
signTransaction: (input: {
account: OneKeySuiAccount;
chain: string;
transaction: { serialize: () => string };
}) => Promise<{ bytes: string; signature: string }>;
};

export type OneKeyTronProvider = {
request: {
(args: { method: "tron_requestAccounts" }): Promise<{ code: number; message: string }>;
Expand All @@ -39,6 +50,7 @@ export type OneKeyProviders = {
jsBridge?: OneKeyJsBridge;
solana?: SolanaProvider;
stellar?: OneKeyStellarProvider;
sui?: OneKeySuiProvider;
tonconnect?: TonConnectBridge;
tron?: OneKeyTronProvider;
};
Loading