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