forked from ton-blockchain/minter-contract
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added wallet connections (ton-blockchain#3)
* added wallet connections * a * a * Wallet connections fixes (ton-blockchain#7) * prettier + fix tests * - Co-authored-by: Shahar Yakir <shahar.yakir@gmail.com>
- Loading branch information
1 parent
fae2730
commit 2f96d24
Showing
18 changed files
with
727 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { Cell } from "ton"; | ||
import { TonhubConnector } from "ton-x"; | ||
import { TransactionDetails } from "../transaction-sender"; | ||
import { TonChromeExtensionWalletAdapter, TonhubWalletAdapter } from "./adapters"; | ||
|
||
import { WalletAdapter, Wallet, Adapters } from "./types"; | ||
|
||
const IS_TESTNET = false; | ||
|
||
export class WalletService { | ||
private readonly adapters: Map<string, WalletAdapter<any>> = new Map(); | ||
|
||
registerAdapter(adapterId: string, adapter: WalletAdapter<any>) { | ||
console.log(this.adapters); | ||
|
||
this.adapters.set(adapterId, adapter); | ||
} | ||
|
||
constructor() { | ||
this.registerAdapter(Adapters.TON_WALLET, new TonChromeExtensionWalletAdapter()); | ||
this.registerAdapter(Adapters.TON_HUB, new TonhubWalletAdapter(IS_TESTNET)); | ||
} | ||
|
||
createSession<S>(adapterId: string, appName: string): Promise<S> { | ||
const adapter = this.adapters.get(adapterId) as WalletAdapter<S>; | ||
return adapter.createSession(appName); | ||
} | ||
|
||
async awaitReadiness<S>(adapterId: string, session: S): Promise<Wallet> { | ||
const adapter = this.adapters.get(adapterId) as WalletAdapter<S>; | ||
return adapter.awaitReadiness(session); | ||
} | ||
|
||
async getWallet<S>(adapterId: string, session: S): Promise<Wallet> { | ||
const adapter = this.adapters.get(adapterId) as WalletAdapter<S>; | ||
return adapter.getWallet(session); | ||
} | ||
|
||
async requestTransaction<S>( | ||
adapterId: string, | ||
session: any, | ||
request: TransactionDetails, | ||
onSuccess?: () => void | ||
): Promise<void | boolean> { | ||
const adapter = this.adapters.get(adapterId) as WalletAdapter<S>; | ||
|
||
return adapter.requestTransaction(session, request, onSuccess); | ||
} | ||
} | ||
|
||
export default WalletService; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { Cell } from "ton"; | ||
import { TransactionDetails } from "../../transaction-sender"; | ||
import { tonWalletClient } from "../clients/TonWalletClient"; | ||
import { TON_WALLET_EXTENSION_URL } from "../config"; | ||
import { TransactionRequest, Wallet, WalletAdapter } from "../types"; | ||
|
||
export function delay(ms: number) { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
export class TonChromeExtensionWalletAdapter implements WalletAdapter<boolean> { | ||
async createSession(): Promise<boolean> { | ||
try { | ||
await tonWalletClient.ready(150); | ||
return true; | ||
} catch (error) { | ||
window.open(TON_WALLET_EXTENSION_URL, "_blank"); | ||
throw error; | ||
} | ||
} | ||
|
||
async awaitReadiness(session: boolean): Promise<Wallet> { | ||
await tonWalletClient.ready(); | ||
|
||
const [[wallet]] = await Promise.all([tonWalletClient.requestWallets(), delay(150)]); | ||
|
||
if (!wallet) { | ||
throw new Error("TON Wallet is not configured."); | ||
} | ||
|
||
return wallet; | ||
} | ||
|
||
getWallet(session: boolean): Promise<Wallet> { | ||
return this.awaitReadiness(session); | ||
} | ||
|
||
isAvailable(): boolean { | ||
return !!(window as any).ton?.isTonWallet; | ||
} | ||
|
||
async requestTransaction( | ||
_session: any, | ||
request: TransactionDetails, | ||
onSuccess?: () => void | ||
): Promise<void> { | ||
const INIT_CELL = new Cell(); | ||
request.stateInit.writeTo(INIT_CELL); | ||
const b64InitCell = INIT_CELL.toBoc().toString("base64"); | ||
|
||
try { | ||
const res: any = await tonWalletClient.sendTransaction({ | ||
to: request.to.toFriendly(), | ||
value: request.value.toString(), | ||
dataType: "boc", | ||
data: request.message?.toBoc().toString("base64"), | ||
stateInit: b64InitCell, | ||
}); | ||
|
||
if (!res) { | ||
throw new Error("Something went wrong"); | ||
} else { | ||
onSuccess && onSuccess(); | ||
} | ||
} catch (error: any) { | ||
throw new Error(error.message); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { Cell, ConfigStore } from "ton"; | ||
import { TonhubConnector } from "ton-x"; | ||
import { TonhubCreatedSession } from "ton-x/dist/connector/TonhubConnector"; | ||
import { TransactionDetails } from "../../transaction-sender"; | ||
import { TransactionRequest, Wallet, WalletAdapter } from "../types"; | ||
|
||
const TONHUB_TIMEOUT = 5 * 60 * 1000; | ||
|
||
export class TonhubWalletAdapter implements WalletAdapter<TonhubCreatedSession> { | ||
tonhubConnector = new TonhubConnector(); | ||
constructor(testnet: boolean) { | ||
this.tonhubConnector = new TonhubConnector({ testnet }); | ||
} | ||
|
||
createSession(name: string): Promise<TonhubCreatedSession> { | ||
const { location } = document; | ||
|
||
return this.tonhubConnector.createNewSession({ | ||
name: name, | ||
url: `${location.protocol}//${location.host}`, | ||
}); | ||
} | ||
|
||
async awaitReadiness(session: TonhubCreatedSession): Promise<Wallet> { | ||
const state = await this.tonhubConnector.awaitSessionReady(session.id, TONHUB_TIMEOUT, 0); | ||
|
||
if (state.state === "revoked") { | ||
throw new Error("Connection was cancelled."); | ||
} | ||
|
||
if (state.state === "expired") { | ||
throw new Error("Connection was not confirmed."); | ||
} | ||
|
||
const walletConfig = new ConfigStore(state.wallet.walletConfig); | ||
|
||
return { | ||
address: state.wallet.address, | ||
publicKey: walletConfig.getString("pk"), | ||
walletVersion: state.wallet.walletType, | ||
}; | ||
} | ||
|
||
getWallet(session: TonhubCreatedSession): Promise<Wallet> { | ||
return this.awaitReadiness(session); | ||
} | ||
|
||
async requestTransaction( | ||
session: TonhubCreatedSession, | ||
request: TransactionDetails, | ||
onSuccess?: () => void | ||
): Promise<void> { | ||
const state = await this.tonhubConnector.getSessionState(session.id); | ||
|
||
if (state.state !== "ready") { | ||
throw new Error("State is not ready"); | ||
} | ||
|
||
const INIT_CELL = new Cell(); | ||
request.stateInit.writeTo(INIT_CELL); | ||
const b64InitCell = INIT_CELL.toBoc().toString("base64"); | ||
|
||
const response = await this.tonhubConnector.requestTransaction({ | ||
seed: session.seed, | ||
appPublicKey: state.wallet.appPublicKey, | ||
to: request.to.toFriendly(), | ||
value: request.value.toString(), | ||
timeout: 5 * 60 * 1000, | ||
stateInit: b64InitCell, | ||
// text: request.text, | ||
payload: request.message?.toBoc().toString("base64"), | ||
}); | ||
|
||
if (response.type === "rejected") { | ||
throw new Error("Transaction was rejected."); | ||
} | ||
|
||
if (response.type === "expired") { | ||
throw new Error("Transaction was expired."); | ||
} | ||
|
||
if (response.type === "invalid_session") { | ||
throw new Error("Something went wrong. Refresh the page and try again."); | ||
} | ||
|
||
if (response.type === "success") { | ||
onSuccess && onSuccess(); | ||
// Handle successful transaction | ||
// const externalMessage = response.response; // Signed external message that was sent to the network | ||
} | ||
} | ||
|
||
isAvailable(): boolean { | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./TonChromeExtensionWalletAdapter"; | ||
export * from "./TonhubWalletAdapter"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { TonWalletProvider, Wallet } from "../types"; | ||
|
||
declare global { | ||
interface Window { | ||
ton?: TonWalletProvider; | ||
} | ||
} | ||
|
||
export class TonWalletClient { | ||
constructor(private readonly window: Window) {} | ||
|
||
private get ton(): TonWalletProvider | undefined { | ||
return this.window.ton; | ||
} | ||
|
||
get isAvailable(): boolean { | ||
return !!this.ton?.isTonWallet; | ||
} | ||
|
||
ready(timeout = 5000): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
const timerId = setInterval(() => { | ||
if (this.isAvailable) { | ||
clearInterval(timerId); | ||
resolve(); | ||
} | ||
}, 50); | ||
|
||
setTimeout(() => reject(new Error("TON Wallet cannot be initialized")), timeout); | ||
}); | ||
} | ||
|
||
requestWallets(): Promise<Wallet[]> { | ||
return this.ton!.send("ton_requestWallets"); | ||
} | ||
|
||
watchAccounts(callback: (accounts: string[]) => void): void { | ||
this.ton!.on("ton_requestAccounts", callback); | ||
} | ||
|
||
sign(hexData: string): Promise<string> { | ||
return this.ton!.send("ton_rawSign", [{ data: hexData }]); | ||
} | ||
|
||
sendTransaction(options: { | ||
to: string; | ||
value: string; | ||
data?: string; | ||
dataType?: "boc" | "hex" | "base64" | "text"; | ||
stateInit?: string; | ||
}): Promise<void> { | ||
return this.ton!.send("ton_sendTransaction", [options]); | ||
} | ||
} | ||
|
||
global["window"] = global["window"] ?? null; | ||
|
||
export const tonWalletClient = new TonWalletClient(window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./TonWalletClient"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Adapter, Adapters } from "./types"; | ||
|
||
const adapters: Adapter[] = [ | ||
{ | ||
text: "Tonhub", | ||
type: Adapters.TON_HUB, | ||
mobileCompatible: true, | ||
}, | ||
{ | ||
text: "Ton Wallet", | ||
type: Adapters.TON_WALLET, | ||
mobileCompatible: false, | ||
}, | ||
]; | ||
|
||
const TON_WALLET_EXTENSION_URL = | ||
"https://chrome.google.com/webstore/detail/ton-wallet/nphplpgoakhhjchkkhmiggakijnkhfnd"; | ||
|
||
export { adapters, TON_WALLET_EXTENSION_URL }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from "./WalletService"; | ||
export * from "./clients"; | ||
export * from "./config"; | ||
export * from "./adapters"; | ||
export * from "./methods"; |
Oops, something went wrong.