@ab-org/predicate-market-sdk 0.0.1 → 0.0.2
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/README.md +15 -7
- package/dist/auth/oidcRelay.d.ts +11 -0
- package/dist/auth/oidcRelay.js +107 -0
- package/dist/auth/walletAccount.d.ts +20 -0
- package/dist/auth/walletAccount.js +267 -0
- package/dist/modules/marketData.d.ts +5 -5
- package/dist/modules/marketData.js +10 -10
- package/dist/ui/SignInModal.js +3 -0
- package/dist/ui/SignInModal.shared.js +40 -1
- package/dist/ui/useSignInModalController.d.ts +2 -2
- package/dist/ui/useSignInModalController.js +51 -70
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Prediction-market specific helpers built on top of `@ab-org/sdk-core`.
|
|
4
4
|
|
|
5
5
|
## Key features
|
|
6
|
-
- Built-in wallet connection modal (social +
|
|
6
|
+
- Built-in wallet connection modal (social via **OIDC relay** + `WalletAccount`, injected wallets via `WalletConnector` — **no FedCM** in `SignInModal` for Google/X)
|
|
7
7
|
- Connection state via `createWalletConnectController()` and `createAccountController()` from `@ab-org/sdk-core`
|
|
8
8
|
- Unified smart-wallet session metadata with capability policy support
|
|
9
9
|
- High-level execution helpers via `createWalletExecutionController()`
|
|
@@ -29,10 +29,13 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
createDepositController,
|
|
31
31
|
createWithdrawController,
|
|
32
|
-
|
|
32
|
+
createMarketDataProvider,
|
|
33
33
|
createPredicateMarketPolicyAdapter,
|
|
34
|
+
type CustodyAdapter,
|
|
34
35
|
} from "@ab-org/predicate-market-sdk";
|
|
35
36
|
|
|
37
|
+
declare const custodyAdapter: CustodyAdapter;
|
|
38
|
+
|
|
36
39
|
const connector = new WalletConnector([
|
|
37
40
|
new MetaMaskProvider(),
|
|
38
41
|
// new CubistSocialProvider(cubistClient)
|
|
@@ -43,7 +46,7 @@ const account = createAccountController();
|
|
|
43
46
|
const execution = createWalletExecutionController();
|
|
44
47
|
|
|
45
48
|
// Use the mock provider until real backend endpoints are ready
|
|
46
|
-
const marketData =
|
|
49
|
+
const marketData = createMarketDataProvider();
|
|
47
50
|
|
|
48
51
|
const deposit = createDepositController(custodyAdapter, marketData);
|
|
49
52
|
const withdraw = createWithdrawController(custodyAdapter, marketData);
|
|
@@ -62,13 +65,15 @@ const policy = createPredicateMarketPolicyAdapter({
|
|
|
62
65
|
|
|
63
66
|
## Configure SignInModal
|
|
64
67
|
|
|
65
|
-
The SDK ships with **bundled auth config** (Google client id, Twitter client id, CubeSigner env/org) so you can call `initSDK` with only `signIn
|
|
68
|
+
The SDK ships with **bundled auth config** (Google client id, Twitter client id, CubeSigner env/org) so you can call `initSDK` with only `signIn`. Override via env (`NEXT_PUBLIC_*`) or by passing options to `initSDK`.
|
|
69
|
+
|
|
70
|
+
**Google / X in `SignInModal`** use the SDK's **bundled OIDC relay auth**: a **popup** opens your **`NEXT_PUBLIC_RELAY_ORIGIN`** routes **`/relay/google`** and **`/relay/x`**, then the SDK's built-in **WalletAccount** bridge turns the returned OIDC token into the session provider.
|
|
66
71
|
|
|
67
72
|
```tsx
|
|
68
73
|
import { initSDK, SignInModal } from "@ab-org/predicate-market-sdk";
|
|
69
74
|
|
|
70
75
|
initSDK({
|
|
71
|
-
//
|
|
76
|
+
// Optional: only used by other Twitter flows; SignInModal X login uses /relay/x on RELAY_ORIGIN
|
|
72
77
|
twitterRedirectUri: typeof window !== "undefined" ? `${window.location.origin}/auth/twitter-callback` : undefined,
|
|
73
78
|
signIn: {
|
|
74
79
|
socialProviders: [
|
|
@@ -88,6 +93,7 @@ initSDK({
|
|
|
88
93
|
```
|
|
89
94
|
|
|
90
95
|
Rules:
|
|
96
|
+
- **`NEXT_PUBLIC_RELAY_ORIGIN`** (or `RELAY_ORIGIN`) must match where you serve **`/relay/google`** and **`/relay/x`**
|
|
91
97
|
- `socialProviders: undefined` uses built-in defaults (`google`, `x`)
|
|
92
98
|
- `socialProviders: []` hides all social buttons
|
|
93
99
|
- known social ids like `google` and `x` automatically reuse built-in icons unless you override `icon`
|
|
@@ -96,6 +102,8 @@ Rules:
|
|
|
96
102
|
- known wallet ids automatically reuse built-in metadata like `installUrl` and detected `installed` state unless you override them
|
|
97
103
|
- component props still override `initSDK({ signIn })` on a per-modal basis
|
|
98
104
|
|
|
105
|
+
The package still **exports** `signInWithGoogle` (Google Identity Services, optional FedCM) for **custom** integrations; the built-in **`SignInModal`** does **not** use it for Google.
|
|
106
|
+
|
|
99
107
|
## Address & balance
|
|
100
108
|
```tsx
|
|
101
109
|
if (!account.isConnected) return <p>Please connect wallet</p>;
|
|
@@ -141,7 +149,7 @@ const quote = await withdraw.fetchQuote("USDT", "ETH", "200");
|
|
|
141
149
|
|
|
142
150
|
### Implementing a real `MarketDataProvider`
|
|
143
151
|
|
|
144
|
-
Replace `
|
|
152
|
+
Replace `createMarketDataProvider()` with your own implementation:
|
|
145
153
|
|
|
146
154
|
```ts
|
|
147
155
|
import type { MarketDataProvider } from "@ab-org/predicate-market-sdk";
|
|
@@ -243,4 +251,4 @@ These policies can be passed into your smart-wallet authorization flow so app ac
|
|
|
243
251
|
>
|
|
244
252
|
Withdraw
|
|
245
253
|
</button>
|
|
246
|
-
```
|
|
254
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type OidcRelayStage = "dev" | "prod";
|
|
2
|
+
interface CreateOidcRelayAuthOptions {
|
|
3
|
+
stage: OidcRelayStage;
|
|
4
|
+
googleClientId: string;
|
|
5
|
+
xClientId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createOidcRelayAuth({ stage, googleClientId, xClientId, }: CreateOidcRelayAuthOptions): {
|
|
8
|
+
loginByGoogle(): Promise<string>;
|
|
9
|
+
loginByX(): Promise<string>;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getEnv } from "../utils/env.js";
|
|
2
|
+
function getRelayOrigin() {
|
|
3
|
+
if (typeof window === "undefined") {
|
|
4
|
+
throw new Error("OIDC relay requires a browser environment");
|
|
5
|
+
}
|
|
6
|
+
if (window.location.hostname === "localhost") {
|
|
7
|
+
return window.location.origin;
|
|
8
|
+
}
|
|
9
|
+
const relayOrigin = getEnv("RELAY_ORIGIN");
|
|
10
|
+
if (!relayOrigin) {
|
|
11
|
+
throw new Error("RELAY_ORIGIN is not configured");
|
|
12
|
+
}
|
|
13
|
+
return relayOrigin;
|
|
14
|
+
}
|
|
15
|
+
function openRelayWindow(url, name) {
|
|
16
|
+
const width = 420;
|
|
17
|
+
const height = 640;
|
|
18
|
+
const top = (window.innerHeight - height) / 2 + window.screenY;
|
|
19
|
+
const left = (window.innerWidth - width) / 2 + window.screenX;
|
|
20
|
+
return window.open(url, name, `dialog=yes,top=${top}px,left=${left}px,width=${width}px,height=${height}px`);
|
|
21
|
+
}
|
|
22
|
+
function waitForOidcToken(popup, relayOrigin, timeoutMs = 120000) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
if (!popup) {
|
|
25
|
+
reject(new Error("Failed to open login popup"));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let settled = false;
|
|
29
|
+
const cleanup = () => {
|
|
30
|
+
clearTimeout(timeout);
|
|
31
|
+
clearInterval(closedCheck);
|
|
32
|
+
window.removeEventListener("message", onMessage);
|
|
33
|
+
};
|
|
34
|
+
const finish = (fn) => {
|
|
35
|
+
if (settled)
|
|
36
|
+
return;
|
|
37
|
+
settled = true;
|
|
38
|
+
cleanup();
|
|
39
|
+
fn();
|
|
40
|
+
};
|
|
41
|
+
const timeout = window.setTimeout(() => {
|
|
42
|
+
try {
|
|
43
|
+
popup.close();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Ignore popup close errors on timeout.
|
|
47
|
+
}
|
|
48
|
+
finish(() => reject(new Error("Login timeout")));
|
|
49
|
+
}, timeoutMs);
|
|
50
|
+
const onMessage = (event) => {
|
|
51
|
+
if (event.origin !== relayOrigin)
|
|
52
|
+
return;
|
|
53
|
+
if (event.data?.action !== "login")
|
|
54
|
+
return;
|
|
55
|
+
const payload = (event.data?.data ?? {});
|
|
56
|
+
if (payload.error) {
|
|
57
|
+
try {
|
|
58
|
+
popup.close();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore popup close errors after relay failure.
|
|
62
|
+
}
|
|
63
|
+
finish(() => reject(new Error(String(payload.error))));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (payload.oidcToken) {
|
|
67
|
+
try {
|
|
68
|
+
popup.close();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Ignore popup close errors after success.
|
|
72
|
+
}
|
|
73
|
+
finish(() => resolve(payload.oidcToken));
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const closedCheck = window.setInterval(() => {
|
|
77
|
+
if (popup.closed) {
|
|
78
|
+
finish(() => reject(new Error("Login cancelled by user")));
|
|
79
|
+
}
|
|
80
|
+
}, 400);
|
|
81
|
+
window.addEventListener("message", onMessage);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export function createOidcRelayAuth({ stage, googleClientId, xClientId, }) {
|
|
85
|
+
const relayOrigin = getRelayOrigin();
|
|
86
|
+
const buildUrl = (provider, clientId) => {
|
|
87
|
+
const target = window.location.origin;
|
|
88
|
+
const params = new URLSearchParams({
|
|
89
|
+
target,
|
|
90
|
+
stage,
|
|
91
|
+
eventId: Date.now().toString(),
|
|
92
|
+
action: "login",
|
|
93
|
+
clientId,
|
|
94
|
+
});
|
|
95
|
+
return `${relayOrigin}/relay/${provider}?${params.toString()}`;
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
async loginByGoogle() {
|
|
99
|
+
const popup = openRelayWindow(buildUrl("google", googleClientId), "Google login");
|
|
100
|
+
return waitForOidcToken(popup, relayOrigin);
|
|
101
|
+
},
|
|
102
|
+
async loginByX() {
|
|
103
|
+
const popup = openRelayWindow(buildUrl("x", xClientId), "X login");
|
|
104
|
+
return waitForOidcToken(popup, relayOrigin);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CubeSignerConfig, type CubeSignerSession, type WalletAuthSource, type WalletProvider, type WalletProviderRequest, type WalletSession } from "@ab-org/sdk-core";
|
|
2
|
+
export declare class EmbeddedWalletAccountProvider implements WalletProvider {
|
|
3
|
+
private readonly provider;
|
|
4
|
+
constructor(provider: WalletProvider);
|
|
5
|
+
request<T = unknown>(payload: WalletProviderRequest): Promise<T>;
|
|
6
|
+
disconnect(): Promise<void>;
|
|
7
|
+
eth_accounts(): Promise<string[]>;
|
|
8
|
+
eth_chainId(): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export default class WalletAccount {
|
|
11
|
+
private static instance;
|
|
12
|
+
private static instanceToken;
|
|
13
|
+
private static walletSession;
|
|
14
|
+
private static cubeSignerSession;
|
|
15
|
+
static clearInstance(): void;
|
|
16
|
+
static getWalletSession(): WalletSession | null;
|
|
17
|
+
static getCubeSignerSession(): CubeSignerSession | null;
|
|
18
|
+
static getInstance(oidcToken: string, authSource: WalletAuthSource, cubeSignerConfig: CubeSignerConfig): Promise<EmbeddedWalletAccountProvider>;
|
|
19
|
+
}
|
|
20
|
+
export declare function clearSocialAccountInstance(): void;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { EvmSigner } from "@cubist-labs/cubesigner-sdk";
|
|
2
|
+
import { CubeSignerAuth, createChainContext, createSessionCapabilityPolicy, } from "@ab-org/sdk-core";
|
|
3
|
+
const cubistCapabilities = [
|
|
4
|
+
"eth_accounts",
|
|
5
|
+
"eth_requestAccounts",
|
|
6
|
+
"eth_chainId",
|
|
7
|
+
"eth_signTransaction",
|
|
8
|
+
"personal_sign",
|
|
9
|
+
"eth_signTypedData_v4",
|
|
10
|
+
"wallet_disconnect",
|
|
11
|
+
];
|
|
12
|
+
const evmChainIdMap = {
|
|
13
|
+
ETH: 1,
|
|
14
|
+
BSC: 56,
|
|
15
|
+
};
|
|
16
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
const toBigIntQuantity = (value) => {
|
|
18
|
+
if (typeof value === "bigint")
|
|
19
|
+
return value;
|
|
20
|
+
if (typeof value === "number") {
|
|
21
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
22
|
+
throw new Error(`Invalid EVM quantity number: ${value}`);
|
|
23
|
+
}
|
|
24
|
+
return BigInt(value);
|
|
25
|
+
}
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
if (!trimmed) {
|
|
28
|
+
throw new Error("EVM quantity cannot be empty");
|
|
29
|
+
}
|
|
30
|
+
if (/^0x[0-9a-fA-F]+$/.test(trimmed) || /^\d+$/.test(trimmed)) {
|
|
31
|
+
return BigInt(trimmed);
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Invalid EVM quantity string: ${value}`);
|
|
34
|
+
};
|
|
35
|
+
const toHexQuantity = (value) => {
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
return `0x${toBigIntQuantity(value).toString(16)}`;
|
|
39
|
+
};
|
|
40
|
+
const normalizeAccessList = (accessList) => {
|
|
41
|
+
if (!accessList)
|
|
42
|
+
return undefined;
|
|
43
|
+
return accessList.map((item) => ({
|
|
44
|
+
address: item.address,
|
|
45
|
+
storageKeys: item.storageKeys,
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
48
|
+
const textEncoder = new TextEncoder();
|
|
49
|
+
const resolveTransactionType = (transaction) => {
|
|
50
|
+
if (transaction.type !== undefined) {
|
|
51
|
+
const normalized = toHexQuantity(transaction.type);
|
|
52
|
+
if (normalized === "0x0" || normalized === "0x1" || normalized === "0x2") {
|
|
53
|
+
return normalized;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Unsupported EVM transaction type for Cubist: ${normalized}`);
|
|
56
|
+
}
|
|
57
|
+
if (transaction.maxFeePerGas !== undefined || transaction.maxPriorityFeePerGas !== undefined) {
|
|
58
|
+
return "0x2";
|
|
59
|
+
}
|
|
60
|
+
if (transaction.accessList?.length) {
|
|
61
|
+
return "0x1";
|
|
62
|
+
}
|
|
63
|
+
return "0x0";
|
|
64
|
+
};
|
|
65
|
+
const toCubistSignRequest = (address, chain, transaction) => {
|
|
66
|
+
const resolvedChainId = (transaction.chainId !== undefined ? Number(toBigIntQuantity(transaction.chainId)) : undefined) ??
|
|
67
|
+
evmChainIdMap[chain];
|
|
68
|
+
if (!resolvedChainId) {
|
|
69
|
+
throw new Error("Cubist signing requires an EVM chainId");
|
|
70
|
+
}
|
|
71
|
+
const type = resolveTransactionType(transaction);
|
|
72
|
+
const commonFields = {
|
|
73
|
+
from: transaction.from ?? address,
|
|
74
|
+
to: transaction.to,
|
|
75
|
+
data: transaction.data,
|
|
76
|
+
gas: toHexQuantity(transaction.gas),
|
|
77
|
+
nonce: toHexQuantity(transaction.nonce),
|
|
78
|
+
value: toHexQuantity(transaction.value),
|
|
79
|
+
};
|
|
80
|
+
const accessList = normalizeAccessList(transaction.accessList);
|
|
81
|
+
const tx = type === "0x2"
|
|
82
|
+
? {
|
|
83
|
+
...commonFields,
|
|
84
|
+
type,
|
|
85
|
+
...(accessList ? { accessList } : {}),
|
|
86
|
+
maxFeePerGas: toHexQuantity(transaction.maxFeePerGas),
|
|
87
|
+
maxPriorityFeePerGas: toHexQuantity(transaction.maxPriorityFeePerGas),
|
|
88
|
+
}
|
|
89
|
+
: type === "0x1"
|
|
90
|
+
? {
|
|
91
|
+
...commonFields,
|
|
92
|
+
type,
|
|
93
|
+
...(accessList ? { accessList } : {}),
|
|
94
|
+
gasPrice: toHexQuantity(transaction.gasPrice),
|
|
95
|
+
}
|
|
96
|
+
: {
|
|
97
|
+
...commonFields,
|
|
98
|
+
type,
|
|
99
|
+
gasPrice: toHexQuantity(transaction.gasPrice),
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
chain_id: resolvedChainId,
|
|
103
|
+
tx,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
const getTransactionParam = (params) => {
|
|
107
|
+
const candidate = params?.[0];
|
|
108
|
+
if (!isRecord(candidate)) {
|
|
109
|
+
throw new Error("eth_signTransaction requires a transaction object");
|
|
110
|
+
}
|
|
111
|
+
return candidate;
|
|
112
|
+
};
|
|
113
|
+
const toHexBytes = (value) => {
|
|
114
|
+
if (/^0x[0-9a-fA-F]*$/.test(value))
|
|
115
|
+
return value;
|
|
116
|
+
return `0x${Array.from(textEncoder.encode(value))
|
|
117
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
118
|
+
.join("")}`;
|
|
119
|
+
};
|
|
120
|
+
const getMessageParam = (address, params) => {
|
|
121
|
+
const [first, second] = params ?? [];
|
|
122
|
+
if (typeof second === "string" && second.toLowerCase() === address.toLowerCase()) {
|
|
123
|
+
return String(first ?? "");
|
|
124
|
+
}
|
|
125
|
+
if (typeof first === "string" && first.toLowerCase() === address.toLowerCase()) {
|
|
126
|
+
return String(second ?? "");
|
|
127
|
+
}
|
|
128
|
+
return String(first ?? "");
|
|
129
|
+
};
|
|
130
|
+
const getTypedDataParam = (address, params) => {
|
|
131
|
+
const [first, second] = params ?? [];
|
|
132
|
+
if (typeof first === "string" && first.toLowerCase() === address.toLowerCase()) {
|
|
133
|
+
return typeof second === "string"
|
|
134
|
+
? JSON.parse(second)
|
|
135
|
+
: (second ?? {});
|
|
136
|
+
}
|
|
137
|
+
return typeof second === "string"
|
|
138
|
+
? JSON.parse(second)
|
|
139
|
+
: (second ?? first ?? {});
|
|
140
|
+
};
|
|
141
|
+
function createEmbeddedProvider({ session, address, chain, }) {
|
|
142
|
+
const signer = new EvmSigner(address, session.client);
|
|
143
|
+
return {
|
|
144
|
+
async request(payload) {
|
|
145
|
+
switch (payload.method) {
|
|
146
|
+
case "eth_accounts":
|
|
147
|
+
case "eth_requestAccounts":
|
|
148
|
+
return [address];
|
|
149
|
+
case "eth_chainId": {
|
|
150
|
+
const chainId = evmChainIdMap[chain];
|
|
151
|
+
if (!chainId) {
|
|
152
|
+
throw new Error(`CubistProvider: chain ${chain} does not expose an EVM chainId`);
|
|
153
|
+
}
|
|
154
|
+
return `0x${chainId.toString(16)}`;
|
|
155
|
+
}
|
|
156
|
+
case "eth_signTransaction": {
|
|
157
|
+
const transaction = getTransactionParam(payload.params);
|
|
158
|
+
const signRequest = toCubistSignRequest(address, chain, transaction);
|
|
159
|
+
return (await signer.signTransaction(signRequest));
|
|
160
|
+
}
|
|
161
|
+
case "personal_sign": {
|
|
162
|
+
const message = getMessageParam(address, payload.params);
|
|
163
|
+
return (await signer.signEip191({ data: toHexBytes(message) }));
|
|
164
|
+
}
|
|
165
|
+
case "eth_signTypedData_v4": {
|
|
166
|
+
const typedData = getTypedDataParam(address, payload.params);
|
|
167
|
+
const domain = typedData.domain;
|
|
168
|
+
const chainId = domain?.chainId !== undefined
|
|
169
|
+
? Number(toBigIntQuantity(domain.chainId))
|
|
170
|
+
: evmChainIdMap[chain];
|
|
171
|
+
if (!chainId) {
|
|
172
|
+
throw new Error("CubistProvider: typed data signing requires an EVM chainId");
|
|
173
|
+
}
|
|
174
|
+
return (await signer.signEip712({
|
|
175
|
+
chain_id: chainId,
|
|
176
|
+
typed_data: typedData,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
default:
|
|
180
|
+
throw new Error(`CubistProvider: unsupported RPC method "${payload.method}"`);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
async disconnect() {
|
|
184
|
+
await session.client.revokeSession();
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
export class EmbeddedWalletAccountProvider {
|
|
189
|
+
constructor(provider) {
|
|
190
|
+
this.provider = provider;
|
|
191
|
+
}
|
|
192
|
+
async request(payload) {
|
|
193
|
+
return this.provider.request(payload);
|
|
194
|
+
}
|
|
195
|
+
async disconnect() {
|
|
196
|
+
await this.provider.disconnect();
|
|
197
|
+
}
|
|
198
|
+
async eth_accounts() {
|
|
199
|
+
return this.request({ method: "eth_accounts" });
|
|
200
|
+
}
|
|
201
|
+
async eth_chainId() {
|
|
202
|
+
return this.request({ method: "eth_chainId" });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
class WalletAccount {
|
|
206
|
+
static clearInstance() {
|
|
207
|
+
WalletAccount.instance = null;
|
|
208
|
+
WalletAccount.instanceToken = null;
|
|
209
|
+
WalletAccount.walletSession = null;
|
|
210
|
+
WalletAccount.cubeSignerSession = null;
|
|
211
|
+
}
|
|
212
|
+
static getWalletSession() {
|
|
213
|
+
return WalletAccount.walletSession;
|
|
214
|
+
}
|
|
215
|
+
static getCubeSignerSession() {
|
|
216
|
+
return WalletAccount.cubeSignerSession;
|
|
217
|
+
}
|
|
218
|
+
static async getInstance(oidcToken, authSource, cubeSignerConfig) {
|
|
219
|
+
if (WalletAccount.instance && WalletAccount.instanceToken === oidcToken) {
|
|
220
|
+
return WalletAccount.instance;
|
|
221
|
+
}
|
|
222
|
+
WalletAccount.clearInstance();
|
|
223
|
+
const auth = new CubeSignerAuth(cubeSignerConfig);
|
|
224
|
+
const cubeSignerSession = await auth.loginWithGoogle(oidcToken);
|
|
225
|
+
const keys = await cubeSignerSession.client.sessionKeys();
|
|
226
|
+
const evmKey = keys.find((key) => key.cached.key_type === "SecpEthAddr");
|
|
227
|
+
if (!evmKey) {
|
|
228
|
+
throw new Error("No EVM key found in CubeSigner session");
|
|
229
|
+
}
|
|
230
|
+
const address = evmKey.materialId;
|
|
231
|
+
const chain = "BSC";
|
|
232
|
+
const provider = createEmbeddedProvider({
|
|
233
|
+
session: cubeSignerSession,
|
|
234
|
+
address,
|
|
235
|
+
chain,
|
|
236
|
+
});
|
|
237
|
+
const wrappedProvider = new EmbeddedWalletAccountProvider(provider);
|
|
238
|
+
const capabilityPolicy = auth.defaultSessionPolicy
|
|
239
|
+
? createSessionCapabilityPolicy(auth.defaultSessionPolicy)
|
|
240
|
+
: undefined;
|
|
241
|
+
WalletAccount.instance = wrappedProvider;
|
|
242
|
+
WalletAccount.instanceToken = oidcToken;
|
|
243
|
+
WalletAccount.cubeSignerSession = cubeSignerSession;
|
|
244
|
+
WalletAccount.walletSession = {
|
|
245
|
+
address,
|
|
246
|
+
chain,
|
|
247
|
+
provider: wrappedProvider,
|
|
248
|
+
walletType: "social",
|
|
249
|
+
authSource,
|
|
250
|
+
sessionId: `${authSource}:${address.toLowerCase()}`,
|
|
251
|
+
expiresAt: capabilityPolicy?.expiresAt,
|
|
252
|
+
capabilities: [...cubistCapabilities],
|
|
253
|
+
sessionData: cubeSignerSession.sessionData,
|
|
254
|
+
chainContext: createChainContext(chain),
|
|
255
|
+
capabilityPolicy,
|
|
256
|
+
};
|
|
257
|
+
return wrappedProvider;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
WalletAccount.instance = null;
|
|
261
|
+
WalletAccount.instanceToken = null;
|
|
262
|
+
WalletAccount.walletSession = null;
|
|
263
|
+
WalletAccount.cubeSignerSession = null;
|
|
264
|
+
export default WalletAccount;
|
|
265
|
+
export function clearSocialAccountInstance() {
|
|
266
|
+
WalletAccount.clearInstance();
|
|
267
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { MarketDataProvider } from "../types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* - getSupportedTokens / getSupportedChains: from GET
|
|
5
|
-
* - getQuote:
|
|
6
|
-
* - getDepositAddress:
|
|
3
|
+
* Default `MarketDataProvider` backed by the merchant chains API.
|
|
4
|
+
* - getSupportedTokens / getSupportedChains: from GET `{merchantBase}/chains`
|
|
5
|
+
* - getQuote: local estimate until a dedicated quote API exists
|
|
6
|
+
* - getDepositAddress: session wallet address + fixed minimum (no deposit-address HTTP API here)
|
|
7
7
|
*/
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function createMarketDataProvider(): MarketDataProvider;
|
|
@@ -3,7 +3,7 @@ import { getEnv } from "../utils/env.js";
|
|
|
3
3
|
const DEFAULT_MERCHANT_BASE_URL = "https://merchant.tomo.services";
|
|
4
4
|
let cachedChains = null;
|
|
5
5
|
/** Fallback when chains API fails (network error, 4xx/5xx, parse error, missing base URL). */
|
|
6
|
-
const
|
|
6
|
+
const DEFAULT_CHAINS_FALLBACK = [
|
|
7
7
|
{
|
|
8
8
|
chain_id: "56",
|
|
9
9
|
network: "BSC",
|
|
@@ -36,10 +36,10 @@ async function fetchChainsFromApi() {
|
|
|
36
36
|
cachedChains = chains;
|
|
37
37
|
return chains;
|
|
38
38
|
}
|
|
39
|
-
return
|
|
39
|
+
return DEFAULT_CHAINS_FALLBACK;
|
|
40
40
|
}
|
|
41
41
|
catch {
|
|
42
|
-
return
|
|
42
|
+
return DEFAULT_CHAINS_FALLBACK;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function chainToChainInfo(chain) {
|
|
@@ -63,7 +63,7 @@ function deriveTokensFromChains(chains) {
|
|
|
63
63
|
}
|
|
64
64
|
return Array.from(bySymbol.values());
|
|
65
65
|
}
|
|
66
|
-
function
|
|
66
|
+
function computeDefaultQuote(request) {
|
|
67
67
|
const isStable = ["USDT", "USDC", "USD1"].includes(request.token);
|
|
68
68
|
const slippage = isStable ? "0.3" : "1.0";
|
|
69
69
|
const feeRate = request.direction === "withdraw" ? 0.001 : 0;
|
|
@@ -81,12 +81,12 @@ function computeMockQuote(request) {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
85
|
-
* - getSupportedTokens / getSupportedChains: from GET
|
|
86
|
-
* - getQuote:
|
|
87
|
-
* - getDepositAddress:
|
|
84
|
+
* Default `MarketDataProvider` backed by the merchant chains API.
|
|
85
|
+
* - getSupportedTokens / getSupportedChains: from GET `{merchantBase}/chains`
|
|
86
|
+
* - getQuote: local estimate until a dedicated quote API exists
|
|
87
|
+
* - getDepositAddress: session wallet address + fixed minimum (no deposit-address HTTP API here)
|
|
88
88
|
*/
|
|
89
|
-
export function
|
|
89
|
+
export function createMarketDataProvider() {
|
|
90
90
|
return {
|
|
91
91
|
async getSupportedTokens(_direction) {
|
|
92
92
|
const chains = await fetchChainsFromApi();
|
|
@@ -100,7 +100,7 @@ export function createMockMarketDataProvider() {
|
|
|
100
100
|
return list.map(chainToChainInfo);
|
|
101
101
|
},
|
|
102
102
|
async getQuote(request) {
|
|
103
|
-
return
|
|
103
|
+
return computeDefaultQuote(request);
|
|
104
104
|
},
|
|
105
105
|
async getDepositAddress(_token, _chain) {
|
|
106
106
|
const session = sessionStore.getState().session;
|
package/dist/ui/SignInModal.js
CHANGED
|
@@ -2,12 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { sessionStore } from "@ab-org/sdk-core";
|
|
4
4
|
import { getSDKConfig } from "../auth/config.js";
|
|
5
|
+
import { clearSocialAccountInstance as clearEmbeddedWalletAccount } from "../auth/walletAccount.js";
|
|
5
6
|
import { resolveSocialProviders } from "./SignInModal.shared.js";
|
|
6
7
|
import { SignInModalFooter, SignInModalFrame, SignInModalSocialSection, SignInModalWalletGrid, } from "./SignInModal.sections.js";
|
|
7
8
|
import { useSignInModalController } from "./useSignInModalController.js";
|
|
8
9
|
import { Toast } from "./components/Toast.js";
|
|
9
10
|
export function clearSocialAccountInstance() {
|
|
10
11
|
try {
|
|
12
|
+
clearEmbeddedWalletAccount();
|
|
11
13
|
const storage = typeof localStorage !== "undefined" ? localStorage : null;
|
|
12
14
|
const adapterId = storage?.getItem("ab:wallet:adapterId");
|
|
13
15
|
const session = sessionStore.getState().session;
|
|
@@ -22,6 +24,7 @@ export function clearSocialAccountInstance() {
|
|
|
22
24
|
storage?.removeItem("ab:wallet:adapterId");
|
|
23
25
|
}
|
|
24
26
|
catch {
|
|
27
|
+
clearEmbeddedWalletAccount();
|
|
25
28
|
sessionStore.clearSession();
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -66,6 +66,20 @@ const IconFrame = ({ background, children, }) => (_jsx("div", { style: {
|
|
|
66
66
|
justifyContent: "center",
|
|
67
67
|
overflow: "hidden",
|
|
68
68
|
}, children: children }));
|
|
69
|
+
const MetaMaskWalletIcon = () => (_jsx(IconFrame, { background: "#1A0F07", children: _jsxs("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", children: [_jsx("path", { d: "M8 6L15 11L12 14L8 6Z", fill: "#E17726" }), _jsx("path", { d: "M24 6L17 11L20 14L24 6Z", fill: "#E27625" }), _jsx("path", { d: "M11 19L15 22V17L11 19Z", fill: "#F6851B" }), _jsx("path", { d: "M21 19L17 22V17L21 19Z", fill: "#F6851B" }), _jsx("path", { d: "M12 14L15 11V17L11 19L12 14Z", fill: "#763D16" }), _jsx("path", { d: "M20 14L17 11V17L21 19L20 14Z", fill: "#763D16" })] }) }));
|
|
70
|
+
const OKXWalletIcon = () => (_jsx(IconFrame, { background: "#FFFFFF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "11", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "2", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "2", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "11", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" })] }) }));
|
|
71
|
+
const CoinbaseWalletIcon = () => (_jsx(IconFrame, { background: "#0052FF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("circle", { cx: "15", cy: "15", r: "10", stroke: "white", strokeWidth: "4" }), _jsx("rect", { x: "9", y: "13", width: "12", height: "4", rx: "2", fill: "white" })] }) }));
|
|
72
|
+
const TrustWalletIcon = () => (_jsx(IconFrame, { background: "#3375FF", children: _jsxs("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: [_jsx("path", { d: "M14 4L21 6.6V12.8C21 17.1 18.1 20.9 14 22.4C9.9 20.9 7 17.1 7 12.8V6.6L14 4Z", fill: "white" }), _jsx("path", { d: "M14 8L17 9.1V12.3C17 14.7 15.7 16.8 14 17.6C12.3 16.8 11 14.7 11 12.3V9.1L14 8Z", fill: "#3375FF" })] }) }));
|
|
73
|
+
const PhantomWalletIcon = () => (_jsx(IconFrame, { background: "linear-gradient(135deg, #6C47FF 0%, #9B6BFF 100%)", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("path", { d: "M8 18.5C8 14.4 11.2 11 15.3 11H20.4C21.8 11 23 12.2 23 13.6C23 15 21.8 16.2 20.4 16.2H14.7", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }), _jsx("path", { d: "M10.5 14H19.5", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }), _jsx("circle", { cx: "12", cy: "20", r: "1.4", fill: "white" }), _jsx("circle", { cx: "18", cy: "20", r: "1.4", fill: "white" })] }) }));
|
|
74
|
+
const RabbyWalletIcon = () => (_jsx(IconFrame, { background: "#EBF2FF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("path", { d: "M11 7L13.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }), _jsx("path", { d: "M19 7L16.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }), _jsx("rect", { x: "8", y: "12", width: "14", height: "11", rx: "6", fill: "#7084FF" }), _jsx("circle", { cx: "13", cy: "17", r: "1.4", fill: "white" }), _jsx("circle", { cx: "17", cy: "17", r: "1.4", fill: "white" }), _jsx("path", { d: "M13 20C13.6 20.4 14.3 20.6 15 20.6C15.7 20.6 16.4 20.4 17 20", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round" })] }) }));
|
|
75
|
+
/** Rainbow icon from wallet-adaptor-base (rainbowWallet.svg) */
|
|
76
|
+
const RainbowWalletIcon = () => (_jsx(IconFrame, { background: "linear-gradient(180deg, #174299 0%, #001E59 100%)", children: _jsxs("svg", { width: "32", height: "32", viewBox: "0 0 120 120", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [_jsxs("defs", { children: [_jsxs("radialGradient", { id: "rainbow_r1", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(74)", children: [_jsx("stop", { offset: "0.770277", stopColor: "#FF4000" }), _jsx("stop", { offset: "1", stopColor: "#8754C9" })] }), _jsxs("linearGradient", { id: "rainbow_l2", x1: "83", y1: "97", x2: "100", y2: "97", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FF4000" }), _jsx("stop", { offset: "1", stopColor: "#8754C9" })] }), _jsxs("linearGradient", { id: "rainbow_l3", x1: "23", y1: "20", x2: "23", y2: "37", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#8754C9" }), _jsx("stop", { offset: "1", stopColor: "#FF4000" })] }), _jsxs("radialGradient", { id: "rainbow_r4", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(58)", children: [_jsx("stop", { offset: "0.723929", stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("linearGradient", { id: "rainbow_l5", x1: "68", y1: "97", x2: "84", y2: "97", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("linearGradient", { id: "rainbow_l6", x1: "23", y1: "52", x2: "23", y2: "36", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("radialGradient", { id: "rainbow_r7", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(42)", children: [_jsx("stop", { offset: "0.59513", stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] }), _jsxs("radialGradient", { id: "rainbow_r8", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(51 97) scale(17 45.3333)", children: [_jsx("stop", { stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] }), _jsxs("radialGradient", { id: "rainbow_r9", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(23 69) rotate(-90) scale(17 322.37)", children: [_jsx("stop", { stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] })] }), _jsx("path", { d: "M20 38H26C56.9279 38 82 63.0721 82 94V100H94C97.3137 100 100 97.3137 100 94C100 53.1309 66.8691 20 26 20C22.6863 20 20 22.6863 20 26V38Z", fill: "url(#rainbow_r1)" }), _jsx("path", { d: "M84 94H100C100 97.3137 97.3137 100 94 100H84V94Z", fill: "url(#rainbow_l2)" }), _jsx("path", { d: "M26 20L26 36H20L20 26C20 22.6863 22.6863 20 26 20Z", fill: "url(#rainbow_l3)" }), _jsx("path", { d: "M20 36H26C58.0325 36 84 61.9675 84 94V100H66V94C66 71.9086 48.0914 54 26 54H20V36Z", fill: "url(#rainbow_r4)" }), _jsx("path", { d: "M68 94H84V100H68V94Z", fill: "url(#rainbow_l5)" }), _jsx("path", { d: "M20 52L20 36L26 36L26 52H20Z", fill: "url(#rainbow_l6)" }), _jsx("path", { d: "M20 62C20 65.3137 22.6863 68 26 68C40.3594 68 52 79.6406 52 94C52 97.3137 54.6863 100 58 100H68V94C68 70.804 49.196 52 26 52H20V62Z", fill: "url(#rainbow_r7)" }), _jsx("path", { d: "M52 94H68V100H58C54.6863 100 52 97.3137 52 94Z", fill: "url(#rainbow_r8)" }), _jsx("path", { d: "M26 68C22.6863 68 20 65.3137 20 62L20 52L26 52L26 68Z", fill: "url(#rainbow_r9)" })] }) }));
|
|
77
|
+
/** Zerion icon from wallet-adaptor-base (zerionWallet.svg) */
|
|
78
|
+
const ZerionWalletIcon = () => (_jsx(IconFrame, { background: "#2962EF", children: _jsx("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: _jsx("path", { fill: "#fff", d: "M6.073 7c-.48 0-.665.593-.262.841l10.073 6.074a.577.577 0 0 0 .758-.139l4.43-5.814c.3-.404-.004-.962-.525-.962H6.073ZM21.904 21c.48 0 .67-.596.267-.844l-10.075-6.073a.569.569 0 0 0-.751.146l-4.437 5.813c-.301.404.012.958.534.958h14.462Z" }) }) }));
|
|
79
|
+
/** Brave Wallet icon from wallet-adaptor-base (braveWallet.svg), scaled */
|
|
80
|
+
const BraveWalletIcon = () => (_jsx(IconFrame, { background: "#FFF", children: _jsxs("svg", { width: "32", height: "32", viewBox: "-100 -100 2970 2970", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [_jsxs("defs", { children: [_jsxs("linearGradient", { id: "brave_a", y1: "51%", y2: "51%", children: [_jsx("stop", { offset: "0.4", stopColor: "#f50" }), _jsx("stop", { offset: "0.6", stopColor: "#ff2000" })] }), _jsxs("linearGradient", { id: "brave_b", x1: "2%", y1: "51%", x2: "51%", y2: "51%", children: [_jsx("stop", { offset: "0", stopColor: "#ff452a" }), _jsx("stop", { offset: "1", stopColor: "#ff2000" })] })] }), _jsx("path", { fill: "url(#brave_a)", d: "m2395 723 60-147-170-176c-92-92-288-38-288-38l-222-252H992L769 363s-196-53-288 37L311 575l60 147-75 218 250 953c52 204 87 283 234 387l457 310c44 27 98 74 147 74s103-47 147-74l457-310c147-104 182-183 234-387l250-953z" }), _jsx("path", { fill: "#fff", d: "M1935 524s287 347 287 420c0 75-36 94-72 133l-215 230c-20 20-63 54-38 113 25 60 60 134 20 210-40 77-110 128-155 120a820 820 0 0 1-190-90c-38-25-160-126-160-165s126-110 150-124c23-16 130-78 132-102s2-30-30-90-88-140-80-192c10-52 100-80 167-105l207-78c16-8 12-15-36-20-48-4-183-22-244-5s-163 43-173 57c-8 14-16 14-7 62l58 315c4 40 12 67-30 77-44 10-117 27-142 27s-99-17-142-27-35-37-30-77c4-40 48-268 57-315 10-48 1-48-7-62-10-14-113-40-174-57-60-17-196 1-244 6-48 4-52 10-36 20l207 77c66 25 158 53 167 105 10 53-47 132-80 192s-32 66-30 90 110 86 132 102c24 15 150 85 150 124s-119 140-159 165a820 820 0 0 1-190 90c-45 8-115-43-156-120-40-76-4-150 20-210 25-60-17-92-38-113l-215-230c-35-37-71-57-71-131s287-420 287-420l273 44c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47zm-215 1328c18 10 7 32-10 44l-254 198c-20 20-52 50-73 50s-52-30-73-50a13200 13200 0 0 0-255-198c-16-12-27-33-10-44l150-80a870 870 0 0 1 188-73c15 0 110 34 187 73l150 80z" }), _jsx("path", { fill: "url(#brave_b)", d: "m1999 363-224-253H992L769 363s-196-53-288 37c0 0 260-23 350 123l276 47c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47 90-146 350-123 350-123-92-92-288-38-288-38" })] }) }));
|
|
81
|
+
/** Bitget icon from wallet-adaptor-base (bitgetWallet.svg) */
|
|
82
|
+
const BitgetWalletIcon = () => (_jsx(IconFrame, { background: "#001F29", children: _jsx("svg", { width: "28", height: "28", viewBox: "0 0 512 512", fill: "none", children: _jsx("path", { d: "M219.948 95.7022C201.623 95.6929 183.33 95.6835 164.941 95.7116C153.822 95.7116 149.651 109.671 157.921 117.939L283.098 243.117C287.004 246.69 289.441 250.574 289.53 255.693C289.441 260.812 287.004 264.696 283.098 268.269L157.921 393.446C149.651 401.715 153.822 415.674 164.941 415.674C183.33 415.702 201.623 415.693 219.948 415.683C229.122 415.679 238.305 415.674 247.511 415.674C259.555 415.674 266.72 409.24 273.154 402.805L386.047 289.912C395.057 280.902 403.119 268.939 403.009 255.693C403.119 242.447 395.057 230.484 386.047 221.474L273.154 108.58C266.72 102.146 259.555 95.7116 247.511 95.7116C238.305 95.7116 229.122 95.7069 219.948 95.7022Z", fill: "#00F0FF" }) }) }));
|
|
69
83
|
const walletIconTheme = {
|
|
70
84
|
metamask: "#F6851B",
|
|
71
85
|
okx: "#050608",
|
|
@@ -84,4 +98,29 @@ const WalletPlaceholder = ({ walletId, name }) => (_jsx(IconFrame, { background:
|
|
|
84
98
|
color: walletIconTheme[walletId] ? "#FFFFFF" : colors.textSecondary,
|
|
85
99
|
fontFamily: fonts.family,
|
|
86
100
|
}, children: name.slice(0, 2).toUpperCase() }) }));
|
|
87
|
-
export const DefaultWalletIcon = ({ walletId, name, }) =>
|
|
101
|
+
export const DefaultWalletIcon = ({ walletId, name, }) => {
|
|
102
|
+
switch (walletId) {
|
|
103
|
+
case "metamask":
|
|
104
|
+
return _jsx(MetaMaskWalletIcon, {});
|
|
105
|
+
case "okx":
|
|
106
|
+
return _jsx(OKXWalletIcon, {});
|
|
107
|
+
case "coinbase":
|
|
108
|
+
return _jsx(CoinbaseWalletIcon, {});
|
|
109
|
+
case "trust":
|
|
110
|
+
return _jsx(TrustWalletIcon, {});
|
|
111
|
+
case "phantom":
|
|
112
|
+
return _jsx(PhantomWalletIcon, {});
|
|
113
|
+
case "rabby":
|
|
114
|
+
return _jsx(RabbyWalletIcon, {});
|
|
115
|
+
case "rainbow":
|
|
116
|
+
return _jsx(RainbowWalletIcon, {});
|
|
117
|
+
case "zerion":
|
|
118
|
+
return _jsx(ZerionWalletIcon, {});
|
|
119
|
+
case "brave":
|
|
120
|
+
return _jsx(BraveWalletIcon, {});
|
|
121
|
+
case "bitget":
|
|
122
|
+
return _jsx(BitgetWalletIcon, {});
|
|
123
|
+
default:
|
|
124
|
+
return _jsx(WalletPlaceholder, { walletId: walletId, name: name });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { GoogleCredential } from "../auth/google.js";
|
|
2
|
+
import type { TwitterAuthResult } from "../auth/twitter.js";
|
|
3
3
|
import { type CubeSignerSession, type WalletSession } from "@ab-org/sdk-core";
|
|
4
4
|
import type { WalletItem } from "./signInTypes.js";
|
|
5
5
|
export interface SignInModalControllerOptions {
|
|
@@ -1,47 +1,41 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
2
|
import { getSDKConfig } from "../auth/config.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { createOidcRelayAuth } from "../auth/oidcRelay.js";
|
|
4
|
+
import WalletAccount from "../auth/walletAccount.js";
|
|
5
|
+
import { getEnv } from "../utils/env.js";
|
|
6
|
+
import { describeSessionCapabilityPolicy, WalletConnector, createDefaultInjectedWalletRegistry, } from "@ab-org/sdk-core";
|
|
6
7
|
import { resolveWalletItems } from "./SignInModal.shared.js";
|
|
8
|
+
function resolveOidcStage() {
|
|
9
|
+
return getEnv("STAGE").toLowerCase() === "prod" ? "prod" : "dev";
|
|
10
|
+
}
|
|
7
11
|
export const useSignInModalController = ({ wallets, initialVisibleCount, onGoogleLogin, onTwitterLogin, onCubeSignerSession, onWalletConnected, onSocialLogin, onWalletSelect, }) => {
|
|
8
12
|
const [expanded, setExpanded] = useState(false);
|
|
9
13
|
const [loadingProvider, setLoadingProvider] = useState(null);
|
|
10
14
|
const [loadingWalletId, setLoadingWalletId] = useState(null);
|
|
11
15
|
const defaultWalletRegistry = useMemo(() => createDefaultInjectedWalletRegistry(), []);
|
|
12
16
|
const sdkConfig = getSDKConfig();
|
|
13
|
-
const cubistProvider = useMemo(() => {
|
|
14
|
-
if (!sdkConfig.cubeSigner)
|
|
15
|
-
return null;
|
|
16
|
-
return new CubistSocialProvider({
|
|
17
|
-
...sdkConfig.cubeSigner,
|
|
18
|
-
defaultSessionPolicy: sdkConfig.signIn?.sessionPolicy ?? sdkConfig.cubeSigner.defaultSessionPolicy,
|
|
19
|
-
});
|
|
20
|
-
}, [sdkConfig.cubeSigner, sdkConfig.signIn?.sessionPolicy]);
|
|
21
17
|
const defaultWalletConnector = useMemo(() => new WalletConnector([
|
|
22
18
|
...defaultWalletRegistry.map((item) => item.provider),
|
|
23
|
-
|
|
24
|
-
]), [cubistProvider, defaultWalletRegistry]);
|
|
19
|
+
]), [defaultWalletRegistry]);
|
|
25
20
|
const resolvedWallets = useMemo(() => resolveWalletItems(wallets, defaultWalletRegistry), [defaultWalletRegistry, wallets]);
|
|
26
21
|
const showExpandToggle = resolvedWallets.length > initialVisibleCount;
|
|
27
22
|
const visibleWallets = expanded ? resolvedWallets : resolvedWallets.slice(0, initialVisibleCount);
|
|
28
23
|
const isBusy = !!loadingProvider || !!loadingWalletId;
|
|
29
|
-
const confirmCapabilitySession = async (providerId,
|
|
30
|
-
const cubist = cubistForPolicy ?? cubistProvider;
|
|
24
|
+
const confirmCapabilitySession = async (providerId, cubeSignerSession) => {
|
|
31
25
|
const confirmation = sdkConfig.signIn?.sessionConfirmation;
|
|
32
|
-
const policy =
|
|
26
|
+
const policy = cubeSignerSession && sdkConfig.cubeSigner
|
|
27
|
+
? {
|
|
28
|
+
id: "preview",
|
|
29
|
+
...(sdkConfig.signIn?.sessionPolicy ?? sdkConfig.cubeSigner.defaultSessionPolicy),
|
|
30
|
+
}
|
|
31
|
+
: undefined;
|
|
33
32
|
if (confirmation?.enabled === false || !policy) {
|
|
34
33
|
return true;
|
|
35
34
|
}
|
|
36
35
|
if (typeof window === "undefined" || typeof window.confirm !== "function") {
|
|
37
36
|
return true;
|
|
38
37
|
}
|
|
39
|
-
const lines = describeSessionCapabilityPolicy(
|
|
40
|
-
? {
|
|
41
|
-
id: "preview",
|
|
42
|
-
...cubist.cubeSignerAuth.defaultSessionPolicy,
|
|
43
|
-
}
|
|
44
|
-
: undefined);
|
|
38
|
+
const lines = describeSessionCapabilityPolicy(policy);
|
|
45
39
|
const message = [
|
|
46
40
|
confirmation?.title ?? "Authorize smart-wallet session",
|
|
47
41
|
confirmation?.message ?? `Continue with ${providerId} and create a capability session?`,
|
|
@@ -51,21 +45,6 @@ export const useSignInModalController = ({ wallets, initialVisibleCount, onGoogl
|
|
|
51
45
|
.join("\n");
|
|
52
46
|
return window.confirm(message);
|
|
53
47
|
};
|
|
54
|
-
const getCubistAndConnector = (config) => {
|
|
55
|
-
if (!config.cubeSigner)
|
|
56
|
-
return { cubist: null, connector: defaultWalletConnector };
|
|
57
|
-
if (cubistProvider)
|
|
58
|
-
return { cubist: cubistProvider, connector: defaultWalletConnector };
|
|
59
|
-
const cubist = new CubistSocialProvider({
|
|
60
|
-
...config.cubeSigner,
|
|
61
|
-
defaultSessionPolicy: config.signIn?.sessionPolicy ?? config.cubeSigner.defaultSessionPolicy,
|
|
62
|
-
});
|
|
63
|
-
const connector = new WalletConnector([
|
|
64
|
-
...defaultWalletRegistry.map((item) => item.provider),
|
|
65
|
-
cubist,
|
|
66
|
-
]);
|
|
67
|
-
return { cubist, connector };
|
|
68
|
-
};
|
|
69
48
|
const handleSocialClick = async (providerId) => {
|
|
70
49
|
setLoadingProvider(providerId);
|
|
71
50
|
try {
|
|
@@ -73,55 +52,57 @@ export const useSignInModalController = ({ wallets, initialVisibleCount, onGoogl
|
|
|
73
52
|
if (!config.cubeSigner) {
|
|
74
53
|
throw new Error("cubeSigner config is required for social login");
|
|
75
54
|
}
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (!confirmed)
|
|
82
|
-
return null;
|
|
55
|
+
const auth = createOidcRelayAuth({
|
|
56
|
+
stage: resolveOidcStage(),
|
|
57
|
+
googleClientId: config.googleClientId ?? "",
|
|
58
|
+
xClientId: config.twitterClientId ?? "",
|
|
59
|
+
});
|
|
83
60
|
if (providerId === "google") {
|
|
84
61
|
if (!config.googleClientId) {
|
|
85
62
|
throw new Error("googleClientId is required for Google sign-in");
|
|
86
63
|
}
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const cubeSignerSession =
|
|
64
|
+
const oidcToken = await auth.loginByGoogle();
|
|
65
|
+
const authSource = "google";
|
|
66
|
+
WalletAccount.clearInstance();
|
|
67
|
+
await WalletAccount.getInstance(oidcToken, authSource, config.cubeSigner);
|
|
68
|
+
const session = WalletAccount.getWalletSession();
|
|
69
|
+
const cubeSignerSession = WalletAccount.getCubeSignerSession();
|
|
70
|
+
const confirmed = await confirmCapabilitySession(providerId, cubeSignerSession);
|
|
71
|
+
if (!confirmed) {
|
|
72
|
+
WalletAccount.clearInstance();
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
onGoogleLogin?.({ idToken: oidcToken });
|
|
93
76
|
if (cubeSignerSession)
|
|
94
77
|
onCubeSignerSession?.(cubeSignerSession);
|
|
95
78
|
onSocialLogin?.(providerId);
|
|
79
|
+
if (!session) {
|
|
80
|
+
throw new Error("Failed to build wallet session from Google login");
|
|
81
|
+
}
|
|
96
82
|
return session;
|
|
97
83
|
}
|
|
98
84
|
if (providerId === "x") {
|
|
99
85
|
if (!config.twitterClientId) {
|
|
100
86
|
throw new Error("twitterClientId is required for X sign-in");
|
|
101
87
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
88
|
+
const oidcToken = await auth.loginByX();
|
|
89
|
+
const authSource = "twitter";
|
|
90
|
+
WalletAccount.clearInstance();
|
|
91
|
+
await WalletAccount.getInstance(oidcToken, authSource, config.cubeSigner);
|
|
92
|
+
const session = WalletAccount.getWalletSession();
|
|
93
|
+
const cubeSignerSession = WalletAccount.getCubeSignerSession();
|
|
94
|
+
const confirmed = await confirmCapabilitySession(providerId, cubeSignerSession);
|
|
95
|
+
if (!confirmed) {
|
|
96
|
+
WalletAccount.clearInstance();
|
|
97
|
+
return null;
|
|
108
98
|
}
|
|
109
|
-
|
|
110
|
-
onTwitterLogin?.(result);
|
|
111
|
-
const session = await connector.connect(cubist.id, {
|
|
112
|
-
payload: {
|
|
113
|
-
type: "twitter",
|
|
114
|
-
params: {
|
|
115
|
-
code: result.code,
|
|
116
|
-
codeVerifier: result.codeVerifier,
|
|
117
|
-
redirectUri,
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
const cubeSignerSession = cubist.cubeSignerSession;
|
|
99
|
+
onTwitterLogin?.({ code: "", codeVerifier: "", state: "" });
|
|
122
100
|
if (cubeSignerSession)
|
|
123
101
|
onCubeSignerSession?.(cubeSignerSession);
|
|
124
102
|
onSocialLogin?.(providerId);
|
|
103
|
+
if (!session) {
|
|
104
|
+
throw new Error("Failed to build wallet session from X login");
|
|
105
|
+
}
|
|
125
106
|
return session;
|
|
126
107
|
}
|
|
127
108
|
throw new Error(`Unsupported social provider: ${providerId}`);
|
|
@@ -152,7 +133,7 @@ export const useSignInModalController = ({ wallets, initialVisibleCount, onGoogl
|
|
|
152
133
|
return session;
|
|
153
134
|
}
|
|
154
135
|
catch (error) {
|
|
155
|
-
console.error(`[
|
|
136
|
+
console.error(`[predicate-market-sdk] Wallet connect failed for ${walletId}:`, error);
|
|
156
137
|
throw error;
|
|
157
138
|
}
|
|
158
139
|
finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ab-org/predicate-market-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/**/*",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"registry": "https://registry.npmjs.org/"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@cubist-labs/cubesigner-sdk": "^0.4.219",
|
|
23
24
|
"axios": "^1.13.6",
|
|
24
25
|
"qrcode-generator": "^2.0.4",
|
|
25
26
|
"@ab-org/sdk-core": "0.0.1"
|