@pioneer-platform/pioneer-sdk 8.11.7 → 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...");
@@ -4126,6 +4220,7 @@ class SDK {
4126
4220
  }
4127
4221
  }
4128
4222
  await this.getBalances();
4223
+ await this.syncMarket();
4129
4224
  const dashboardData = {
4130
4225
  networks: [],
4131
4226
  totalValueUsd: 0,
@@ -4199,6 +4294,18 @@ class SDK {
4199
4294
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4200
4295
  })).filter((entry) => entry.percentage > 0);
4201
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);
4202
4309
  return true;
4203
4310
  } catch (e) {
4204
4311
  console.error(tag6, "Error in sync:", e);
@@ -4787,14 +4894,16 @@ class SDK {
4787
4894
  console.timeEnd("GetPortfolioBalances Response Time");
4788
4895
  let balances = marketInfo.data;
4789
4896
  for (let balance of balances) {
4790
- const assetInfo = this.assetsMap.get(balance.caip);
4897
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4791
4898
  if (!assetInfo)
4792
4899
  continue;
4900
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4793
4901
  Object.assign(balance, assetInfo, {
4794
4902
  networkId: import_pioneer_caip8.caipToNetworkId(balance.caip),
4795
4903
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4796
4904
  identifier: `${balance.caip}:${balance.pubkey}`,
4797
- updated: Date.now()
4905
+ updated: Date.now(),
4906
+ color
4798
4907
  });
4799
4908
  }
4800
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...");
@@ -4302,6 +4396,7 @@ class SDK {
4302
4396
  }
4303
4397
  }
4304
4398
  await this.getBalances();
4399
+ await this.syncMarket();
4305
4400
  const dashboardData = {
4306
4401
  networks: [],
4307
4402
  totalValueUsd: 0,
@@ -4375,6 +4470,18 @@ class SDK {
4375
4470
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4376
4471
  })).filter((entry) => entry.percentage > 0);
4377
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);
4378
4485
  return true;
4379
4486
  } catch (e) {
4380
4487
  console.error(tag6, "Error in sync:", e);
@@ -4963,14 +5070,16 @@ class SDK {
4963
5070
  console.timeEnd("GetPortfolioBalances Response Time");
4964
5071
  let balances = marketInfo.data;
4965
5072
  for (let balance of balances) {
4966
- const assetInfo = this.assetsMap.get(balance.caip);
5073
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4967
5074
  if (!assetInfo)
4968
5075
  continue;
5076
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4969
5077
  Object.assign(balance, assetInfo, {
4970
5078
  networkId: caipToNetworkId7(balance.caip),
4971
5079
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4972
5080
  identifier: `${balance.caip}:${balance.pubkey}`,
4973
- updated: Date.now()
5081
+ updated: Date.now(),
5082
+ color
4974
5083
  });
4975
5084
  }
4976
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...");
@@ -4302,6 +4396,7 @@ class SDK {
4302
4396
  }
4303
4397
  }
4304
4398
  await this.getBalances();
4399
+ await this.syncMarket();
4305
4400
  const dashboardData = {
4306
4401
  networks: [],
4307
4402
  totalValueUsd: 0,
@@ -4375,6 +4470,18 @@ class SDK {
4375
4470
  percentage: totalPortfolioValue > 0 ? Number((network.totalValueUsd / totalPortfolioValue * 100).toFixed(2)) : 0
4376
4471
  })).filter((entry) => entry.percentage > 0);
4377
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);
4378
4485
  return true;
4379
4486
  } catch (e) {
4380
4487
  console.error(tag6, "Error in sync:", e);
@@ -4963,14 +5070,16 @@ class SDK {
4963
5070
  console.timeEnd("GetPortfolioBalances Response Time");
4964
5071
  let balances = marketInfo.data;
4965
5072
  for (let balance of balances) {
4966
- const assetInfo = this.assetsMap.get(balance.caip);
5073
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
4967
5074
  if (!assetInfo)
4968
5075
  continue;
5076
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
4969
5077
  Object.assign(balance, assetInfo, {
4970
5078
  networkId: caipToNetworkId7(balance.caip),
4971
5079
  icon: assetInfo.icon || "https://pioneers.dev/coins/etherum.png",
4972
5080
  identifier: `${balance.caip}:${balance.pubkey}`,
4973
- updated: Date.now()
5081
+ updated: Date.now(),
5082
+ color
4974
5083
  });
4975
5084
  }
4976
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.7",
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
@@ -629,6 +785,9 @@ export class SDK {
629
785
  }
630
786
  await this.getBalances();
631
787
 
788
+ // Sync market prices for all balances
789
+ await this.syncMarket();
790
+
632
791
  //we should be fully synced so lets make the dashboard
633
792
  const dashboardData: {
634
793
  networks: {
@@ -783,6 +942,20 @@ export class SDK {
783
942
 
784
943
  this.dashboard = dashboardData;
785
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
+
786
959
  return true;
787
960
  } catch (e) {
788
961
  console.error(tag, 'Error in sync:', e);
@@ -1564,14 +1737,18 @@ export class SDK {
1564
1737
 
1565
1738
  // Enrich balances with asset info
1566
1739
  for (let balance of balances) {
1567
- const assetInfo = this.assetsMap.get(balance.caip);
1740
+ const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
1568
1741
  if (!assetInfo) continue;
1569
1742
 
1743
+ // Get color from mapping (fallback to assetInfo.color if it exists)
1744
+ const color = ASSET_COLORS[balance.caip] || assetInfo.color;
1745
+
1570
1746
  Object.assign(balance, assetInfo, {
1571
1747
  networkId: caipToNetworkId(balance.caip),
1572
1748
  icon: assetInfo.icon || 'https://pioneers.dev/coins/etherum.png',
1573
1749
  identifier: `${balance.caip}:${balance.pubkey}`,
1574
1750
  updated: Date.now(), // Add timestamp for worker validation
1751
+ color, // Add color from mapping
1575
1752
  });
1576
1753
  }
1577
1754
  this.balances = balances;