@hot-labs/kit 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +11 -0
- package/.github/workflows/deploy-example.yml +55 -0
- package/.github/workflows/release.yml +74 -0
- package/.prettierrc +4 -0
- package/.prototools +2 -0
- package/.vscode/settings.json +3 -0
- package/CHANGELOG.md +1 -0
- package/README.md +67 -0
- package/build/GoogleConnector.d.ts +20 -0
- package/build/GoogleConnector.js +76 -0
- package/build/GoogleConnector.js.map +1 -0
- package/build/HotConnector.d.ts +91 -0
- package/build/HotConnector.js +285 -0
- package/build/HotConnector.js.map +1 -0
- package/build/OmniConnector.d.ts +95 -0
- package/build/OmniConnector.js +123 -0
- package/build/OmniConnector.js.map +1 -0
- package/build/OmniWallet.d.ts +57 -0
- package/build/OmniWallet.js +56 -0
- package/build/OmniWallet.js.map +1 -0
- package/build/cosmos/connector.d.ts +53 -0
- package/build/cosmos/connector.js +207 -0
- package/build/cosmos/connector.js.map +1 -0
- package/build/cosmos/wallet.d.ts +28 -0
- package/build/cosmos/wallet.js +59 -0
- package/build/cosmos/wallet.js.map +1 -0
- package/build/events.d.ts +42 -0
- package/build/events.js +64 -0
- package/build/events.js.map +1 -0
- package/build/evm/abi.d.ts +17 -0
- package/build/evm/abi.js +38 -0
- package/build/evm/abi.js.map +1 -0
- package/build/evm/connector.d.ts +35 -0
- package/build/evm/connector.js +124 -0
- package/build/evm/connector.js.map +1 -0
- package/build/evm/wallet.d.ts +47 -0
- package/build/evm/wallet.js +136 -0
- package/build/evm/wallet.js.map +1 -0
- package/build/exchange.d.ts +63 -0
- package/build/exchange.js +384 -0
- package/build/exchange.js.map +1 -0
- package/build/hot-wallet/evm.d.ts +1 -0
- package/build/hot-wallet/evm.js +33 -0
- package/build/hot-wallet/evm.js.map +1 -0
- package/build/hot-wallet/hot.d.ts +3 -0
- package/build/hot-wallet/hot.js +40 -0
- package/build/hot-wallet/hot.js.map +1 -0
- package/build/hot-wallet/index.d.ts +4 -0
- package/build/hot-wallet/index.js +5 -0
- package/build/hot-wallet/index.js.map +1 -0
- package/build/hot-wallet/solana/account.d.ts +11 -0
- package/build/hot-wallet/solana/account.js +42 -0
- package/build/hot-wallet/solana/account.js.map +1 -0
- package/build/hot-wallet/solana/index.d.ts +1 -0
- package/build/hot-wallet/solana/index.js +85 -0
- package/build/hot-wallet/solana/index.js.map +1 -0
- package/build/hot-wallet/solana/register.d.ts +2 -0
- package/build/hot-wallet/solana/register.js +41 -0
- package/build/hot-wallet/solana/register.js.map +1 -0
- package/build/hot-wallet/solana/solana-wallet.d.ts +34 -0
- package/build/hot-wallet/solana/solana-wallet.js +223 -0
- package/build/hot-wallet/solana/solana-wallet.js.map +1 -0
- package/build/hot-wallet/solana/utils.d.ts +32 -0
- package/build/hot-wallet/solana/utils.js +36 -0
- package/build/hot-wallet/solana/utils.js.map +1 -0
- package/build/hot-wallet/stellar.d.ts +38 -0
- package/build/hot-wallet/stellar.js +32 -0
- package/build/hot-wallet/stellar.js.map +1 -0
- package/build/hot-wallet/ton.d.ts +1 -0
- package/build/hot-wallet/ton.js +49 -0
- package/build/hot-wallet/ton.js.map +1 -0
- package/build/hot-wallet/wallet.d.ts +1 -0
- package/build/hot-wallet/wallet.js +40 -0
- package/build/hot-wallet/wallet.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.js +25 -0
- package/build/index.js.map +1 -0
- package/build/near/connector.d.ts +28 -0
- package/build/near/connector.js +56 -0
- package/build/near/connector.js.map +1 -0
- package/build/near/wallet.d.ts +62 -0
- package/build/near/wallet.js +233 -0
- package/build/near/wallet.js.map +1 -0
- package/build/omni/Intents.d.ts +93 -0
- package/build/omni/Intents.js +395 -0
- package/build/omni/Intents.js.map +1 -0
- package/build/omni/bridge.d.ts +3 -0
- package/build/omni/bridge.js +34 -0
- package/build/omni/bridge.js.map +1 -0
- package/build/omni/config.d.ts +99 -0
- package/build/omni/config.js +126 -0
- package/build/omni/config.js.map +1 -0
- package/build/omni/defaultTokens.d.ts +17 -0
- package/build/omni/defaultTokens.js +1079 -0
- package/build/omni/defaultTokens.js.map +1 -0
- package/build/omni/index.d.ts +8 -0
- package/build/omni/index.js +9 -0
- package/build/omni/index.js.map +1 -0
- package/build/omni/nearRpc.d.ts +24 -0
- package/build/omni/nearRpc.js +167 -0
- package/build/omni/nearRpc.js.map +1 -0
- package/build/omni/recipient.d.ts +10 -0
- package/build/omni/recipient.js +40 -0
- package/build/omni/recipient.js.map +1 -0
- package/build/omni/token.d.ts +36 -0
- package/build/omni/token.js +136 -0
- package/build/omni/token.js.map +1 -0
- package/build/omni/tokens.d.ts +14 -0
- package/build/omni/tokens.js +57 -0
- package/build/omni/tokens.js.map +1 -0
- package/build/omni/types.d.ts +41 -0
- package/build/omni/types.js +2 -0
- package/build/omni/types.js.map +1 -0
- package/build/omni/utils.d.ts +24 -0
- package/build/omni/utils.js +150 -0
- package/build/omni/utils.js.map +1 -0
- package/build/settings.d.ts +5 -0
- package/build/settings.js +6 -0
- package/build/settings.js.map +1 -0
- package/build/solana/connector.d.ts +31 -0
- package/build/solana/connector.js +138 -0
- package/build/solana/connector.js.map +1 -0
- package/build/solana/protocol.d.ts +25 -0
- package/build/solana/protocol.js +56 -0
- package/build/solana/protocol.js.map +1 -0
- package/build/solana/wallet.d.ts +47 -0
- package/build/solana/wallet.js +188 -0
- package/build/solana/wallet.js.map +1 -0
- package/build/solana/wallets.d.ts +102 -0
- package/build/solana/wallets.js +150 -0
- package/build/solana/wallets.js.map +1 -0
- package/build/stellar/connector.d.ts +25 -0
- package/build/stellar/connector.js +56 -0
- package/build/stellar/connector.js.map +1 -0
- package/build/stellar/wallet.d.ts +70 -0
- package/build/stellar/wallet.js +225 -0
- package/build/stellar/wallet.js.map +1 -0
- package/build/storage.d.ts +10 -0
- package/build/storage.js +12 -0
- package/build/storage.js.map +1 -0
- package/build/ton/connector.d.ts +25 -0
- package/build/ton/connector.js +119 -0
- package/build/ton/connector.js.map +1 -0
- package/build/ton/utils.d.ts +45 -0
- package/build/ton/utils.js +64 -0
- package/build/ton/utils.js.map +1 -0
- package/build/ton/wallet.d.ts +70 -0
- package/build/ton/wallet.js +154 -0
- package/build/ton/wallet.js.map +1 -0
- package/build/ui/Popup.d.ts +10 -0
- package/build/ui/Popup.js +38 -0
- package/build/ui/Popup.js.map +1 -0
- package/build/ui/connect/AuthPopup.d.ts +2 -0
- package/build/ui/connect/AuthPopup.js +48 -0
- package/build/ui/connect/AuthPopup.js.map +1 -0
- package/build/ui/connect/ConnectWallet.d.ts +9 -0
- package/build/ui/connect/ConnectWallet.js +22 -0
- package/build/ui/connect/ConnectWallet.js.map +1 -0
- package/build/ui/connect/LogoutPopup.d.ts +10 -0
- package/build/ui/connect/LogoutPopup.js +8 -0
- package/build/ui/connect/LogoutPopup.js.map +1 -0
- package/build/ui/connect/WCPopup.d.ts +13 -0
- package/build/ui/connect/WCPopup.js +81 -0
- package/build/ui/connect/WCPopup.js.map +1 -0
- package/build/ui/connect/WCRequest.d.ts +9 -0
- package/build/ui/connect/WCRequest.js +13 -0
- package/build/ui/connect/WCRequest.js.map +1 -0
- package/build/ui/connect/WalletPicker.d.ts +11 -0
- package/build/ui/connect/WalletPicker.js +48 -0
- package/build/ui/connect/WalletPicker.js.map +1 -0
- package/build/ui/icons/arrow-right.d.ts +1 -0
- package/build/ui/icons/arrow-right.js +5 -0
- package/build/ui/icons/arrow-right.js.map +1 -0
- package/build/ui/icons/exchange.d.ts +6 -0
- package/build/ui/icons/exchange.js +6 -0
- package/build/ui/icons/exchange.js.map +1 -0
- package/build/ui/icons/logout.d.ts +1 -0
- package/build/ui/icons/logout.js +3 -0
- package/build/ui/icons/logout.js.map +1 -0
- package/build/ui/icons/pending.d.ts +1 -0
- package/build/ui/icons/pending.js +5 -0
- package/build/ui/icons/pending.js.map +1 -0
- package/build/ui/icons/qr.d.ts +1 -0
- package/build/ui/icons/qr.js +5 -0
- package/build/ui/icons/qr.js.map +1 -0
- package/build/ui/icons/search.d.ts +1 -0
- package/build/ui/icons/search.js +5 -0
- package/build/ui/icons/search.js.map +1 -0
- package/build/ui/icons/switch.d.ts +1 -0
- package/build/ui/icons/switch.js +5 -0
- package/build/ui/icons/switch.js.map +1 -0
- package/build/ui/icons/wallet.d.ts +1 -0
- package/build/ui/icons/wallet.js +5 -0
- package/build/ui/icons/wallet.js.map +1 -0
- package/build/ui/payment/Bridge.d.ts +27 -0
- package/build/ui/payment/Bridge.js +340 -0
- package/build/ui/payment/Bridge.js.map +1 -0
- package/build/ui/payment/DepositQR.d.ts +9 -0
- package/build/ui/payment/DepositQR.js +56 -0
- package/build/ui/payment/DepositQR.js.map +1 -0
- package/build/ui/payment/Payment.d.ts +16 -0
- package/build/ui/payment/Payment.js +50 -0
- package/build/ui/payment/Payment.js.map +1 -0
- package/build/ui/payment/Profile.d.ts +7 -0
- package/build/ui/payment/Profile.js +88 -0
- package/build/ui/payment/Profile.js.map +1 -0
- package/build/ui/payment/SelectRecipient.d.ts +14 -0
- package/build/ui/payment/SelectRecipient.js +68 -0
- package/build/ui/payment/SelectRecipient.js.map +1 -0
- package/build/ui/payment/SelectSender.d.ts +13 -0
- package/build/ui/payment/SelectSender.js +23 -0
- package/build/ui/payment/SelectSender.js.map +1 -0
- package/build/ui/payment/SelectToken.d.ts +13 -0
- package/build/ui/payment/SelectToken.js +92 -0
- package/build/ui/payment/SelectToken.js.map +1 -0
- package/build/ui/payment/TokenCard.d.ts +23 -0
- package/build/ui/payment/TokenCard.js +50 -0
- package/build/ui/payment/TokenCard.js.map +1 -0
- package/build/ui/router.d.ts +37 -0
- package/build/ui/router.js +56 -0
- package/build/ui/router.js.map +1 -0
- package/build/ui/styles.d.ts +11 -0
- package/build/ui/styles.js +273 -0
- package/build/ui/styles.js.map +1 -0
- package/package.json +60 -0
- package/skill.md +989 -0
- package/src/GoogleConnector.ts +102 -0
- package/src/HotConnector.ts +344 -0
- package/src/OmniConnector.ts +161 -0
- package/src/OmniWallet.ts +94 -0
- package/src/cosmos/connector.ts +242 -0
- package/src/cosmos/wallet.ts +77 -0
- package/src/events.ts +66 -0
- package/src/evm/abi.ts +39 -0
- package/src/evm/connector.ts +139 -0
- package/src/evm/wallet.ts +156 -0
- package/src/exchange.ts +426 -0
- package/src/hot-wallet/evm.ts +38 -0
- package/src/hot-wallet/hot.ts +39 -0
- package/src/hot-wallet/index.ts +4 -0
- package/src/hot-wallet/solana/account.ts +52 -0
- package/src/hot-wallet/solana/index.ts +98 -0
- package/src/hot-wallet/solana/register.ts +48 -0
- package/src/hot-wallet/solana/solana-wallet.ts +280 -0
- package/src/hot-wallet/solana/utils.ts +56 -0
- package/src/hot-wallet/stellar.ts +39 -0
- package/src/hot-wallet/ton.ts +56 -0
- package/src/hot-wallet/wallet.ts +44 -0
- package/src/index.ts +30 -0
- package/src/near/connector.ts +71 -0
- package/src/near/wallet.ts +255 -0
- package/src/omni/Intents.ts +454 -0
- package/src/omni/bridge.ts +38 -0
- package/src/omni/config.ts +130 -0
- package/src/omni/defaultTokens.ts +1078 -0
- package/src/omni/index.ts +8 -0
- package/src/omni/nearRpc.ts +187 -0
- package/src/omni/recipient.ts +41 -0
- package/src/omni/token.ts +125 -0
- package/src/omni/tokens.ts +68 -0
- package/src/omni/types.ts +46 -0
- package/src/omni/utils.ts +163 -0
- package/src/settings.ts +5 -0
- package/src/solana/connector.ts +151 -0
- package/src/solana/protocol.ts +66 -0
- package/src/solana/wallet.ts +230 -0
- package/src/solana/wallets.ts +243 -0
- package/src/stellar/connector.ts +69 -0
- package/src/stellar/wallet.ts +267 -0
- package/src/storage.ts +19 -0
- package/src/ton/connector.ts +138 -0
- package/src/ton/utils.ts +73 -0
- package/src/ton/wallet.ts +178 -0
- package/src/ui/Popup.tsx +62 -0
- package/src/ui/connect/AuthPopup.tsx +78 -0
- package/src/ui/connect/ConnectWallet.tsx +63 -0
- package/src/ui/connect/LogoutPopup.tsx +20 -0
- package/src/ui/connect/WCPopup.tsx +122 -0
- package/src/ui/connect/WCRequest.tsx +28 -0
- package/src/ui/connect/WalletPicker.tsx +92 -0
- package/src/ui/icons/arrow-right.tsx +8 -0
- package/src/ui/icons/exchange.tsx +17 -0
- package/src/ui/icons/logout.tsx +18 -0
- package/src/ui/icons/pending.tsx +18 -0
- package/src/ui/icons/qr.tsx +12 -0
- package/src/ui/icons/search.tsx +18 -0
- package/src/ui/icons/switch.tsx +10 -0
- package/src/ui/icons/wallet.tsx +18 -0
- package/src/ui/payment/Bridge.tsx +582 -0
- package/src/ui/payment/DepositQR.tsx +88 -0
- package/src/ui/payment/Payment.tsx +78 -0
- package/src/ui/payment/Profile.tsx +140 -0
- package/src/ui/payment/SelectRecipient.tsx +111 -0
- package/src/ui/payment/SelectSender.tsx +60 -0
- package/src/ui/payment/SelectToken.tsx +134 -0
- package/src/ui/payment/TokenCard.tsx +83 -0
- package/src/ui/router.tsx +92 -0
- package/src/ui/styles.ts +284 -0
- package/tsconfig.json +22 -0
- package/vite.config.ts +17 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { base64, base58, hex } from "@scure/base";
|
|
2
|
+
import { BrowserProvider, ethers, JsonRpcProvider, JsonRpcSigner, TransactionRequest } from "ethers";
|
|
3
|
+
|
|
4
|
+
import { OmniConnector } from "../OmniConnector";
|
|
5
|
+
import { OmniWallet } from "../OmniWallet";
|
|
6
|
+
import { WalletType } from "../omni/config";
|
|
7
|
+
import { ReviewFee } from "../omni/bridge";
|
|
8
|
+
import { Token } from "../omni/token";
|
|
9
|
+
import { erc20abi } from "./abi";
|
|
10
|
+
|
|
11
|
+
export interface EvmProvider {
|
|
12
|
+
request: (args: any) => Promise<any>;
|
|
13
|
+
on?: (method: string, handler: (args: any) => void) => void;
|
|
14
|
+
off?: (method: string, handler: (args: any) => void) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class EvmWallet extends OmniWallet {
|
|
18
|
+
readonly publicKey?: string;
|
|
19
|
+
readonly type = WalletType.EVM;
|
|
20
|
+
|
|
21
|
+
constructor(readonly connector: OmniConnector, readonly address: string, readonly provider: EvmProvider) {
|
|
22
|
+
super(connector);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private rpcs: Record<number, JsonRpcProvider> = {};
|
|
26
|
+
rpc(chain: number) {
|
|
27
|
+
if (chain < 1 || chain == null) throw "Invalid chain";
|
|
28
|
+
if (this.rpcs[chain]) return this.rpcs[chain];
|
|
29
|
+
const rpc = new JsonRpcProvider(`https://api0.herewallet.app/api/v1/evm/rpc/${chain}`, chain, { staticNetwork: true });
|
|
30
|
+
this.rpcs[chain] = rpc;
|
|
31
|
+
return rpc;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get omniAddress() {
|
|
35
|
+
return this.address.toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async disconnect() {
|
|
39
|
+
this.provider.request?.({ method: "wallet_revokePermissions", params: [{ eth_accounts: {} }] });
|
|
40
|
+
await super.disconnect();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async fetchBalances(chain: number, whitelist: string[]): Promise<Record<string, bigint>> {
|
|
44
|
+
const native = await this.fetchBalance(chain, "native");
|
|
45
|
+
try {
|
|
46
|
+
const res = await fetch(`https://api0.herewallet.app/api/v1/user/balances/${chain}/${this.address}`, { body: JSON.stringify({ whitelist, chain_id: chain }), method: "POST" });
|
|
47
|
+
if (!res.ok) throw new Error("Failed to fetch balances");
|
|
48
|
+
const { balances } = await res.json();
|
|
49
|
+
return { ...balances, native };
|
|
50
|
+
} catch {
|
|
51
|
+
const balances = await Promise.all(
|
|
52
|
+
whitelist.map(async (token) => {
|
|
53
|
+
const balance = await this.fetchBalance(chain, token);
|
|
54
|
+
return [token, balance];
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
return { ...Object.fromEntries(balances), native };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async fetchBalance(chain: number, address: string) {
|
|
62
|
+
const rpc = this.rpc(chain);
|
|
63
|
+
if (address === "native") {
|
|
64
|
+
const balance = await rpc.getBalance(this.address);
|
|
65
|
+
return BigInt(balance);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const erc20 = new ethers.Contract(address, erc20abi, rpc);
|
|
69
|
+
const balance = await erc20.balanceOf(this.address);
|
|
70
|
+
return BigInt(balance);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async signIntentsWithAuth(domain: string, intents?: Record<string, any>[]) {
|
|
74
|
+
const seed = hex.encode(window.crypto.getRandomValues(new Uint8Array(32)));
|
|
75
|
+
const msgBuffer = new TextEncoder().encode(`${domain}_${seed}`);
|
|
76
|
+
const nonce = await window.crypto.subtle.digest("SHA-256", new Uint8Array(msgBuffer));
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
signed: await this.signIntents(intents || [], { nonce: new Uint8Array(nonce) }),
|
|
80
|
+
chainId: WalletType.EVM,
|
|
81
|
+
publicKey: this.address,
|
|
82
|
+
address: this.address,
|
|
83
|
+
seed,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async signMessage(msg: string) {
|
|
88
|
+
if (!this.provider.request) throw "not impl";
|
|
89
|
+
const result: string = await this.provider.request({ method: "personal_sign", params: [msg, this.address] });
|
|
90
|
+
const yInt = parseInt(result.slice(-2), 16);
|
|
91
|
+
const isZero = yInt === 27 || yInt === 0;
|
|
92
|
+
return hex.decode(result.slice(2, -2) + (isZero ? "00" : "01"));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async transferFee(token: Token, receiver: string, amount: bigint): Promise<ReviewFee> {
|
|
96
|
+
const rpc = this.rpc(token.chain);
|
|
97
|
+
const fee = ReviewFee.fromFeeData(await rpc.getFeeData(), token.chain);
|
|
98
|
+
|
|
99
|
+
if (token.address === "native") {
|
|
100
|
+
const gasLimit = await rpc.estimateGas({ to: receiver, value: 100n, ...fee.evmGas });
|
|
101
|
+
const extaLimit = BigInt(Math.floor(Number(gasLimit) * 1.3));
|
|
102
|
+
return fee.changeGasLimit(extaLimit);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const erc20 = new ethers.Contract(token.address, erc20abi, rpc);
|
|
106
|
+
const gasLimit = await erc20.transfer.estimateGas(receiver, amount, fee.evmGas);
|
|
107
|
+
const extaLimit = BigInt(Math.floor(Number(gasLimit) * 1.3));
|
|
108
|
+
return fee.changeGasLimit(extaLimit);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async sendTransaction(chain: number, request: TransactionRequest): Promise<string> {
|
|
112
|
+
if (!this.provider.request) throw "not impl";
|
|
113
|
+
const provider = new BrowserProvider(this.provider as any);
|
|
114
|
+
const signer = new JsonRpcSigner(provider, this.address);
|
|
115
|
+
|
|
116
|
+
await this.provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: `0x${chain.toString(16)}` }] });
|
|
117
|
+
const tx = await signer.sendTransaction(request);
|
|
118
|
+
return tx.hash;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async transfer(args: { token: Token; receiver: string; amount: bigint; comment?: string; gasFee?: ReviewFee }): Promise<string> {
|
|
122
|
+
if (args.token.address === "native") {
|
|
123
|
+
return await this.sendTransaction(args.token.chain, {
|
|
124
|
+
...args.gasFee?.evmGas,
|
|
125
|
+
from: this.address,
|
|
126
|
+
value: args.amount,
|
|
127
|
+
to: args.receiver,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const erc20 = new ethers.Contract(args.token.address, erc20abi, this.rpc(args.token.chain));
|
|
132
|
+
const tx = await erc20.transfer.populateTransaction(args.receiver, args.amount, { ...args.gasFee?.evmGas });
|
|
133
|
+
return await this.sendTransaction(args.token.chain, tx);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async signIntents(intents: Record<string, any>[], options?: { deadline?: number; nonce?: Uint8Array }): Promise<Record<string, any>> {
|
|
137
|
+
const nonce = new Uint8Array(options?.nonce || window.crypto.getRandomValues(new Uint8Array(32)));
|
|
138
|
+
|
|
139
|
+
const message = JSON.stringify({
|
|
140
|
+
deadline: options?.deadline ? new Date(options.deadline).toISOString() : "2100-01-01T00:00:00.000Z",
|
|
141
|
+
verifying_contract: "intents.near",
|
|
142
|
+
signer_id: this.omniAddress,
|
|
143
|
+
nonce: base64.encode(nonce),
|
|
144
|
+
intents: intents,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const buffer = await this.signMessage(message);
|
|
148
|
+
return {
|
|
149
|
+
signature: `secp256k1:${base58.encode(buffer)}`,
|
|
150
|
+
payload: message,
|
|
151
|
+
standard: "erc191",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export default EvmWallet;
|
package/src/exchange.ts
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { GetExecutionStatusResponse, OneClickService, ApiError, OpenAPI, QuoteRequest, QuoteResponse } from "@defuse-protocol/one-click-sdk-typescript";
|
|
2
|
+
import { utils } from "@hot-labs/omni-sdk";
|
|
3
|
+
import { hex } from "@scure/base";
|
|
4
|
+
|
|
5
|
+
import CosmosWallet from "./cosmos/wallet";
|
|
6
|
+
import StellarWallet from "./stellar/wallet";
|
|
7
|
+
import NearWallet from "./near/wallet";
|
|
8
|
+
import EvmWallet from "./evm/wallet";
|
|
9
|
+
|
|
10
|
+
import { HotConnector } from "./HotConnector";
|
|
11
|
+
import { Network, OmniToken, WalletType } from "./omni/config";
|
|
12
|
+
import { bridge, ReviewFee } from "./omni/bridge";
|
|
13
|
+
import { Recipient } from "./omni/recipient";
|
|
14
|
+
import { OmniWallet } from "./OmniWallet";
|
|
15
|
+
import { tokens } from "./omni/tokens";
|
|
16
|
+
import { Token } from "./omni/token";
|
|
17
|
+
|
|
18
|
+
OpenAPI.BASE = "https://1click.chaindefuser.com";
|
|
19
|
+
OpenAPI.TOKEN = "";
|
|
20
|
+
|
|
21
|
+
export class UnsupportedDexError extends Error {
|
|
22
|
+
constructor(message: string) {
|
|
23
|
+
super(message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ReadableDexError extends Error {
|
|
28
|
+
constructor(message: string) {
|
|
29
|
+
super(message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type BridgeReview = {
|
|
34
|
+
amountIn: bigint;
|
|
35
|
+
amountOut: bigint;
|
|
36
|
+
slippage: number;
|
|
37
|
+
fee: ReviewFee | null;
|
|
38
|
+
qoute: QuoteResponse["quote"] | "withdraw" | "deposit";
|
|
39
|
+
status: "pending" | "success" | "failed";
|
|
40
|
+
statusMessage: string | null;
|
|
41
|
+
sender: OmniWallet | "qr";
|
|
42
|
+
recipient: Recipient;
|
|
43
|
+
from: Token;
|
|
44
|
+
to: Token;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
interface BridgeRequest {
|
|
48
|
+
refund: OmniWallet;
|
|
49
|
+
sender: OmniWallet | "qr";
|
|
50
|
+
type?: "exactIn" | "exactOut";
|
|
51
|
+
recipient: Recipient;
|
|
52
|
+
slippage: number;
|
|
53
|
+
amount: bigint;
|
|
54
|
+
from: Token;
|
|
55
|
+
to: Token;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
59
|
+
|
|
60
|
+
export class Exchange {
|
|
61
|
+
constructor(readonly wibe3: HotConnector) {}
|
|
62
|
+
|
|
63
|
+
async getToken(chain: number, address: string): Promise<string | null> {
|
|
64
|
+
if (chain === Network.Hot) return address;
|
|
65
|
+
const tokensList = await tokens.getTokens();
|
|
66
|
+
const token = tokensList.find((t) => {
|
|
67
|
+
if (t.chain !== chain) return false;
|
|
68
|
+
if (t.address?.toLowerCase() === address.toLowerCase()) return true;
|
|
69
|
+
if (address === "native" && t.address == "native") return true;
|
|
70
|
+
if (address === "native" && t.address == "wrap.near") return true;
|
|
71
|
+
return false;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return token?.omniAddress || null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async deposit(args: { sender: OmniWallet; token: Token; amount: bigint; recipient: Recipient; onMessage: (message: string) => void }) {
|
|
78
|
+
const { sender, token, amount, recipient, onMessage } = args;
|
|
79
|
+
onMessage("Sending deposit transaction");
|
|
80
|
+
|
|
81
|
+
if (token.type === WalletType.COSMOS && sender instanceof CosmosWallet) {
|
|
82
|
+
const cosmosBridge = await bridge.cosmos();
|
|
83
|
+
const hash = await cosmosBridge.deposit({
|
|
84
|
+
sendTransaction: async (tx) => sender.sendTransaction(tx),
|
|
85
|
+
senderPublicKey: hex.decode(sender.publicKey),
|
|
86
|
+
intentAccount: recipient.omniAddress,
|
|
87
|
+
sender: sender.address,
|
|
88
|
+
token: token.address,
|
|
89
|
+
chain: token.chain,
|
|
90
|
+
amount: amount,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
onMessage("Waiting for deposit");
|
|
94
|
+
const deposit = await bridge.waitPendingDeposit(token.chain, hash, recipient.omniAddress);
|
|
95
|
+
onMessage("Finishing deposit");
|
|
96
|
+
await bridge.finishDeposit(deposit);
|
|
97
|
+
onMessage("Deposit finished");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (token.type === WalletType.EVM && sender instanceof EvmWallet) {
|
|
102
|
+
const hash = await bridge.evm.deposit({
|
|
103
|
+
sendTransaction: async (tx) => sender.sendTransaction(token.chain, tx),
|
|
104
|
+
intentAccount: recipient.omniAddress,
|
|
105
|
+
sender: sender.address,
|
|
106
|
+
token: token.address,
|
|
107
|
+
chain: token.chain,
|
|
108
|
+
amount: amount,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!hash) throw new Error("Failed to deposit");
|
|
112
|
+
onMessage("Waiting for deposit");
|
|
113
|
+
const deposit = await bridge.waitPendingDeposit(token.chain, hash, recipient.omniAddress);
|
|
114
|
+
onMessage("Finishing deposit");
|
|
115
|
+
await bridge.finishDeposit(deposit);
|
|
116
|
+
onMessage("Deposit finished");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (token.type === WalletType.NEAR && sender instanceof NearWallet) {
|
|
121
|
+
return await bridge.near.deposit({
|
|
122
|
+
sendTransaction: async (tx: any) => sender.sendTransaction(tx),
|
|
123
|
+
intentAccount: recipient.omniAddress,
|
|
124
|
+
sender: sender.address,
|
|
125
|
+
token: token.address,
|
|
126
|
+
amount: amount,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
throw new Error("Unsupported token");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async withdraw(args: { sender: OmniWallet; token: Token; amount: bigint; recipient: Recipient }) {
|
|
134
|
+
const { sender, token, amount, recipient } = args;
|
|
135
|
+
|
|
136
|
+
const receipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
137
|
+
if (receipientWallet instanceof NearWallet && token.type === WalletType.NEAR) {
|
|
138
|
+
await receipientWallet.registerToken(token.address);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await bridge.withdrawToken({
|
|
142
|
+
signIntents: async (intents) => sender.signIntents(intents),
|
|
143
|
+
intentAccount: sender.omniAddress,
|
|
144
|
+
receiver: recipient.address,
|
|
145
|
+
token: token.address,
|
|
146
|
+
chain: token.chain,
|
|
147
|
+
gasless: true,
|
|
148
|
+
amount: amount,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async withdrawFee(request: BridgeRequest) {
|
|
153
|
+
if (request.sender === "qr") throw new Error("Sender is QR");
|
|
154
|
+
if (request.to.chain === Network.Near || request.to.chain === Network.Hot) return 0n;
|
|
155
|
+
const gaslessFee = await bridge.getGaslessWithdrawFee({
|
|
156
|
+
receiver: request.recipient.address,
|
|
157
|
+
token: request.to.address,
|
|
158
|
+
chain: request.to.chain,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (gaslessFee.gasPrice === 0n) return 0n;
|
|
162
|
+
if (request.to.address === "native") return 0n;
|
|
163
|
+
|
|
164
|
+
// if withdraw token is not native, we need to swap a bit of it to native to cover the withdraw fee
|
|
165
|
+
const swap = await bridge.buildSwapExectOutIntent({
|
|
166
|
+
intentAccount: request.sender.omniAddress,
|
|
167
|
+
intentFrom: utils.toOmniIntent(request.to.chain, request.to.address),
|
|
168
|
+
intentTo: utils.toOmniIntent(request.to.chain, "native"),
|
|
169
|
+
amountOut: gaslessFee.gasPrice,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// if swap is successful and the amount out is greater than the amount in, we need to subtract the amount in from the amount out
|
|
173
|
+
return BigInt(swap.amount_in);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async reviewSwap(request: BridgeRequest): Promise<BridgeReview> {
|
|
177
|
+
const { sender, refund, from, to, amount, recipient, slippage, type } = request;
|
|
178
|
+
const intentFrom = await this.getToken(from.chain, from.address);
|
|
179
|
+
const intentTo = await this.getToken(to.chain, to.address);
|
|
180
|
+
|
|
181
|
+
if (!intentFrom) throw new Error("Unsupported token");
|
|
182
|
+
if (!intentTo) throw new Error("Unsupported token");
|
|
183
|
+
|
|
184
|
+
const deadlineTime = 20 * 60 * 1000;
|
|
185
|
+
const directChains = [Network.Near, Network.Juno, Network.Gonka, Network.ADI];
|
|
186
|
+
const deadline = new Date(Date.now() + deadlineTime).toISOString();
|
|
187
|
+
const noFee = from.symbol === to.symbol;
|
|
188
|
+
|
|
189
|
+
if (sender !== "qr" && directChains.includes(from.chain) && to.chain === Network.Hot && from.omniAddress === to.omniAddress) {
|
|
190
|
+
const fee = await bridge.getDepositFee({
|
|
191
|
+
intentAccount: sender.omniAddress,
|
|
192
|
+
sender: sender.address,
|
|
193
|
+
token: from.address,
|
|
194
|
+
chain: from.chain,
|
|
195
|
+
amount: amount,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
from: from,
|
|
200
|
+
to: to,
|
|
201
|
+
sender: sender,
|
|
202
|
+
recipient,
|
|
203
|
+
amountIn: amount,
|
|
204
|
+
amountOut: amount,
|
|
205
|
+
slippage: slippage,
|
|
206
|
+
statusMessage: null,
|
|
207
|
+
status: "pending",
|
|
208
|
+
qoute: "deposit",
|
|
209
|
+
fee,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (sender !== "qr" && directChains.includes(to.chain) && from.chain === Network.Hot && from.omniAddress === to.omniAddress) {
|
|
214
|
+
const fee = await this.withdrawFee(request);
|
|
215
|
+
if (fee >= amount) throw "Withdraw fee is greater than amount";
|
|
216
|
+
return {
|
|
217
|
+
from: from,
|
|
218
|
+
to: to,
|
|
219
|
+
amountIn: amount,
|
|
220
|
+
sender: sender,
|
|
221
|
+
fee: new ReviewFee({ chain: -4 }),
|
|
222
|
+
amountOut: amount - fee,
|
|
223
|
+
slippage: slippage,
|
|
224
|
+
recipient: recipient,
|
|
225
|
+
statusMessage: null,
|
|
226
|
+
status: "pending",
|
|
227
|
+
qoute: "withdraw",
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const refundParams = { refundType: QuoteRequest.refundType.ORIGIN_CHAIN, refundTo: refund.address };
|
|
232
|
+
if (refund.type !== from.type) {
|
|
233
|
+
if (!refund.omniAddress) throw "Setup refund address";
|
|
234
|
+
refundParams.refundType = QuoteRequest.refundType.INTENTS;
|
|
235
|
+
refundParams.refundTo = refund.omniAddress;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (recipient.type === WalletType.STELLAR) {
|
|
239
|
+
const isTokenActivated = await StellarWallet.isTokenActivated(recipient.address, request.to.address);
|
|
240
|
+
const recipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
241
|
+
if (!isTokenActivated && !recipientWallet) throw "Token not activated for recipient";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let qoute: QuoteResponse | null = null;
|
|
245
|
+
try {
|
|
246
|
+
qoute = await OneClickService.getQuote({
|
|
247
|
+
originAsset: intentFrom,
|
|
248
|
+
destinationAsset: intentTo,
|
|
249
|
+
slippageTolerance: Math.round(slippage * 10_000),
|
|
250
|
+
swapType: type === "exactIn" ? QuoteRequest.swapType.EXACT_INPUT : QuoteRequest.swapType.EXACT_OUTPUT,
|
|
251
|
+
depositType: from.chain === Network.Hot ? QuoteRequest.depositType.INTENTS : QuoteRequest.depositType.ORIGIN_CHAIN,
|
|
252
|
+
depositMode: from.chain === Network.Stellar ? QuoteRequest.depositMode.MEMO : QuoteRequest.depositMode.SIMPLE,
|
|
253
|
+
recipientType: to.chain === Network.Hot ? QuoteRequest.recipientType.INTENTS : QuoteRequest.recipientType.DESTINATION_CHAIN,
|
|
254
|
+
recipient: to.chain === Network.Hot ? recipient.omniAddress : recipient.address,
|
|
255
|
+
appFees: noFee ? [] : [{ recipient: "intents.tg", fee: 25 }],
|
|
256
|
+
amount: request.amount.toString(),
|
|
257
|
+
referral: "intents.tg",
|
|
258
|
+
deadline: deadline,
|
|
259
|
+
...refundParams,
|
|
260
|
+
dry: false,
|
|
261
|
+
});
|
|
262
|
+
} catch (e) {
|
|
263
|
+
console.log({ e });
|
|
264
|
+
if (e instanceof ApiError && e.body.message.includes("Amount is too low")) {
|
|
265
|
+
const minAmount = e.body.message.match(/try at least (\d+)/)?.[1];
|
|
266
|
+
if (minAmount) throw `Minimum amount is ${from.readable(minAmount)} ${from.symbol}`;
|
|
267
|
+
throw "Amount is too low";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (e instanceof ApiError && e.body.message.includes("is not valid")) {
|
|
271
|
+
throw "This pair is not supported yet";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
throw e;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let fee: ReviewFee | null = null;
|
|
278
|
+
if (request.from.chain !== Network.Hot && sender !== "qr") {
|
|
279
|
+
const amount = BigInt(qoute.quote.amountIn);
|
|
280
|
+
const depositAddress = qoute.quote.depositAddress!;
|
|
281
|
+
fee = await sender.transferFee(request.from, depositAddress, amount).catch(() => null);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
from: request.from,
|
|
286
|
+
to: request.to,
|
|
287
|
+
amountIn: BigInt(qoute.quote.amountIn),
|
|
288
|
+
amountOut: BigInt(qoute.quote.amountOut),
|
|
289
|
+
slippage: request.slippage,
|
|
290
|
+
recipient: request.recipient,
|
|
291
|
+
statusMessage: null,
|
|
292
|
+
qoute: qoute.quote,
|
|
293
|
+
status: "pending",
|
|
294
|
+
sender: sender,
|
|
295
|
+
fee: fee,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async makeSwap(review: BridgeReview, pending: { log: (message: string) => void }) {
|
|
300
|
+
const { sender, recipient } = review;
|
|
301
|
+
|
|
302
|
+
if (review.qoute === "withdraw") {
|
|
303
|
+
if (sender === "qr") throw new Error("Sender is QR");
|
|
304
|
+
await this.withdraw({ sender, token: review.to, amount: review.amountIn, recipient });
|
|
305
|
+
this.wibe3.fetchToken(review.from, sender);
|
|
306
|
+
|
|
307
|
+
const recipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
308
|
+
if (recipientWallet) this.wibe3.fetchToken(review.to, recipientWallet);
|
|
309
|
+
return review;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (review.qoute === "deposit") {
|
|
313
|
+
if (sender === "qr") throw new Error("Sender is QR");
|
|
314
|
+
await this.deposit({ sender, token: review.from, amount: review.amountIn, recipient, onMessage: pending.log });
|
|
315
|
+
this.wibe3.fetchToken(review.from, sender);
|
|
316
|
+
|
|
317
|
+
const recipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
318
|
+
if (recipientWallet) this.wibe3.fetchToken(review.to, recipientWallet);
|
|
319
|
+
return review;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (sender !== "qr") {
|
|
323
|
+
if (recipient.type === WalletType.STELLAR) {
|
|
324
|
+
const isTokenActivated = await StellarWallet.isTokenActivated(recipient.address, review.to.address);
|
|
325
|
+
const recipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
326
|
+
if (!isTokenActivated && !recipientWallet) throw "Token not activated for recipient";
|
|
327
|
+
if (!isTokenActivated && recipientWallet instanceof StellarWallet) {
|
|
328
|
+
await recipientWallet.changeTrustline(review.to.address);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const depositAddress = review.qoute.depositAddress!;
|
|
333
|
+
let hash = "";
|
|
334
|
+
if (review.from.chain === Network.Hot) {
|
|
335
|
+
hash = await sender.intents
|
|
336
|
+
.transfer({
|
|
337
|
+
amount: review.amountIn,
|
|
338
|
+
token: review.from.address as OmniToken,
|
|
339
|
+
recipient: depositAddress,
|
|
340
|
+
})
|
|
341
|
+
.execute();
|
|
342
|
+
} else {
|
|
343
|
+
hash = await sender.transfer({
|
|
344
|
+
receiver: depositAddress,
|
|
345
|
+
amount: review.amountIn,
|
|
346
|
+
comment: review.qoute.depositMemo,
|
|
347
|
+
token: review.from,
|
|
348
|
+
gasFee: review.fee ?? undefined,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
pending.log("Submitting tx");
|
|
353
|
+
this.wibe3.fetchToken(review.from, sender);
|
|
354
|
+
await OneClickService.submitDepositTx({ txHash: hash, depositAddress }).catch(() => {});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (sender !== "qr") {
|
|
358
|
+
wait(1000).then(() => this.wibe3.fetchToken(review.to, sender));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
pending.log("Processing...");
|
|
362
|
+
const recipientWallet = this.wibe3.wallets.find((w) => w.address === recipient.address);
|
|
363
|
+
if (!recipientWallet) return await this.processing(review);
|
|
364
|
+
|
|
365
|
+
const beforeBalance = await this.wibe3.fetchToken(review.to, recipientWallet).catch(() => null);
|
|
366
|
+
if (!beforeBalance) return await this.processing(review);
|
|
367
|
+
|
|
368
|
+
return await Promise.race([
|
|
369
|
+
this.waitBalance(review.to, recipientWallet, beforeBalance, review),
|
|
370
|
+
this.processing(review), //
|
|
371
|
+
]);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async waitBalance(to: Token, wallet: OmniWallet, beforeBalance: bigint, review: BridgeReview): Promise<BridgeReview> {
|
|
375
|
+
const afterBalance = await this.wibe3.fetchToken(to, wallet).catch(() => beforeBalance);
|
|
376
|
+
if (afterBalance > beforeBalance) {
|
|
377
|
+
return {
|
|
378
|
+
...review,
|
|
379
|
+
amountOut: afterBalance - beforeBalance,
|
|
380
|
+
statusMessage: "Swap successful",
|
|
381
|
+
status: "success",
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
await wait(2000);
|
|
386
|
+
return await this.waitBalance(to, wallet, beforeBalance, review);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
getMessage(status: GetExecutionStatusResponse.status): string | null {
|
|
390
|
+
if (status === GetExecutionStatusResponse.status.PENDING_DEPOSIT) return "Waiting for deposit";
|
|
391
|
+
if (status === GetExecutionStatusResponse.status.INCOMPLETE_DEPOSIT) return "Incomplete deposit";
|
|
392
|
+
if (status === GetExecutionStatusResponse.status.KNOWN_DEPOSIT_TX) return "Known deposit tx";
|
|
393
|
+
if (status === GetExecutionStatusResponse.status.PROCESSING) return "Processing swap";
|
|
394
|
+
if (status === GetExecutionStatusResponse.status.SUCCESS) return "Swap successful";
|
|
395
|
+
if (status === GetExecutionStatusResponse.status.FAILED) return "Swap failed";
|
|
396
|
+
if (status === GetExecutionStatusResponse.status.REFUNDED) return "Swap refunded";
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async checkStatus(review: BridgeReview) {
|
|
401
|
+
if (review.qoute === "deposit" || review.qoute === "withdraw") return;
|
|
402
|
+
const status = await OneClickService.getExecutionStatus(review.qoute.depositAddress!, review.qoute.depositMemo);
|
|
403
|
+
const message = this.getMessage(status.status);
|
|
404
|
+
|
|
405
|
+
let state: "pending" | "success" | "failed" = "pending";
|
|
406
|
+
if (status.status === GetExecutionStatusResponse.status.SUCCESS) state = "success";
|
|
407
|
+
if (status.status === GetExecutionStatusResponse.status.FAILED) state = "failed";
|
|
408
|
+
if (status.status === GetExecutionStatusResponse.status.REFUNDED) state = "failed";
|
|
409
|
+
|
|
410
|
+
if (status.swapDetails.amountOut) review.amountOut = BigInt(status.swapDetails.amountOut);
|
|
411
|
+
review.statusMessage = message;
|
|
412
|
+
review.status = state;
|
|
413
|
+
return review;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async processing(review: BridgeReview, interval = 3000) {
|
|
417
|
+
while (review.status === "pending") {
|
|
418
|
+
await this.checkStatus(review);
|
|
419
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (review.status === "success") return review;
|
|
423
|
+
if (review.status === "failed") throw review.statusMessage || "Bridge failed";
|
|
424
|
+
throw new Error("Unknown status");
|
|
425
|
+
}
|
|
426
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isInjected, requestHot } from "./hot";
|
|
2
|
+
|
|
3
|
+
class HotEvmProvider {
|
|
4
|
+
_events = new Map<string, Set<any>>();
|
|
5
|
+
isConnected = () => true;
|
|
6
|
+
isHotWallet = true;
|
|
7
|
+
isMetaMask = true;
|
|
8
|
+
|
|
9
|
+
request = (request: any) => requestHot("ethereum", request);
|
|
10
|
+
removeListener() {}
|
|
11
|
+
on() {}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function announceProvider(provider: HotEvmProvider) {
|
|
15
|
+
// @ts-expect-error: window.ethereum is not typed
|
|
16
|
+
window.ethereum = undefined;
|
|
17
|
+
// @ts-expect-error: window.ethereum is not typed
|
|
18
|
+
window.ethereum = provider;
|
|
19
|
+
window?.dispatchEvent(
|
|
20
|
+
new CustomEvent("eip6963:announceProvider", {
|
|
21
|
+
detail: Object.freeze({
|
|
22
|
+
provider: provider,
|
|
23
|
+
info: {
|
|
24
|
+
icon: "https://storage.herewallet.app/logo.png",
|
|
25
|
+
rdns: "org.hot-labs",
|
|
26
|
+
uuid: "cc8e962c-1f42-425c-8845-e8bd2e136fff",
|
|
27
|
+
name: "HOT Wallet",
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (isInjected()) {
|
|
35
|
+
const hotProvider = new HotEvmProvider();
|
|
36
|
+
window.addEventListener("eip6963:requestProvider", () => announceProvider(hotProvider));
|
|
37
|
+
announceProvider(hotProvider);
|
|
38
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const ancestorOrigins = new Set([
|
|
2
|
+
"http://localhost:1234",
|
|
3
|
+
"https://my.herewallet.app",
|
|
4
|
+
"https://tgapp-dev.herewallet.app",
|
|
5
|
+
"https://tgapp.herewallet.app",
|
|
6
|
+
"https://beta.herewallet.app",
|
|
7
|
+
"https://app.hot-labs.org",
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
export const isInjected = () => {
|
|
11
|
+
if (typeof window === "undefined") return false;
|
|
12
|
+
if (window.self === window.top) return false;
|
|
13
|
+
return ancestorOrigins.has(window.location.ancestorOrigins?.[0]);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const uuid4 = () => {
|
|
17
|
+
try {
|
|
18
|
+
return crypto.randomUUID();
|
|
19
|
+
} catch {
|
|
20
|
+
const temp_url = URL.createObjectURL(new Blob());
|
|
21
|
+
const uuid = temp_url.toString();
|
|
22
|
+
URL.revokeObjectURL(temp_url);
|
|
23
|
+
return uuid.split(/[:/]/g).pop()!.toLowerCase(); // remove prefixes
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const requestHot = (method: string, request: any) => {
|
|
28
|
+
const id = uuid4();
|
|
29
|
+
return new Promise<any>((resolve, reject) => {
|
|
30
|
+
const handler = (e: any) => {
|
|
31
|
+
if (e.data.id !== id) return;
|
|
32
|
+
window?.removeEventListener("message", handler);
|
|
33
|
+
return e.data.success ? resolve(e.data.payload) : reject(e.data.payload);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
window?.parent.postMessage({ $hot: true, method, request, id }, "*");
|
|
37
|
+
window?.addEventListener("message", handler);
|
|
38
|
+
});
|
|
39
|
+
};
|