@pollar/core 0.5.0 → 0.5.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/dist/index.d.mts +27 -5
- package/dist/index.d.ts +27 -5
- package/dist/index.js +251 -195
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +251 -195
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -767,8 +767,176 @@ var PollarFlowError = class extends Error {
|
|
|
767
767
|
}
|
|
768
768
|
};
|
|
769
769
|
|
|
770
|
+
// src/wallets/FreighterAdapter.ts
|
|
771
|
+
var import_freighter_api = __toESM(require_index_min());
|
|
772
|
+
|
|
773
|
+
// src/wallets/types.ts
|
|
774
|
+
var WalletType = /* @__PURE__ */ ((WalletType2) => {
|
|
775
|
+
WalletType2["FREIGHTER"] = "freighter";
|
|
776
|
+
WalletType2["ALBEDO"] = "albedo";
|
|
777
|
+
return WalletType2;
|
|
778
|
+
})(WalletType || {});
|
|
779
|
+
|
|
780
|
+
// src/wallets/FreighterAdapter.ts
|
|
781
|
+
var FreighterAdapter = class {
|
|
782
|
+
constructor() {
|
|
783
|
+
this.type = "freighter" /* FREIGHTER */;
|
|
784
|
+
}
|
|
785
|
+
async isAvailable() {
|
|
786
|
+
try {
|
|
787
|
+
return await (0, import_freighter_api.isConnected)();
|
|
788
|
+
} catch {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
async connect() {
|
|
793
|
+
const connected = await (0, import_freighter_api.isConnected)();
|
|
794
|
+
if (!connected) {
|
|
795
|
+
throw new Error("Freighter wallet is not installed");
|
|
796
|
+
}
|
|
797
|
+
const allowed = await (0, import_freighter_api.isAllowed)();
|
|
798
|
+
if (!allowed) {
|
|
799
|
+
await (0, import_freighter_api.setAllowed)();
|
|
800
|
+
}
|
|
801
|
+
const userInfo = await (0, import_freighter_api.getUserInfo)();
|
|
802
|
+
if (!userInfo?.publicKey) {
|
|
803
|
+
throw new Error("Failed to get user information from Freighter");
|
|
804
|
+
}
|
|
805
|
+
return { address: userInfo.publicKey, publicKey: userInfo.publicKey };
|
|
806
|
+
}
|
|
807
|
+
async disconnect() {
|
|
808
|
+
}
|
|
809
|
+
async getPublicKey() {
|
|
810
|
+
try {
|
|
811
|
+
const allowed = await (0, import_freighter_api.isAllowed)();
|
|
812
|
+
if (!allowed) return null;
|
|
813
|
+
const userInfo = await (0, import_freighter_api.getUserInfo)();
|
|
814
|
+
return userInfo?.publicKey ?? null;
|
|
815
|
+
} catch {
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
async getNetwork() {
|
|
820
|
+
return (0, import_freighter_api.getNetwork)();
|
|
821
|
+
}
|
|
822
|
+
async signTransaction(xdr, options) {
|
|
823
|
+
const result = await (0, import_freighter_api.signTransaction)(xdr, {
|
|
824
|
+
network: options?.network,
|
|
825
|
+
networkPassphrase: options?.networkPassphrase,
|
|
826
|
+
accountToSign: options?.accountToSign
|
|
827
|
+
});
|
|
828
|
+
if (!result || typeof result !== "string") {
|
|
829
|
+
throw new Error("Invalid response from Freighter");
|
|
830
|
+
}
|
|
831
|
+
return { signedTxXdr: result };
|
|
832
|
+
}
|
|
833
|
+
async signAuthEntry(entryXdr, options) {
|
|
834
|
+
const result = await (0, import_freighter_api.signAuthEntry)(entryXdr, { accountToSign: options?.accountToSign });
|
|
835
|
+
if (!result || typeof result !== "string") {
|
|
836
|
+
throw new Error("Invalid response from Freighter");
|
|
837
|
+
}
|
|
838
|
+
return { signedAuthEntry: result };
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
// src/wallets/AlbedoAdapter.ts
|
|
843
|
+
function openAlbedoPopup(url) {
|
|
844
|
+
const popup = window.open(url, "albedo", "width=420,height=720,resizable=yes,scrollbars=yes");
|
|
845
|
+
if (!popup) {
|
|
846
|
+
throw new Error("Failed to open Albedo popup (blocked by browser)");
|
|
847
|
+
}
|
|
848
|
+
return popup;
|
|
849
|
+
}
|
|
850
|
+
function waitForAlbedoPopup() {
|
|
851
|
+
return new Promise((resolve, reject) => {
|
|
852
|
+
const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
|
|
853
|
+
function handler(event) {
|
|
854
|
+
if (event.origin !== window.location.origin || event.data?.type !== "ALBEDO_RESULT") return;
|
|
855
|
+
clearTimeout(timeout);
|
|
856
|
+
window.removeEventListener("message", handler);
|
|
857
|
+
resolve(event.data.payload);
|
|
858
|
+
}
|
|
859
|
+
window.addEventListener("message", handler);
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
function waitForAlbedoResult() {
|
|
863
|
+
return new Promise((resolve, reject) => {
|
|
864
|
+
const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
|
|
865
|
+
const parseResult = () => {
|
|
866
|
+
const params = new URLSearchParams(window.location.search);
|
|
867
|
+
if (!params.has("pubkey") && !params.has("signed_envelope_xdr") && !params.has("signed_xdr")) return;
|
|
868
|
+
clearTimeout(timeout);
|
|
869
|
+
const result = {};
|
|
870
|
+
params.forEach((value, key) => {
|
|
871
|
+
result[key] = value;
|
|
872
|
+
});
|
|
873
|
+
window.history.replaceState({}, document.title, window.location.pathname);
|
|
874
|
+
resolve(result);
|
|
875
|
+
};
|
|
876
|
+
parseResult();
|
|
877
|
+
window.addEventListener("popstate", parseResult);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
var AlbedoAdapter = class {
|
|
881
|
+
constructor() {
|
|
882
|
+
this.type = "albedo" /* ALBEDO */;
|
|
883
|
+
}
|
|
884
|
+
async isAvailable() {
|
|
885
|
+
return typeof window !== "undefined";
|
|
886
|
+
}
|
|
887
|
+
async connect() {
|
|
888
|
+
const url = new URL("https://albedo.link");
|
|
889
|
+
url.searchParams.set("intent", "public-key");
|
|
890
|
+
url.searchParams.set("app_name", "Pollar");
|
|
891
|
+
url.searchParams.set("network", "testnet");
|
|
892
|
+
url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
|
|
893
|
+
url.searchParams.set("origin", window.location.origin);
|
|
894
|
+
openAlbedoPopup(url.toString());
|
|
895
|
+
const result = await waitForAlbedoPopup();
|
|
896
|
+
if (!result.pubkey) {
|
|
897
|
+
throw new Error("Albedo connection rejected");
|
|
898
|
+
}
|
|
899
|
+
return { address: result.pubkey, publicKey: result.pubkey };
|
|
900
|
+
}
|
|
901
|
+
async disconnect() {
|
|
902
|
+
}
|
|
903
|
+
async getPublicKey() {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
async getNetwork() {
|
|
907
|
+
throw new Error("Albedo does not expose network");
|
|
908
|
+
}
|
|
909
|
+
async signTransaction(xdr, _options) {
|
|
910
|
+
const url = new URL("https://albedo.link");
|
|
911
|
+
url.searchParams.set("intent", "tx");
|
|
912
|
+
url.searchParams.set("xdr", xdr);
|
|
913
|
+
url.searchParams.set("app_name", "Pollar");
|
|
914
|
+
url.searchParams.set("network", "testnet");
|
|
915
|
+
url.searchParams.set("callback", window.location.href);
|
|
916
|
+
url.searchParams.set("origin", window.location.origin);
|
|
917
|
+
window.location.href = url.toString();
|
|
918
|
+
const result = await waitForAlbedoResult();
|
|
919
|
+
if (!result.signed_envelope_xdr) throw new Error("Albedo signing rejected");
|
|
920
|
+
return { signedTxXdr: result.signed_envelope_xdr };
|
|
921
|
+
}
|
|
922
|
+
async signAuthEntry(entryXdr, _options) {
|
|
923
|
+
const url = new URL("https://albedo.link");
|
|
924
|
+
url.searchParams.set("intent", "sign-auth-entry");
|
|
925
|
+
url.searchParams.set("xdr", entryXdr);
|
|
926
|
+
url.searchParams.set("app_name", "Pollar");
|
|
927
|
+
url.searchParams.set("network", "testnet");
|
|
928
|
+
url.searchParams.set("callback", window.location.href);
|
|
929
|
+
url.searchParams.set("origin", window.location.origin);
|
|
930
|
+
window.location.href = url.toString();
|
|
931
|
+
const result = await waitForAlbedoResult();
|
|
932
|
+
if (!result.signed_xdr) throw new Error("Albedo auth entry signing rejected");
|
|
933
|
+
return { signedAuthEntry: result.signed_xdr };
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
|
|
770
937
|
// src/client/session.ts
|
|
771
938
|
var STORAGE_KEY = "pollar:session";
|
|
939
|
+
var WALLET_TYPE_KEY = "pollar:walletType";
|
|
772
940
|
function isValidSession(value) {
|
|
773
941
|
if (typeof value !== "object" || value === null) {
|
|
774
942
|
console.warn("[PollarClient:session] Invalid session \u2014 value is not an object");
|
|
@@ -904,8 +1072,15 @@ function writeStorage(session) {
|
|
|
904
1072
|
}
|
|
905
1073
|
function removeStorage() {
|
|
906
1074
|
localStorage.removeItem(STORAGE_KEY);
|
|
1075
|
+
localStorage.removeItem(WALLET_TYPE_KEY);
|
|
907
1076
|
console.info("[PollarClient:session] Session removed from storage");
|
|
908
1077
|
}
|
|
1078
|
+
function writeWalletType(type) {
|
|
1079
|
+
localStorage.setItem(WALLET_TYPE_KEY, type);
|
|
1080
|
+
}
|
|
1081
|
+
function readWalletType() {
|
|
1082
|
+
return localStorage.getItem(WALLET_TYPE_KEY);
|
|
1083
|
+
}
|
|
909
1084
|
|
|
910
1085
|
// src/client/stream.ts
|
|
911
1086
|
function abortableDelay(ms, signal) {
|
|
@@ -979,7 +1154,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
979
1154
|
}
|
|
980
1155
|
|
|
981
1156
|
// src/client/auth/authenticate.ts
|
|
982
|
-
async function authenticate(clientSessionId, deps) {
|
|
1157
|
+
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
983
1158
|
const { api, signal, setAuthState, storeSession, clearSession } = deps;
|
|
984
1159
|
setAuthState({ step: "authenticating" });
|
|
985
1160
|
await streamUntilFound(api, clientSessionId, (data2) => data2?.status === "READY", 200, signal);
|
|
@@ -988,6 +1163,16 @@ async function authenticate(clientSessionId, deps) {
|
|
|
988
1163
|
signal
|
|
989
1164
|
});
|
|
990
1165
|
if (data?.code === "SDK_LOGIN_SUCCESS" && isValidSession(data?.content)) {
|
|
1166
|
+
if (expectedWallet && data.content.data.providers.wallet?.address !== expectedWallet) {
|
|
1167
|
+
setAuthState({
|
|
1168
|
+
step: "error",
|
|
1169
|
+
previousStep: "authenticating",
|
|
1170
|
+
message: "Wallet mismatch: session wallet does not match connected wallet",
|
|
1171
|
+
errorCode: AUTH_ERROR_CODES.WALLET_AUTH_FAILED
|
|
1172
|
+
});
|
|
1173
|
+
clearSession();
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
991
1176
|
storeSession(data.content);
|
|
992
1177
|
} else {
|
|
993
1178
|
setAuthState({
|
|
@@ -1105,173 +1290,6 @@ async function loginOAuth(provider, deps) {
|
|
|
1105
1290
|
await authenticate(clientSessionId, deps);
|
|
1106
1291
|
}
|
|
1107
1292
|
|
|
1108
|
-
// src/wallets/FreighterAdapter.ts
|
|
1109
|
-
var import_freighter_api = __toESM(require_index_min());
|
|
1110
|
-
|
|
1111
|
-
// src/wallets/types.ts
|
|
1112
|
-
var WalletType = /* @__PURE__ */ ((WalletType2) => {
|
|
1113
|
-
WalletType2["FREIGHTER"] = "freighter";
|
|
1114
|
-
WalletType2["ALBEDO"] = "albedo";
|
|
1115
|
-
return WalletType2;
|
|
1116
|
-
})(WalletType || {});
|
|
1117
|
-
|
|
1118
|
-
// src/wallets/FreighterAdapter.ts
|
|
1119
|
-
var FreighterAdapter = class {
|
|
1120
|
-
constructor() {
|
|
1121
|
-
this.type = "freighter" /* FREIGHTER */;
|
|
1122
|
-
}
|
|
1123
|
-
async isAvailable() {
|
|
1124
|
-
try {
|
|
1125
|
-
return await (0, import_freighter_api.isConnected)();
|
|
1126
|
-
} catch {
|
|
1127
|
-
return false;
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
async connect() {
|
|
1131
|
-
const connected = await (0, import_freighter_api.isConnected)();
|
|
1132
|
-
if (!connected) {
|
|
1133
|
-
throw new Error("Freighter wallet is not installed");
|
|
1134
|
-
}
|
|
1135
|
-
const allowed = await (0, import_freighter_api.isAllowed)();
|
|
1136
|
-
if (!allowed) {
|
|
1137
|
-
await (0, import_freighter_api.setAllowed)();
|
|
1138
|
-
}
|
|
1139
|
-
const userInfo = await (0, import_freighter_api.getUserInfo)();
|
|
1140
|
-
if (!userInfo?.publicKey) {
|
|
1141
|
-
throw new Error("Failed to get user information from Freighter");
|
|
1142
|
-
}
|
|
1143
|
-
return { address: userInfo.publicKey, publicKey: userInfo.publicKey };
|
|
1144
|
-
}
|
|
1145
|
-
async disconnect() {
|
|
1146
|
-
}
|
|
1147
|
-
async getPublicKey() {
|
|
1148
|
-
try {
|
|
1149
|
-
const allowed = await (0, import_freighter_api.isAllowed)();
|
|
1150
|
-
if (!allowed) return null;
|
|
1151
|
-
const userInfo = await (0, import_freighter_api.getUserInfo)();
|
|
1152
|
-
return userInfo?.publicKey ?? null;
|
|
1153
|
-
} catch {
|
|
1154
|
-
return null;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
async getNetwork() {
|
|
1158
|
-
return (0, import_freighter_api.getNetwork)();
|
|
1159
|
-
}
|
|
1160
|
-
async signTransaction(xdr, options) {
|
|
1161
|
-
const result = await (0, import_freighter_api.signTransaction)(xdr, {
|
|
1162
|
-
network: options?.network,
|
|
1163
|
-
networkPassphrase: options?.networkPassphrase,
|
|
1164
|
-
accountToSign: options?.accountToSign
|
|
1165
|
-
});
|
|
1166
|
-
if (!result || typeof result !== "string") {
|
|
1167
|
-
throw new Error("Invalid response from Freighter");
|
|
1168
|
-
}
|
|
1169
|
-
return { signedTxXdr: result };
|
|
1170
|
-
}
|
|
1171
|
-
async signAuthEntry(entryXdr, options) {
|
|
1172
|
-
const result = await (0, import_freighter_api.signAuthEntry)(entryXdr, { accountToSign: options?.accountToSign });
|
|
1173
|
-
if (!result || typeof result !== "string") {
|
|
1174
|
-
throw new Error("Invalid response from Freighter");
|
|
1175
|
-
}
|
|
1176
|
-
return { signedAuthEntry: result };
|
|
1177
|
-
}
|
|
1178
|
-
};
|
|
1179
|
-
|
|
1180
|
-
// src/wallets/AlbedoAdapter.ts
|
|
1181
|
-
function openAlbedoPopup(url) {
|
|
1182
|
-
const popup = window.open(url, "albedo", "width=420,height=720,resizable=yes,scrollbars=yes");
|
|
1183
|
-
if (!popup) {
|
|
1184
|
-
throw new Error("Failed to open Albedo popup (blocked by browser)");
|
|
1185
|
-
}
|
|
1186
|
-
return popup;
|
|
1187
|
-
}
|
|
1188
|
-
function waitForAlbedoPopup() {
|
|
1189
|
-
return new Promise((resolve, reject) => {
|
|
1190
|
-
const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
|
|
1191
|
-
function handler(event) {
|
|
1192
|
-
if (event.origin !== window.location.origin || event.data?.type !== "ALBEDO_RESULT") return;
|
|
1193
|
-
clearTimeout(timeout);
|
|
1194
|
-
window.removeEventListener("message", handler);
|
|
1195
|
-
resolve(event.data.payload);
|
|
1196
|
-
}
|
|
1197
|
-
window.addEventListener("message", handler);
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
|
-
function waitForAlbedoResult() {
|
|
1201
|
-
return new Promise((resolve, reject) => {
|
|
1202
|
-
const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
|
|
1203
|
-
const parseResult = () => {
|
|
1204
|
-
const params = new URLSearchParams(window.location.search);
|
|
1205
|
-
if (!params.has("pubkey") && !params.has("signed_envelope_xdr") && !params.has("signed_xdr")) return;
|
|
1206
|
-
clearTimeout(timeout);
|
|
1207
|
-
const result = {};
|
|
1208
|
-
params.forEach((value, key) => {
|
|
1209
|
-
result[key] = value;
|
|
1210
|
-
});
|
|
1211
|
-
window.history.replaceState({}, document.title, window.location.pathname);
|
|
1212
|
-
resolve(result);
|
|
1213
|
-
};
|
|
1214
|
-
parseResult();
|
|
1215
|
-
window.addEventListener("popstate", parseResult);
|
|
1216
|
-
});
|
|
1217
|
-
}
|
|
1218
|
-
var AlbedoAdapter = class {
|
|
1219
|
-
constructor() {
|
|
1220
|
-
this.type = "albedo" /* ALBEDO */;
|
|
1221
|
-
}
|
|
1222
|
-
async isAvailable() {
|
|
1223
|
-
return typeof window !== "undefined";
|
|
1224
|
-
}
|
|
1225
|
-
async connect() {
|
|
1226
|
-
const url = new URL("https://albedo.link");
|
|
1227
|
-
url.searchParams.set("intent", "public-key");
|
|
1228
|
-
url.searchParams.set("app_name", "Pollar");
|
|
1229
|
-
url.searchParams.set("network", "testnet");
|
|
1230
|
-
url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
|
|
1231
|
-
url.searchParams.set("origin", window.location.origin);
|
|
1232
|
-
openAlbedoPopup(url.toString());
|
|
1233
|
-
const result = await waitForAlbedoPopup();
|
|
1234
|
-
if (!result.pubkey) {
|
|
1235
|
-
throw new Error("Albedo connection rejected");
|
|
1236
|
-
}
|
|
1237
|
-
return { address: result.pubkey, publicKey: result.pubkey };
|
|
1238
|
-
}
|
|
1239
|
-
async disconnect() {
|
|
1240
|
-
}
|
|
1241
|
-
async getPublicKey() {
|
|
1242
|
-
return null;
|
|
1243
|
-
}
|
|
1244
|
-
async getNetwork() {
|
|
1245
|
-
throw new Error("Albedo does not expose network");
|
|
1246
|
-
}
|
|
1247
|
-
async signTransaction(xdr, _options) {
|
|
1248
|
-
const url = new URL("https://albedo.link");
|
|
1249
|
-
url.searchParams.set("intent", "tx");
|
|
1250
|
-
url.searchParams.set("xdr", xdr);
|
|
1251
|
-
url.searchParams.set("app_name", "Pollar");
|
|
1252
|
-
url.searchParams.set("network", "testnet");
|
|
1253
|
-
url.searchParams.set("callback", window.location.href);
|
|
1254
|
-
url.searchParams.set("origin", window.location.origin);
|
|
1255
|
-
window.location.href = url.toString();
|
|
1256
|
-
const result = await waitForAlbedoResult();
|
|
1257
|
-
if (!result.signed_envelope_xdr) throw new Error("Albedo signing rejected");
|
|
1258
|
-
return { signedTxXdr: result.signed_envelope_xdr };
|
|
1259
|
-
}
|
|
1260
|
-
async signAuthEntry(entryXdr, _options) {
|
|
1261
|
-
const url = new URL("https://albedo.link");
|
|
1262
|
-
url.searchParams.set("intent", "sign-auth-entry");
|
|
1263
|
-
url.searchParams.set("xdr", entryXdr);
|
|
1264
|
-
url.searchParams.set("app_name", "Pollar");
|
|
1265
|
-
url.searchParams.set("network", "testnet");
|
|
1266
|
-
url.searchParams.set("callback", window.location.href);
|
|
1267
|
-
url.searchParams.set("origin", window.location.origin);
|
|
1268
|
-
window.location.href = url.toString();
|
|
1269
|
-
const result = await waitForAlbedoResult();
|
|
1270
|
-
if (!result.signed_xdr) throw new Error("Albedo auth entry signing rejected");
|
|
1271
|
-
return { signedAuthEntry: result.signed_xdr };
|
|
1272
|
-
}
|
|
1273
|
-
};
|
|
1274
|
-
|
|
1275
1293
|
// src/client/auth/walletFlow.ts
|
|
1276
1294
|
function withSignal(promise, signal) {
|
|
1277
1295
|
return Promise.race([
|
|
@@ -1289,6 +1307,7 @@ async function loginWallet(type, deps) {
|
|
|
1289
1307
|
const { api, signal, setAuthState } = deps;
|
|
1290
1308
|
const clientSessionId = await createAuthSession(deps);
|
|
1291
1309
|
if (!clientSessionId) return;
|
|
1310
|
+
let connectedWallet;
|
|
1292
1311
|
try {
|
|
1293
1312
|
setAuthState({ step: "connecting_wallet", walletType: type });
|
|
1294
1313
|
const adapter = type === "freighter" /* FREIGHTER */ ? new FreighterAdapter() : new AlbedoAdapter();
|
|
@@ -1298,7 +1317,8 @@ async function loginWallet(type, deps) {
|
|
|
1298
1317
|
return;
|
|
1299
1318
|
}
|
|
1300
1319
|
const { publicKey } = await withSignal(adapter.connect(), signal);
|
|
1301
|
-
|
|
1320
|
+
connectedWallet = publicKey;
|
|
1321
|
+
deps.storeWalletAdapter(adapter, type);
|
|
1302
1322
|
setAuthState({ step: "authenticating_wallet" });
|
|
1303
1323
|
const { data: walletData, error: walletError } = await api.POST("/auth/wallet", {
|
|
1304
1324
|
body: { clientSessionId, walletAddress: publicKey },
|
|
@@ -1322,7 +1342,7 @@ async function loginWallet(type, deps) {
|
|
|
1322
1342
|
});
|
|
1323
1343
|
return;
|
|
1324
1344
|
}
|
|
1325
|
-
await authenticate(clientSessionId, deps);
|
|
1345
|
+
await authenticate(clientSessionId, deps, connectedWallet);
|
|
1326
1346
|
}
|
|
1327
1347
|
|
|
1328
1348
|
// src/client/client.ts
|
|
@@ -1339,6 +1359,8 @@ var PollarClient = class {
|
|
|
1339
1359
|
this._transactionStateListeners = /* @__PURE__ */ new Set();
|
|
1340
1360
|
this._txHistoryState = { step: "idle" };
|
|
1341
1361
|
this._txHistoryStateListeners = /* @__PURE__ */ new Set();
|
|
1362
|
+
this._walletBalanceState = { step: "idle" };
|
|
1363
|
+
this._walletBalanceStateListeners = /* @__PURE__ */ new Set();
|
|
1342
1364
|
this._authState = { step: "idle" };
|
|
1343
1365
|
this._authStateListeners = /* @__PURE__ */ new Set();
|
|
1344
1366
|
this._networkState = { step: "idle" };
|
|
@@ -1499,10 +1521,6 @@ var PollarClient = class {
|
|
|
1499
1521
|
return () => this._transactionStateListeners.delete(cb);
|
|
1500
1522
|
}
|
|
1501
1523
|
// ─── Tx history ──────────────────────────────────────────────────────────
|
|
1502
|
-
_setTxHistoryState(next) {
|
|
1503
|
-
this._txHistoryState = next;
|
|
1504
|
-
for (const cb of this._txHistoryStateListeners) cb(next);
|
|
1505
|
-
}
|
|
1506
1524
|
getTxHistoryState() {
|
|
1507
1525
|
return this._txHistoryState;
|
|
1508
1526
|
}
|
|
@@ -1526,13 +1544,32 @@ var PollarClient = class {
|
|
|
1526
1544
|
}
|
|
1527
1545
|
}
|
|
1528
1546
|
// ─── Wallet balance ───────────────────────────────────────────────────────
|
|
1529
|
-
|
|
1547
|
+
getWalletBalanceState() {
|
|
1548
|
+
return this._walletBalanceState;
|
|
1549
|
+
}
|
|
1550
|
+
onWalletBalanceStateChange(cb) {
|
|
1551
|
+
this._walletBalanceStateListeners.add(cb);
|
|
1552
|
+
cb(this._walletBalanceState);
|
|
1553
|
+
return () => this._walletBalanceStateListeners.delete(cb);
|
|
1554
|
+
}
|
|
1555
|
+
async refreshBalance(publicKey) {
|
|
1530
1556
|
const pk = publicKey ?? this._session?.wallet?.publicKey;
|
|
1531
|
-
if (!pk)
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1557
|
+
if (!pk) {
|
|
1558
|
+
this._setWalletBalanceState({ step: "error", message: "No wallet connected" });
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
this._setWalletBalanceState({ step: "loading" });
|
|
1562
|
+
try {
|
|
1563
|
+
const network = this.getNetwork();
|
|
1564
|
+
const { data, error } = await this._api.GET("/wallet/balance", { params: { query: { publicKey: pk, network } } });
|
|
1565
|
+
if (!error && data?.success && data.content) {
|
|
1566
|
+
this._setWalletBalanceState({ step: "loaded", data: data.content });
|
|
1567
|
+
} else {
|
|
1568
|
+
this._setWalletBalanceState({ step: "error", message: "Failed to load balance" });
|
|
1569
|
+
}
|
|
1570
|
+
} catch {
|
|
1571
|
+
this._setWalletBalanceState({ step: "error", message: "Failed to load balance" });
|
|
1572
|
+
}
|
|
1536
1573
|
}
|
|
1537
1574
|
// ─── Transactions ─────────────────────────────────────────────────────────
|
|
1538
1575
|
async buildTx(operation, params, options) {
|
|
@@ -1560,27 +1597,29 @@ var PollarClient = class {
|
|
|
1560
1597
|
this._setTransactionState({ step: "error" });
|
|
1561
1598
|
}
|
|
1562
1599
|
}
|
|
1600
|
+
getWalletType() {
|
|
1601
|
+
return this._walletAdapter?.type ?? null;
|
|
1602
|
+
}
|
|
1563
1603
|
async signAndSubmitTx(unsignedXdr) {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
}
|
|
1569
|
-
const
|
|
1570
|
-
this._setTransactionState({ step: "signing", buildData });
|
|
1604
|
+
const state = this._transactionState;
|
|
1605
|
+
const buildData = state?.step === "built" ? state.buildData : state?.step === "error" ? state.buildData : void 0;
|
|
1606
|
+
const isBuiltFlow = !!buildData;
|
|
1607
|
+
const stateExtra = buildData ? { buildData } : { external: true };
|
|
1608
|
+
this._setTransactionState({ step: "signing", ...stateExtra });
|
|
1609
|
+
const accountToSign = isBuiltFlow ? this._session?.wallet?.publicKey : this._session?.data?.providers?.wallet?.address ?? this._session?.wallet?.publicKey;
|
|
1571
1610
|
if (this._walletAdapter) {
|
|
1572
1611
|
try {
|
|
1573
|
-
const signOpts =
|
|
1612
|
+
const signOpts = accountToSign ? { networkPassphrase: this._networkPassphrase(), accountToSign } : { networkPassphrase: this._networkPassphrase() };
|
|
1574
1613
|
const { signedTxXdr } = await this._walletAdapter.signTransaction(unsignedXdr, signOpts);
|
|
1575
1614
|
const stellarClient = new StellarClient(this.getNetwork());
|
|
1576
1615
|
const result = await stellarClient.submitTransaction(signedTxXdr);
|
|
1577
1616
|
if (result.success) {
|
|
1578
|
-
this._setTransactionState({ step: "success",
|
|
1617
|
+
this._setTransactionState({ step: "success", ...stateExtra, hash: result.hash });
|
|
1579
1618
|
} else {
|
|
1580
|
-
this._setTransactionState({ step: "error", ...
|
|
1619
|
+
this._setTransactionState({ step: "error", ...stateExtra, details: result.errorCode });
|
|
1581
1620
|
}
|
|
1582
1621
|
} catch {
|
|
1583
|
-
this._setTransactionState({ step: "error", ...
|
|
1622
|
+
this._setTransactionState({ step: "error", ...stateExtra });
|
|
1584
1623
|
}
|
|
1585
1624
|
return;
|
|
1586
1625
|
}
|
|
@@ -1592,13 +1631,13 @@ var PollarClient = class {
|
|
|
1592
1631
|
try {
|
|
1593
1632
|
const { data, error } = await this._api.POST("/tx/sign-and-send", { body });
|
|
1594
1633
|
if (!error && data?.success && data.content?.hash) {
|
|
1595
|
-
this._setTransactionState({ step: "success",
|
|
1634
|
+
this._setTransactionState({ step: "success", ...stateExtra, hash: data.content.hash });
|
|
1596
1635
|
} else {
|
|
1597
1636
|
const details = error?.details;
|
|
1598
|
-
this._setTransactionState({ step: "error", ...
|
|
1637
|
+
this._setTransactionState({ step: "error", ...stateExtra, ...details && { details } });
|
|
1599
1638
|
}
|
|
1600
1639
|
} catch {
|
|
1601
|
-
this._setTransactionState({ step: "error", ...
|
|
1640
|
+
this._setTransactionState({ step: "error", ...stateExtra });
|
|
1602
1641
|
}
|
|
1603
1642
|
}
|
|
1604
1643
|
// ─── App config ───────────────────────────────────────────────────────────
|
|
@@ -1643,6 +1682,14 @@ var PollarClient = class {
|
|
|
1643
1682
|
pollRampTransaction(txId, opts) {
|
|
1644
1683
|
return pollRampTransaction(this._api, txId, opts);
|
|
1645
1684
|
}
|
|
1685
|
+
_setTxHistoryState(next) {
|
|
1686
|
+
this._txHistoryState = next;
|
|
1687
|
+
for (const cb of this._txHistoryStateListeners) cb(next);
|
|
1688
|
+
}
|
|
1689
|
+
_setWalletBalanceState(next) {
|
|
1690
|
+
this._walletBalanceState = next;
|
|
1691
|
+
for (const cb of this._walletBalanceStateListeners) cb(next);
|
|
1692
|
+
}
|
|
1646
1693
|
// ─── Private ──────────────────────────────────────────────────────────────
|
|
1647
1694
|
/** Creates a new AbortController, cancelling any existing flow first. */
|
|
1648
1695
|
_newController() {
|
|
@@ -1658,8 +1705,9 @@ var PollarClient = class {
|
|
|
1658
1705
|
setAuthState: this._setAuthState.bind(this),
|
|
1659
1706
|
storeSession: this._storeSession.bind(this),
|
|
1660
1707
|
clearSession: this._clearSession.bind(this),
|
|
1661
|
-
storeWalletAdapter: (adapter) => {
|
|
1708
|
+
storeWalletAdapter: (adapter, type) => {
|
|
1662
1709
|
this._walletAdapter = adapter;
|
|
1710
|
+
writeWalletType(type);
|
|
1663
1711
|
}
|
|
1664
1712
|
};
|
|
1665
1713
|
}
|
|
@@ -1681,6 +1729,14 @@ var PollarClient = class {
|
|
|
1681
1729
|
this._session = readStorage();
|
|
1682
1730
|
if (this._session) {
|
|
1683
1731
|
this._authState = { step: "authenticated", session: this._session };
|
|
1732
|
+
if (this._session.data?.providers?.wallet?.address) {
|
|
1733
|
+
const storedType = readWalletType();
|
|
1734
|
+
if (storedType === "freighter" /* FREIGHTER */) {
|
|
1735
|
+
this._walletAdapter = new FreighterAdapter();
|
|
1736
|
+
} else if (storedType === "albedo" /* ALBEDO */) {
|
|
1737
|
+
this._walletAdapter = new AlbedoAdapter();
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1684
1740
|
console.info("[PollarClient] Session restored from storage");
|
|
1685
1741
|
} else {
|
|
1686
1742
|
console.info("[PollarClient] No session in storage");
|