@pioneer-platform/pioneer-sdk 8.11.8 → 8.11.9

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.cjs CHANGED
@@ -3705,6 +3705,22 @@ async function syncMarket(balances, pioneer) {
3705
3705
 
3706
3706
  // src/index.ts
3707
3707
  var TAG9 = " | Pioneer-sdk | ";
3708
+ var ASSET_COLORS = {
3709
+ "bip122:000000000019d6689c085ae165831e93/slip44:0": "#FF9800",
3710
+ "eip155:1/slip44:60": "#627EEA",
3711
+ "eip155:137/slip44:60": "#8247E5",
3712
+ "eip155:8453/slip44:60": "#0052FF",
3713
+ "eip155:56/slip44:60": "#F3BA2F",
3714
+ "bip122:12a765e31ffd4059bada1e25190f6e98/slip44:2": "#BFBBBB",
3715
+ "bip122:00000000001a91e3dace36e2be3bf030/slip44:3": "#C2A633",
3716
+ "bip122:000000000000000000651ef99cb9fcbe/slip44:145": "#8DC351",
3717
+ "bip122:000007d91d1254d60e2dd1ae58038307/slip44:5": "#008CE7",
3718
+ "cosmos:cosmoshub-4/slip44:118": "#2E3148",
3719
+ "cosmos:osmosis-1/slip44:118": "#9B1FD7",
3720
+ "ripple:4109c6f2045fc7eff4cde8f9905d19c2/slip44:144": "#23292F",
3721
+ "cosmos:mayachain-mainnet-v1/slip44:931": "#00D4AA",
3722
+ "cosmos:thorchain-mainnet-v1/slip44:931": "#00CCFF"
3723
+ };
3708
3724
 
3709
3725
  class SDK {
3710
3726
  status;
@@ -3725,6 +3741,7 @@ class SDK {
3725
3741
  outboundBlockchainContext;
3726
3742
  outboundPubkeyContext;
3727
3743
  buildDashboardFromBalances;
3744
+ syncState;
3728
3745
  pioneer;
3729
3746
  charts;
3730
3747
  paths;
@@ -3767,6 +3784,8 @@ class SDK {
3767
3784
  estimateTransactionFee;
3768
3785
  getCharts;
3769
3786
  keepKeySdk;
3787
+ getSyncState;
3788
+ isSynced;
3770
3789
  getGasAssets;
3771
3790
  transactions;
3772
3791
  transfer;
@@ -3826,6 +3845,16 @@ class SDK {
3826
3845
  this.utxoApiKey = config.utxoApiKey;
3827
3846
  this.walletConnectProjectId = config.walletConnectProjectId;
3828
3847
  this.contextType = "";
3848
+ this.syncState = {
3849
+ isSynced: false,
3850
+ isInitialSync: true,
3851
+ cacheAge: 0,
3852
+ syncProgress: 0,
3853
+ syncedChains: 0,
3854
+ totalChains: this.blockchains.length,
3855
+ lastSyncTime: null,
3856
+ syncSource: "none"
3857
+ };
3829
3858
  this.offlineClient = config.offlineFirst ? new OfflineClient({
3830
3859
  vaultUrl: config.vaultUrl || "kkapi://",
3831
3860
  timeout: 1000,
@@ -3960,6 +3989,18 @@ class SDK {
3960
3989
  };
3961
3990
  this.dashboard = dashboardData;
3962
3991
  this.events.emit("SET_DASHBOARD", this.dashboard);
3992
+ const cacheAge = portfolioData.lastUpdated ? Math.floor((Date.now() - portfolioData.lastUpdated) / 1000) : 0;
3993
+ this.syncState = {
3994
+ isSynced: true,
3995
+ isInitialSync: false,
3996
+ cacheAge,
3997
+ syncProgress: 100,
3998
+ syncedChains: this.blockchains.length,
3999
+ totalChains: this.blockchains.length,
4000
+ lastSyncTime: portfolioData.lastUpdated || Date.now(),
4001
+ syncSource: "cache"
4002
+ };
4003
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
3963
4004
  } else {
3964
4005
  console.warn("[CACHE VALIDATION] ❌ Cache data corrupted, building dashboard from cached balances");
3965
4006
  const dashboardData = this.buildDashboardFromBalances();
@@ -3986,6 +4027,12 @@ class SDK {
3986
4027
  return null;
3987
4028
  }
3988
4029
  };
4030
+ this.getSyncState = function() {
4031
+ return this.syncState;
4032
+ };
4033
+ this.isSynced = function() {
4034
+ return this.syncState.isSynced;
4035
+ };
3989
4036
  this.init = async function(walletsVerbose, setup) {
3990
4037
  const tag6 = `${TAG9} | init | `;
3991
4038
  try {
@@ -4042,6 +4089,53 @@ class SDK {
4042
4089
  clientEvents.events.on("message", (request) => {
4043
4090
  this.events.emit("message", request);
4044
4091
  });
4092
+ clientEvents.events.on("balance:update", (data) => {
4093
+ const tag7 = TAG9 + " | balance:update | ";
4094
+ try {
4095
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4096
+ const balance = payload.balance;
4097
+ console.log(tag7, "Received balance update:", balance.caip);
4098
+ const exists = this.balances.find((b) => b.caip === balance.caip && b.pubkey === balance.pubkey);
4099
+ if (!exists) {
4100
+ this.balances.push(balance);
4101
+ } else {
4102
+ const index = this.balances.findIndex((b) => b.caip === balance.caip && b.pubkey === balance.pubkey);
4103
+ this.balances[index] = balance;
4104
+ }
4105
+ this.events.emit("BALANCE_UPDATE", balance);
4106
+ } catch (e) {
4107
+ console.error(tag7, "Error processing balance update:", e);
4108
+ }
4109
+ });
4110
+ clientEvents.events.on("sync:progress", (data) => {
4111
+ const tag7 = TAG9 + " | sync:progress | ";
4112
+ try {
4113
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4114
+ console.log(tag7, `Sync progress: ${payload.percentage}%`);
4115
+ this.syncState.syncProgress = payload.percentage;
4116
+ this.syncState.syncedChains = payload.completed;
4117
+ this.syncState.totalChains = payload.total;
4118
+ this.events.emit("SYNC_PROGRESS", this.syncState);
4119
+ } catch (e) {
4120
+ console.error(tag7, "Error processing sync progress:", e);
4121
+ }
4122
+ });
4123
+ clientEvents.events.on("sync:complete", (data) => {
4124
+ const tag7 = TAG9 + " | sync:complete | ";
4125
+ try {
4126
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4127
+ console.log(tag7, `Sync complete: ${payload.balances} balances in ${payload.duration}ms`);
4128
+ this.syncState.isSynced = true;
4129
+ this.syncState.isInitialSync = false;
4130
+ this.syncState.syncProgress = 100;
4131
+ this.syncState.lastSyncTime = Date.now();
4132
+ this.syncState.syncSource = "fresh";
4133
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4134
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4135
+ } catch (e) {
4136
+ console.error(tag7, "Error processing sync complete:", e);
4137
+ }
4138
+ });
4045
4139
  this.events.emit("SET_STATUS", "init");
4046
4140
  if (this.keepKeySdk && !skipSync) {
4047
4141
  console.log("⚡ [FAST PORTFOLIO] Attempting fast load...");
@@ -4200,6 +4294,18 @@ class SDK {
4200
4294
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4201
4295
  })).filter((entry) => entry.percentage > 0);
4202
4296
  this.dashboard = dashboardData;
4297
+ this.syncState = {
4298
+ isSynced: true,
4299
+ isInitialSync: false,
4300
+ cacheAge: 0,
4301
+ syncProgress: 100,
4302
+ syncedChains: this.blockchains.length,
4303
+ totalChains: this.blockchains.length,
4304
+ lastSyncTime: Date.now(),
4305
+ syncSource: "fresh"
4306
+ };
4307
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4308
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4203
4309
  return true;
4204
4310
  } catch (e) {
4205
4311
  console.error(tag6, "Error in sync:", e);
@@ -4788,14 +4894,16 @@ class SDK {
4788
4894
  console.timeEnd("GetPortfolioBalances Response Time");
4789
4895
  let balances = marketInfo.data;
4790
4896
  for (let balance of balances) {
4791
- const assetInfo = this.assetsMap.get(balance.caip);
4897
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4792
4898
  if (!assetInfo)
4793
4899
  continue;
4900
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4794
4901
  Object.assign(balance, assetInfo, {
4795
4902
  networkId: import_pioneer_caip8.caipToNetworkId(balance.caip),
4796
4903
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4797
4904
  identifier: `${balance.caip}:${balance.pubkey}`,
4798
- updated: Date.now()
4905
+ updated: Date.now(),
4906
+ color
4799
4907
  });
4800
4908
  }
4801
4909
  this.balances = balances;
package/dist/index.es.js CHANGED
@@ -3881,6 +3881,22 @@ async function syncMarket(balances, pioneer) {
3881
3881
 
3882
3882
  // src/index.ts
3883
3883
  var TAG9 = " | Pioneer-sdk | ";
3884
+ var ASSET_COLORS = {
3885
+ "bip122:000000000019d6689c085ae165831e93/slip44:0": "#FF9800",
3886
+ "eip155:1/slip44:60": "#627EEA",
3887
+ "eip155:137/slip44:60": "#8247E5",
3888
+ "eip155:8453/slip44:60": "#0052FF",
3889
+ "eip155:56/slip44:60": "#F3BA2F",
3890
+ "bip122:12a765e31ffd4059bada1e25190f6e98/slip44:2": "#BFBBBB",
3891
+ "bip122:00000000001a91e3dace36e2be3bf030/slip44:3": "#C2A633",
3892
+ "bip122:000000000000000000651ef99cb9fcbe/slip44:145": "#8DC351",
3893
+ "bip122:000007d91d1254d60e2dd1ae58038307/slip44:5": "#008CE7",
3894
+ "cosmos:cosmoshub-4/slip44:118": "#2E3148",
3895
+ "cosmos:osmosis-1/slip44:118": "#9B1FD7",
3896
+ "ripple:4109c6f2045fc7eff4cde8f9905d19c2/slip44:144": "#23292F",
3897
+ "cosmos:mayachain-mainnet-v1/slip44:931": "#00D4AA",
3898
+ "cosmos:thorchain-mainnet-v1/slip44:931": "#00CCFF"
3899
+ };
3884
3900
 
3885
3901
  class SDK {
3886
3902
  status;
@@ -3901,6 +3917,7 @@ class SDK {
3901
3917
  outboundBlockchainContext;
3902
3918
  outboundPubkeyContext;
3903
3919
  buildDashboardFromBalances;
3920
+ syncState;
3904
3921
  pioneer;
3905
3922
  charts;
3906
3923
  paths;
@@ -3943,6 +3960,8 @@ class SDK {
3943
3960
  estimateTransactionFee;
3944
3961
  getCharts;
3945
3962
  keepKeySdk;
3963
+ getSyncState;
3964
+ isSynced;
3946
3965
  getGasAssets;
3947
3966
  transactions;
3948
3967
  transfer;
@@ -4002,6 +4021,16 @@ class SDK {
4002
4021
  this.utxoApiKey = config.utxoApiKey;
4003
4022
  this.walletConnectProjectId = config.walletConnectProjectId;
4004
4023
  this.contextType = "";
4024
+ this.syncState = {
4025
+ isSynced: false,
4026
+ isInitialSync: true,
4027
+ cacheAge: 0,
4028
+ syncProgress: 0,
4029
+ syncedChains: 0,
4030
+ totalChains: this.blockchains.length,
4031
+ lastSyncTime: null,
4032
+ syncSource: "none"
4033
+ };
4005
4034
  this.offlineClient = config.offlineFirst ? new OfflineClient({
4006
4035
  vaultUrl: config.vaultUrl || "kkapi://",
4007
4036
  timeout: 1000,
@@ -4136,6 +4165,18 @@ class SDK {
4136
4165
  };
4137
4166
  this.dashboard = dashboardData;
4138
4167
  this.events.emit("SET_DASHBOARD", this.dashboard);
4168
+ const cacheAge = portfolioData.lastUpdated ? Math.floor((Date.now() - portfolioData.lastUpdated) / 1000) : 0;
4169
+ this.syncState = {
4170
+ isSynced: true,
4171
+ isInitialSync: false,
4172
+ cacheAge,
4173
+ syncProgress: 100,
4174
+ syncedChains: this.blockchains.length,
4175
+ totalChains: this.blockchains.length,
4176
+ lastSyncTime: portfolioData.lastUpdated || Date.now(),
4177
+ syncSource: "cache"
4178
+ };
4179
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4139
4180
  } else {
4140
4181
  console.warn("[CACHE VALIDATION] ❌ Cache data corrupted, building dashboard from cached balances");
4141
4182
  const dashboardData = this.buildDashboardFromBalances();
@@ -4162,6 +4203,12 @@ class SDK {
4162
4203
  return null;
4163
4204
  }
4164
4205
  };
4206
+ this.getSyncState = function() {
4207
+ return this.syncState;
4208
+ };
4209
+ this.isSynced = function() {
4210
+ return this.syncState.isSynced;
4211
+ };
4165
4212
  this.init = async function(walletsVerbose, setup) {
4166
4213
  const tag6 = `${TAG9} | init | `;
4167
4214
  try {
@@ -4218,6 +4265,53 @@ class SDK {
4218
4265
  clientEvents.events.on("message", (request) => {
4219
4266
  this.events.emit("message", request);
4220
4267
  });
4268
+ clientEvents.events.on("balance:update", (data) => {
4269
+ const tag7 = TAG9 + " | balance:update | ";
4270
+ try {
4271
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4272
+ const balance = payload.balance;
4273
+ console.log(tag7, "Received balance update:", balance.caip);
4274
+ const exists = this.balances.find((b2) => b2.caip === balance.caip && b2.pubkey === balance.pubkey);
4275
+ if (!exists) {
4276
+ this.balances.push(balance);
4277
+ } else {
4278
+ const index = this.balances.findIndex((b2) => b2.caip === balance.caip && b2.pubkey === balance.pubkey);
4279
+ this.balances[index] = balance;
4280
+ }
4281
+ this.events.emit("BALANCE_UPDATE", balance);
4282
+ } catch (e) {
4283
+ console.error(tag7, "Error processing balance update:", e);
4284
+ }
4285
+ });
4286
+ clientEvents.events.on("sync:progress", (data) => {
4287
+ const tag7 = TAG9 + " | sync:progress | ";
4288
+ try {
4289
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4290
+ console.log(tag7, `Sync progress: ${payload.percentage}%`);
4291
+ this.syncState.syncProgress = payload.percentage;
4292
+ this.syncState.syncedChains = payload.completed;
4293
+ this.syncState.totalChains = payload.total;
4294
+ this.events.emit("SYNC_PROGRESS", this.syncState);
4295
+ } catch (e) {
4296
+ console.error(tag7, "Error processing sync progress:", e);
4297
+ }
4298
+ });
4299
+ clientEvents.events.on("sync:complete", (data) => {
4300
+ const tag7 = TAG9 + " | sync:complete | ";
4301
+ try {
4302
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4303
+ console.log(tag7, `Sync complete: ${payload.balances} balances in ${payload.duration}ms`);
4304
+ this.syncState.isSynced = true;
4305
+ this.syncState.isInitialSync = false;
4306
+ this.syncState.syncProgress = 100;
4307
+ this.syncState.lastSyncTime = Date.now();
4308
+ this.syncState.syncSource = "fresh";
4309
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4310
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4311
+ } catch (e) {
4312
+ console.error(tag7, "Error processing sync complete:", e);
4313
+ }
4314
+ });
4221
4315
  this.events.emit("SET_STATUS", "init");
4222
4316
  if (this.keepKeySdk && !skipSync) {
4223
4317
  console.log("⚡ [FAST PORTFOLIO] Attempting fast load...");
@@ -4376,6 +4470,18 @@ class SDK {
4376
4470
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4377
4471
  })).filter((entry) => entry.percentage > 0);
4378
4472
  this.dashboard = dashboardData;
4473
+ this.syncState = {
4474
+ isSynced: true,
4475
+ isInitialSync: false,
4476
+ cacheAge: 0,
4477
+ syncProgress: 100,
4478
+ syncedChains: this.blockchains.length,
4479
+ totalChains: this.blockchains.length,
4480
+ lastSyncTime: Date.now(),
4481
+ syncSource: "fresh"
4482
+ };
4483
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4484
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4379
4485
  return true;
4380
4486
  } catch (e) {
4381
4487
  console.error(tag6, "Error in sync:", e);
@@ -4964,14 +5070,16 @@ class SDK {
4964
5070
  console.timeEnd("GetPortfolioBalances Response Time");
4965
5071
  let balances = marketInfo.data;
4966
5072
  for (let balance of balances) {
4967
- const assetInfo = this.assetsMap.get(balance.caip);
5073
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4968
5074
  if (!assetInfo)
4969
5075
  continue;
5076
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4970
5077
  Object.assign(balance, assetInfo, {
4971
5078
  networkId: caipToNetworkId7(balance.caip),
4972
5079
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4973
5080
  identifier: `${balance.caip}:${balance.pubkey}`,
4974
- updated: Date.now()
5081
+ updated: Date.now(),
5082
+ color
4975
5083
  });
4976
5084
  }
4977
5085
  this.balances = balances;
package/dist/index.js CHANGED
@@ -3881,6 +3881,22 @@ async function syncMarket(balances, pioneer) {
3881
3881
 
3882
3882
  // src/index.ts
3883
3883
  var TAG9 = " | Pioneer-sdk | ";
3884
+ var ASSET_COLORS = {
3885
+ "bip122:000000000019d6689c085ae165831e93/slip44:0": "#FF9800",
3886
+ "eip155:1/slip44:60": "#627EEA",
3887
+ "eip155:137/slip44:60": "#8247E5",
3888
+ "eip155:8453/slip44:60": "#0052FF",
3889
+ "eip155:56/slip44:60": "#F3BA2F",
3890
+ "bip122:12a765e31ffd4059bada1e25190f6e98/slip44:2": "#BFBBBB",
3891
+ "bip122:00000000001a91e3dace36e2be3bf030/slip44:3": "#C2A633",
3892
+ "bip122:000000000000000000651ef99cb9fcbe/slip44:145": "#8DC351",
3893
+ "bip122:000007d91d1254d60e2dd1ae58038307/slip44:5": "#008CE7",
3894
+ "cosmos:cosmoshub-4/slip44:118": "#2E3148",
3895
+ "cosmos:osmosis-1/slip44:118": "#9B1FD7",
3896
+ "ripple:4109c6f2045fc7eff4cde8f9905d19c2/slip44:144": "#23292F",
3897
+ "cosmos:mayachain-mainnet-v1/slip44:931": "#00D4AA",
3898
+ "cosmos:thorchain-mainnet-v1/slip44:931": "#00CCFF"
3899
+ };
3884
3900
 
3885
3901
  class SDK {
3886
3902
  status;
@@ -3901,6 +3917,7 @@ class SDK {
3901
3917
  outboundBlockchainContext;
3902
3918
  outboundPubkeyContext;
3903
3919
  buildDashboardFromBalances;
3920
+ syncState;
3904
3921
  pioneer;
3905
3922
  charts;
3906
3923
  paths;
@@ -3943,6 +3960,8 @@ class SDK {
3943
3960
  estimateTransactionFee;
3944
3961
  getCharts;
3945
3962
  keepKeySdk;
3963
+ getSyncState;
3964
+ isSynced;
3946
3965
  getGasAssets;
3947
3966
  transactions;
3948
3967
  transfer;
@@ -4002,6 +4021,16 @@ class SDK {
4002
4021
  this.utxoApiKey = config.utxoApiKey;
4003
4022
  this.walletConnectProjectId = config.walletConnectProjectId;
4004
4023
  this.contextType = "";
4024
+ this.syncState = {
4025
+ isSynced: false,
4026
+ isInitialSync: true,
4027
+ cacheAge: 0,
4028
+ syncProgress: 0,
4029
+ syncedChains: 0,
4030
+ totalChains: this.blockchains.length,
4031
+ lastSyncTime: null,
4032
+ syncSource: "none"
4033
+ };
4005
4034
  this.offlineClient = config.offlineFirst ? new OfflineClient({
4006
4035
  vaultUrl: config.vaultUrl || "kkapi://",
4007
4036
  timeout: 1000,
@@ -4136,6 +4165,18 @@ class SDK {
4136
4165
  };
4137
4166
  this.dashboard = dashboardData;
4138
4167
  this.events.emit("SET_DASHBOARD", this.dashboard);
4168
+ const cacheAge = portfolioData.lastUpdated ? Math.floor((Date.now() - portfolioData.lastUpdated) / 1000) : 0;
4169
+ this.syncState = {
4170
+ isSynced: true,
4171
+ isInitialSync: false,
4172
+ cacheAge,
4173
+ syncProgress: 100,
4174
+ syncedChains: this.blockchains.length,
4175
+ totalChains: this.blockchains.length,
4176
+ lastSyncTime: portfolioData.lastUpdated || Date.now(),
4177
+ syncSource: "cache"
4178
+ };
4179
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4139
4180
  } else {
4140
4181
  console.warn("[CACHE VALIDATION] ❌ Cache data corrupted, building dashboard from cached balances");
4141
4182
  const dashboardData = this.buildDashboardFromBalances();
@@ -4162,6 +4203,12 @@ class SDK {
4162
4203
  return null;
4163
4204
  }
4164
4205
  };
4206
+ this.getSyncState = function() {
4207
+ return this.syncState;
4208
+ };
4209
+ this.isSynced = function() {
4210
+ return this.syncState.isSynced;
4211
+ };
4165
4212
  this.init = async function(walletsVerbose, setup) {
4166
4213
  const tag6 = `${TAG9} | init | `;
4167
4214
  try {
@@ -4218,6 +4265,53 @@ class SDK {
4218
4265
  clientEvents.events.on("message", (request) => {
4219
4266
  this.events.emit("message", request);
4220
4267
  });
4268
+ clientEvents.events.on("balance:update", (data) => {
4269
+ const tag7 = TAG9 + " | balance:update | ";
4270
+ try {
4271
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4272
+ const balance = payload.balance;
4273
+ console.log(tag7, "Received balance update:", balance.caip);
4274
+ const exists = this.balances.find((b2) => b2.caip === balance.caip && b2.pubkey === balance.pubkey);
4275
+ if (!exists) {
4276
+ this.balances.push(balance);
4277
+ } else {
4278
+ const index = this.balances.findIndex((b2) => b2.caip === balance.caip && b2.pubkey === balance.pubkey);
4279
+ this.balances[index] = balance;
4280
+ }
4281
+ this.events.emit("BALANCE_UPDATE", balance);
4282
+ } catch (e) {
4283
+ console.error(tag7, "Error processing balance update:", e);
4284
+ }
4285
+ });
4286
+ clientEvents.events.on("sync:progress", (data) => {
4287
+ const tag7 = TAG9 + " | sync:progress | ";
4288
+ try {
4289
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4290
+ console.log(tag7, `Sync progress: ${payload.percentage}%`);
4291
+ this.syncState.syncProgress = payload.percentage;
4292
+ this.syncState.syncedChains = payload.completed;
4293
+ this.syncState.totalChains = payload.total;
4294
+ this.events.emit("SYNC_PROGRESS", this.syncState);
4295
+ } catch (e) {
4296
+ console.error(tag7, "Error processing sync progress:", e);
4297
+ }
4298
+ });
4299
+ clientEvents.events.on("sync:complete", (data) => {
4300
+ const tag7 = TAG9 + " | sync:complete | ";
4301
+ try {
4302
+ const payload = typeof data === "string" ? JSON.parse(data) : data;
4303
+ console.log(tag7, `Sync complete: ${payload.balances} balances in ${payload.duration}ms`);
4304
+ this.syncState.isSynced = true;
4305
+ this.syncState.isInitialSync = false;
4306
+ this.syncState.syncProgress = 100;
4307
+ this.syncState.lastSyncTime = Date.now();
4308
+ this.syncState.syncSource = "fresh";
4309
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4310
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4311
+ } catch (e) {
4312
+ console.error(tag7, "Error processing sync complete:", e);
4313
+ }
4314
+ });
4221
4315
  this.events.emit("SET_STATUS", "init");
4222
4316
  if (this.keepKeySdk && !skipSync) {
4223
4317
  console.log("⚡ [FAST PORTFOLIO] Attempting fast load...");
@@ -4376,6 +4470,18 @@ class SDK {
4376
4470
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4377
4471
  })).filter((entry) => entry.percentage > 0);
4378
4472
  this.dashboard = dashboardData;
4473
+ this.syncState = {
4474
+ isSynced: true,
4475
+ isInitialSync: false,
4476
+ cacheAge: 0,
4477
+ syncProgress: 100,
4478
+ syncedChains: this.blockchains.length,
4479
+ totalChains: this.blockchains.length,
4480
+ lastSyncTime: Date.now(),
4481
+ syncSource: "fresh"
4482
+ };
4483
+ this.events.emit("SYNC_STATE_CHANGED", this.syncState);
4484
+ this.events.emit("SYNC_COMPLETE", this.syncState);
4379
4485
  return true;
4380
4486
  } catch (e) {
4381
4487
  console.error(tag6, "Error in sync:", e);
@@ -4964,14 +5070,16 @@ class SDK {
4964
5070
  console.timeEnd("GetPortfolioBalances Response Time");
4965
5071
  let balances = marketInfo.data;
4966
5072
  for (let balance of balances) {
4967
- const assetInfo = this.assetsMap.get(balance.caip);
5073
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4968
5074
  if (!assetInfo)
4969
5075
  continue;
5076
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4970
5077
  Object.assign(balance, assetInfo, {
4971
5078
  networkId: caipToNetworkId7(balance.caip),
4972
5079
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4973
5080
  identifier: `${balance.caip}:${balance.pubkey}`,
4974
- updated: Date.now()
5081
+ updated: Date.now(),
5082
+ color
4975
5083
  });
4976
5084
  }
4977
5085
  this.balances = balances;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "author": "highlander",
3
3
  "name": "@pioneer-platform/pioneer-sdk",
4
- "version": "8.11.8",
4
+ "version": "8.11.9",
5
5
  "dependencies": {
6
6
  "@keepkey/keepkey-sdk": "^0.2.62",
7
7
  "@pioneer-platform/loggerdog": "^8.11.0",
@@ -12,7 +12,8 @@
12
12
  "@pioneer-platform/pioneer-events": "^8.11.0",
13
13
  "coinselect": "^3.1.13",
14
14
  "eventemitter3": "^5.0.1",
15
- "neotraverse": "^0.6.8"
15
+ "neotraverse": "^0.6.8",
16
+ "socket.io-client": "^4.7.2"
16
17
  },
17
18
  "description": "Pioneer Core SDK",
18
19
  "devDependencies": {
package/src/index.ts CHANGED
@@ -23,6 +23,37 @@ import { syncMarket } from './utils/sync-market.js';
23
23
 
24
24
  const TAG = ' | Pioneer-sdk | ';
25
25
 
26
+ // Color mappings for major assets (until pioneer-discovery includes colors)
27
+ const ASSET_COLORS: Record<string, string> = {
28
+ // Bitcoin
29
+ 'bip122:000000000019d6689c085ae165831e93/slip44:0': '#FF9800',
30
+ // Ethereum
31
+ 'eip155:1/slip44:60': '#627EEA',
32
+ // Polygon
33
+ 'eip155:137/slip44:60': '#8247E5',
34
+ // Base
35
+ 'eip155:8453/slip44:60': '#0052FF',
36
+ // BNB
37
+ 'eip155:56/slip44:60': '#F3BA2F',
38
+ // Litecoin
39
+ 'bip122:12a765e31ffd4059bada1e25190f6e98/slip44:2': '#BFBBBB',
40
+ // Dogecoin
41
+ 'bip122:00000000001a91e3dace36e2be3bf030/slip44:3': '#C2A633',
42
+ // Bitcoin Cash
43
+ 'bip122:000000000000000000651ef99cb9fcbe/slip44:145': '#8DC351',
44
+ // Dash
45
+ 'bip122:000007d91d1254d60e2dd1ae58038307/slip44:5': '#008CE7',
46
+ // Cosmos
47
+ 'cosmos:cosmoshub-4/slip44:118': '#2E3148',
48
+ // Osmosis
49
+ 'cosmos:osmosis-1/slip44:118': '#9B1FD7',
50
+ // XRP
51
+ 'ripple:4109c6f2045fc7eff4cde8f9905d19c2/slip44:144': '#23292F',
52
+ // Maya/CACAO
53
+ 'cosmos:mayachain-mainnet-v1/slip44:931': '#00D4AA',
54
+ // Thorchain/RUNE
55
+ 'cosmos:thorchain-mainnet-v1/slip44:931': '#00CCFF',
56
+ };
26
57
 
27
58
  export interface PioneerSDKConfig {
28
59
  appName: string;
@@ -46,6 +77,17 @@ export interface PioneerSDKConfig {
46
77
  forceLocalhost?: boolean;
47
78
  }
48
79
 
80
+ export interface SyncState {
81
+ isSynced: boolean; // Has fresh data from full sync?
82
+ isInitialSync: boolean; // First sync (no cache)?
83
+ cacheAge: number; // Seconds since last cache update
84
+ syncProgress: number; // 0-100 percentage of completion
85
+ syncedChains: number; // Number of chains synced
86
+ totalChains: number; // Total chains to sync
87
+ lastSyncTime: number | null; // Timestamp of last successful sync
88
+ syncSource: 'cache' | 'fresh' | 'none'; // Where data came from
89
+ }
90
+
49
91
 
50
92
  export class SDK {
51
93
  public status: string;
@@ -66,6 +108,7 @@ export class SDK {
66
108
  public outboundBlockchainContext: any;
67
109
  public outboundPubkeyContext: any;
68
110
  public buildDashboardFromBalances: any;
111
+ public syncState: SyncState;
69
112
  // public swapKit: any | null;
70
113
  public pioneer: any;
71
114
  public charts: any[];
@@ -131,6 +174,8 @@ export class SDK {
131
174
  public estimateTransactionFee: (feeRate: string, unit: string, networkType: string, txSize?: number) => FeeEstimate;
132
175
  public getCharts: () => Promise<any>;
133
176
  public keepKeySdk: any;
177
+ public getSyncState: () => SyncState;
178
+ public isSynced: () => boolean;
134
179
  private getGasAssets: () => Promise<any>;
135
180
  private transactions: any;
136
181
  private transfer: (sendPayload: any) => Promise<any>;
@@ -210,6 +255,18 @@ export class SDK {
210
255
  this.walletConnectProjectId = config.walletConnectProjectId;
211
256
  this.contextType = '';
212
257
 
258
+ // Initialize sync state
259
+ this.syncState = {
260
+ isSynced: false,
261
+ isInitialSync: true,
262
+ cacheAge: 0,
263
+ syncProgress: 0,
264
+ syncedChains: 0,
265
+ totalChains: this.blockchains.length,
266
+ lastSyncTime: null,
267
+ syncSource: 'none'
268
+ };
269
+
213
270
  // Initialize offline client if offline-first mode is enabled
214
271
  this.offlineClient = config.offlineFirst
215
272
  ? new OfflineClient({
@@ -409,6 +466,23 @@ export class SDK {
409
466
 
410
467
  this.dashboard = dashboardData;
411
468
  this.events.emit('SET_DASHBOARD', this.dashboard);
469
+
470
+ // Update sync state - cache hit
471
+ const cacheAge = portfolioData.lastUpdated
472
+ ? Math.floor((Date.now() - portfolioData.lastUpdated) / 1000)
473
+ : 0;
474
+
475
+ this.syncState = {
476
+ isSynced: true,
477
+ isInitialSync: false,
478
+ cacheAge,
479
+ syncProgress: 100,
480
+ syncedChains: this.blockchains.length,
481
+ totalChains: this.blockchains.length,
482
+ lastSyncTime: portfolioData.lastUpdated || Date.now(),
483
+ syncSource: 'cache'
484
+ };
485
+ this.events.emit('SYNC_STATE_CHANGED', this.syncState);
412
486
  } else {
413
487
  console.warn(
414
488
  '[CACHE VALIDATION] ❌ Cache data corrupted, building dashboard from cached balances',
@@ -443,6 +517,16 @@ export class SDK {
443
517
  }
444
518
  };
445
519
 
520
+ // Get current sync state
521
+ this.getSyncState = function (): SyncState {
522
+ return this.syncState;
523
+ };
524
+
525
+ // Check if SDK has synced data (either from cache or fresh sync)
526
+ this.isSynced = function (): boolean {
527
+ return this.syncState.isSynced;
528
+ };
529
+
446
530
  this.init = async function (walletsVerbose: any, setup: any) {
447
531
  const tag = `${TAG} | init | `;
448
532
  try {
@@ -515,6 +599,78 @@ export class SDK {
515
599
  this.events.emit('message', request);
516
600
  });
517
601
 
602
+ // Listen for balance streaming events (Phase 2b)
603
+ clientEvents.events.on('balance:update', (data: any) => {
604
+ const tag = TAG + ' | balance:update | ';
605
+ try {
606
+ const payload = typeof data === 'string' ? JSON.parse(data) : data;
607
+ const balance = payload.balance;
608
+
609
+ console.log(tag, 'Received balance update:', balance.caip);
610
+
611
+ // Add balance to balances array if not already present
612
+ const exists = this.balances.find((b: any) =>
613
+ b.caip === balance.caip && b.pubkey === balance.pubkey
614
+ );
615
+
616
+ if (!exists) {
617
+ this.balances.push(balance);
618
+ } else {
619
+ // Update existing balance
620
+ const index = this.balances.findIndex((b: any) =>
621
+ b.caip === balance.caip && b.pubkey === balance.pubkey
622
+ );
623
+ this.balances[index] = balance;
624
+ }
625
+
626
+ // Emit SDK event for UI updates
627
+ this.events.emit('BALANCE_UPDATE', balance);
628
+ } catch (e) {
629
+ console.error(tag, 'Error processing balance update:', e);
630
+ }
631
+ });
632
+
633
+ clientEvents.events.on('sync:progress', (data: any) => {
634
+ const tag = TAG + ' | sync:progress | ';
635
+ try {
636
+ const payload = typeof data === 'string' ? JSON.parse(data) : data;
637
+
638
+ console.log(tag, `Sync progress: ${payload.percentage}%`);
639
+
640
+ // Update sync state
641
+ this.syncState.syncProgress = payload.percentage;
642
+ this.syncState.syncedChains = payload.completed;
643
+ this.syncState.totalChains = payload.total;
644
+
645
+ // Emit SDK event
646
+ this.events.emit('SYNC_PROGRESS', this.syncState);
647
+ } catch (e) {
648
+ console.error(tag, 'Error processing sync progress:', e);
649
+ }
650
+ });
651
+
652
+ clientEvents.events.on('sync:complete', (data: any) => {
653
+ const tag = TAG + ' | sync:complete | ';
654
+ try {
655
+ const payload = typeof data === 'string' ? JSON.parse(data) : data;
656
+
657
+ console.log(tag, `Sync complete: ${payload.balances} balances in ${payload.duration}ms`);
658
+
659
+ // Update sync state
660
+ this.syncState.isSynced = true;
661
+ this.syncState.isInitialSync = false;
662
+ this.syncState.syncProgress = 100;
663
+ this.syncState.lastSyncTime = Date.now();
664
+ this.syncState.syncSource = 'fresh';
665
+
666
+ // Emit SDK events
667
+ this.events.emit('SYNC_COMPLETE', this.syncState);
668
+ this.events.emit('SYNC_STATE_CHANGED', this.syncState);
669
+ } catch (e) {
670
+ console.error(tag, 'Error processing sync complete:', e);
671
+ }
672
+ });
673
+
518
674
  this.events.emit('SET_STATUS', 'init');
519
675
 
520
676
  // Fast Portfolio Pattern: Try unified portfolio first, then sync if needed
@@ -786,6 +942,20 @@ export class SDK {
786
942
 
787
943
  this.dashboard = dashboardData;
788
944
 
945
+ // Update sync state - fresh sync complete
946
+ this.syncState = {
947
+ isSynced: true,
948
+ isInitialSync: false,
949
+ cacheAge: 0,
950
+ syncProgress: 100,
951
+ syncedChains: this.blockchains.length,
952
+ totalChains: this.blockchains.length,
953
+ lastSyncTime: Date.now(),
954
+ syncSource: 'fresh'
955
+ };
956
+ this.events.emit('SYNC_STATE_CHANGED', this.syncState);
957
+ this.events.emit('SYNC_COMPLETE', this.syncState);
958
+
789
959
  return true;
790
960
  } catch (e) {
791
961
  console.error(tag, 'Error in sync:', e);
@@ -1567,14 +1737,18 @@ export class SDK {
1567
1737
 
1568
1738
  // Enrich balances with asset info
1569
1739
  for (let balance of balances) {
1570
- const assetInfo = this.assetsMap.get(balance.caip);
1740
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
1571
1741
  if (!assetInfo) continue;
1572
1742
 
1743
+ // Get color from mapping (fallback to assetInfo.color if it exists)
1744
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
1745
+
1573
1746
  Object.assign(balance, assetInfo, {
1574
1747
  networkId: caipToNetworkId(balance.caip),
1575
1748
  icon: assetInfo.icon || 'https://pioneers.dev/coins/etherum.png',
1576
1749
  identifier: `${balance.caip}:${balance.pubkey}`,
1577
1750
  updated: Date.now(), // Add timestamp for worker validation
1751
+ color, // Add color from mapping
1578
1752
  });
1579
1753
  }
1580
1754
  this.balances = balances;