@sage-protocol/cli 0.6.2 → 0.6.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.
@@ -987,10 +987,10 @@ function register(program) {
987
987
  ui.info('Run: sage governance threshold-status' + (opts.gov ? ` --gov ${opts.gov}` : '') + (opts.subdao ? ` --subdao ${opts.subdao}` : ''));
988
988
  })
989
989
  )
990
- // Cancel command for threshold-based cancellation
990
+ // Cancel command for threshold-based cancellation and guardian veto
991
991
  .addCommand(
992
992
  new Command('cancel')
993
- .description('Cancel a proposal (if you are the proposer, or proposer dropped below threshold)')
993
+ .description('Cancel a proposal (proposer, threshold-based, or guardian veto)')
994
994
  .argument('<id>', 'Proposal ID')
995
995
  .option('--subdao <address>', 'SubDAO address to derive Governor from')
996
996
  .option('--gov <address>', 'Governor address (overrides SubDAO/context)')
@@ -1011,20 +1011,44 @@ function register(program) {
1011
1011
  'function proposalThreshold() view returns (uint256)',
1012
1012
  'function sxxxToken() view returns (address)',
1013
1013
  'function state(uint256) view returns (uint8)',
1014
+ 'function subDAO() view returns (address)',
1014
1015
  // OZ Governor cancel signature
1015
1016
  'function cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) returns (uint256)',
1016
1017
  ]);
1017
1018
 
1018
1019
  const govRead = new ethers.Contract(govAddr, iface, readProvider);
1019
1020
 
1020
- // Check proposal state and cancelability
1021
+ // Check proposal state
1021
1022
  const state = await govRead.state(proposalId);
1022
1023
  const stateNames = ['Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'];
1023
1024
  const stateName = stateNames[Number(state)] || `Unknown(${state})`;
1025
+ const stateNum = Number(state);
1024
1026
 
1025
- if (Number(state) >= 2) {
1026
- throw new Error(`Proposal not cancelable - current state: ${stateName}`);
1027
- }
1027
+ // Get SubDAO and check guardian role
1028
+ const GUARDIAN_ROLE = ethers.keccak256(ethers.toUtf8Bytes('GUARDIAN_ROLE'));
1029
+ let isGuardian = false;
1030
+ let subdaoAddr = null;
1031
+ const myAddress = await signer.getAddress();
1032
+
1033
+ try {
1034
+ subdaoAddr = await govRead.subDAO();
1035
+ if (subdaoAddr && subdaoAddr !== ethers.ZeroAddress) {
1036
+ const subdaoIface = new ethers.Interface([
1037
+ 'function hasRole(bytes32 role, address account) view returns (bool)',
1038
+ ]);
1039
+ const subdao = new ethers.Contract(subdaoAddr, subdaoIface, readProvider);
1040
+ isGuardian = await subdao.hasRole(GUARDIAN_ROLE, myAddress);
1041
+ }
1042
+ } catch (_) { /* SubDAO may not be available */ }
1043
+
1044
+ // State validation based on authorization path
1045
+ // Guardians can cancel: Pending (0), Active (1), Succeeded (4), Queued (5)
1046
+ // Others can only cancel: Pending (0), Active (1)
1047
+ const guardianCancelableStates = [0, 1, 4, 5]; // Pending, Active, Succeeded, Queued
1048
+ const normalCancelableStates = [0, 1]; // Pending, Active
1049
+
1050
+ const isGuardianCancelable = guardianCancelableStates.includes(stateNum);
1051
+ const isNormalCancelable = normalCancelableStates.includes(stateNum);
1028
1052
 
1029
1053
  // Get proposer and check threshold
1030
1054
  let proposer = null, threshold = null, sxxxToken = null, proposerBalance = null;
@@ -1037,20 +1061,36 @@ function register(program) {
1037
1061
  proposerBalance = await erc20.balanceOf(proposer);
1038
1062
  }
1039
1063
 
1040
- const myAddress = await signer.getAddress();
1041
1064
  const iAmProposer = proposer && proposer.toLowerCase() === myAddress.toLowerCase();
1042
1065
  const proposerBelowThreshold = (threshold !== null && proposerBalance !== null) ? proposerBalance < threshold : false;
1043
- const canCancel = iAmProposer || proposerBelowThreshold;
1044
1066
 
1045
- if (!canCancel) {
1046
- throw new Error(`Cannot cancel: You are not the proposer and proposer's balance (${proposerBalance ? ethers.formatEther(proposerBalance) : '?'} SXXX) is still above threshold (${threshold ? ethers.formatEther(threshold) : '?'} SXXX)`);
1067
+ // Determine cancel authorization
1068
+ let cancelReason = null;
1069
+ if (isGuardian && isGuardianCancelable) {
1070
+ cancelReason = 'guardian_veto';
1071
+ } else if (isNormalCancelable && iAmProposer) {
1072
+ cancelReason = 'proposer';
1073
+ } else if (isNormalCancelable && proposerBelowThreshold) {
1074
+ cancelReason = 'below_threshold';
1075
+ }
1076
+
1077
+ if (!cancelReason) {
1078
+ if (isGuardian && !isGuardianCancelable) {
1079
+ throw new Error(`Proposal not cancelable - current state: ${stateName} (guardians cannot cancel ${stateName} proposals)`);
1080
+ } else if (!isNormalCancelable) {
1081
+ throw new Error(`Proposal not cancelable - current state: ${stateName}`);
1082
+ } else {
1083
+ throw new Error(`Cannot cancel: You are not the proposer, not a guardian, and proposer's balance (${proposerBalance ? ethers.formatEther(proposerBalance) : '?'} SXXX) is still above threshold (${threshold ? ethers.formatEther(threshold) : '?'} SXXX)`);
1084
+ }
1047
1085
  }
1048
1086
 
1049
1087
  if (!opts.json) {
1050
1088
  ui.info(`Proposal ${id} - State: ${stateName}`);
1051
- if (iAmProposer) {
1089
+ if (cancelReason === 'guardian_veto') {
1090
+ ui.warn('🛡️ Guardian veto: Using emergency cancel authority');
1091
+ } else if (cancelReason === 'proposer') {
1052
1092
  ui.info('You are the proposer - can cancel your own proposal');
1053
- } else if (proposerBelowThreshold) {
1093
+ } else if (cancelReason === 'below_threshold') {
1054
1094
  ui.info(`Proposer dropped below threshold (${ethers.formatEther(proposerBalance)} < ${ethers.formatEther(threshold)} SXXX)`);
1055
1095
  }
1056
1096
  }
@@ -1107,7 +1147,7 @@ function register(program) {
1107
1147
  // Check cancelability of a proposal
1108
1148
  .addCommand(
1109
1149
  new Command('cancelability')
1110
- .description('Check if a proposal can be canceled (threshold-based or by proposer)')
1150
+ .description('Check if a proposal can be canceled (proposer, threshold-based, or guardian veto)')
1111
1151
  .argument('<id>', 'Proposal ID')
1112
1152
  .option('--subdao <address>', 'SubDAO address to derive Governor from')
1113
1153
  .option('--gov <address>', 'Governor address (overrides SubDAO/context)')
@@ -1128,6 +1168,7 @@ function register(program) {
1128
1168
  'function proposalThresholdSnapshot(uint256) view returns (uint256)',
1129
1169
  'function sxxxToken() view returns (address)',
1130
1170
  'function state(uint256) view returns (uint8)',
1171
+ 'function subDAO() view returns (address)',
1131
1172
  ]);
1132
1173
 
1133
1174
  const gov = new ethers.Contract(govAddr, iface, provider);
@@ -1136,9 +1177,15 @@ function register(program) {
1136
1177
  const state = await gov.state(proposalId);
1137
1178
  const stateNames = ['Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'];
1138
1179
  const stateName = stateNames[Number(state)] || `Unknown(${state})`;
1180
+ const stateNum = Number(state);
1139
1181
 
1140
- // Cancelable states: Pending (0) or Active (1)
1141
- const inCancelableState = Number(state) < 2;
1182
+ // Cancelable states differ by authorization path
1183
+ // Guardians: Pending (0), Active (1), Succeeded (4), Queued (5)
1184
+ // Others: Pending (0), Active (1)
1185
+ const guardianCancelableStates = [0, 1, 4, 5];
1186
+ const normalCancelableStates = [0, 1];
1187
+ const inGuardianCancelableState = guardianCancelableStates.includes(stateNum);
1188
+ const inNormalCancelableState = normalCancelableStates.includes(stateNum);
1142
1189
 
1143
1190
  // Get proposer and threshold info
1144
1191
  let proposer = null, threshold = null, snapshotThreshold = null, sxxxToken = null, proposerBalance = null;
@@ -1163,19 +1210,21 @@ function register(program) {
1163
1210
  const result = {
1164
1211
  proposalId: proposalId.toString(),
1165
1212
  state: stateName,
1166
- stateNum: Number(state),
1167
- inCancelableState,
1213
+ stateNum,
1214
+ cancelableByGuardian: inGuardianCancelableState,
1215
+ cancelableByProposer: inNormalCancelableState,
1216
+ cancelableByAnyone: inNormalCancelableState && proposerBelowThreshold,
1168
1217
  proposer,
1169
1218
  threshold: effectiveThreshold ? ethers.formatEther(effectiveThreshold) : null,
1170
1219
  proposerBalance: proposerBalance !== null ? ethers.formatEther(proposerBalance) : null,
1171
1220
  proposerBelowThreshold,
1172
- cancelableByAnyone: inCancelableState && proposerBelowThreshold,
1173
- cancelableByProposer: inCancelableState,
1174
- reason: !inCancelableState
1221
+ reason: !inNormalCancelableState && !inGuardianCancelableState
1175
1222
  ? `Proposal in ${stateName} state (not cancelable)`
1176
- : proposerBelowThreshold
1177
- ? 'Proposer below threshold - anyone can cancel'
1178
- : 'Only proposer can cancel',
1223
+ : inGuardianCancelableState && !inNormalCancelableState
1224
+ ? `Guardian veto available (${stateName} state)`
1225
+ : proposerBelowThreshold
1226
+ ? 'Proposer below threshold - anyone can cancel'
1227
+ : 'Proposer or guardian can cancel',
1179
1228
  };
1180
1229
 
1181
1230
  if (opts.json) {
@@ -1188,17 +1237,21 @@ function register(program) {
1188
1237
  ui.labelValue('Proposer Balance', result.proposerBalance ? `${result.proposerBalance} SXXX` : '-');
1189
1238
  ui.newline();
1190
1239
 
1191
- if (!inCancelableState) {
1240
+ if (!inNormalCancelableState && !inGuardianCancelableState) {
1192
1241
  ui.info(`Not cancelable: ${stateName} state`);
1242
+ } else if (inGuardianCancelableState && !inNormalCancelableState) {
1243
+ ui.warn(`🛡️ Guardian veto available: ${stateName} proposals can be canceled by guardians`);
1244
+ ui.info('Run: sage governance cancel ' + id + ' (requires GUARDIAN_ROLE)');
1193
1245
  } else if (proposerBelowThreshold) {
1194
1246
  ui.warn('Cancelable by anyone: proposer dropped below threshold');
1195
1247
  ui.info('Run: sage governance cancel ' + id);
1196
1248
  } else {
1197
- ui.info('Only cancelable by proposer');
1249
+ ui.info('Cancelable by proposer or guardian');
1198
1250
  }
1199
1251
  }
1200
1252
 
1201
- process.exit(result.cancelableByAnyone ? 0 : 1);
1253
+ // Exit 0 if cancelable by anyone (threshold) or guardian
1254
+ process.exit(result.cancelableByAnyone || result.cancelableByGuardian ? 0 : 1);
1202
1255
 
1203
1256
  } catch (e) {
1204
1257
  if (opts.json) {
@@ -24,7 +24,7 @@ function getDefaultSubgraphUrl() {
24
24
  return (
25
25
  process.env.SUBGRAPH_URL ||
26
26
  process.env.SAGE_SUBGRAPH_URL ||
27
- 'https://api.studio.thegraph.com/query/67446/sage-protocol-base-sepolia/version/latest'
27
+ 'https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.5/gn'
28
28
  );
29
29
  }
30
30
 
@@ -518,7 +518,7 @@ class PrivyAuthWalletManager {
518
518
  "react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime",
519
519
  "react-dom": "https://esm.sh/react-dom@18.2.0",
520
520
  "react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
521
- "@privy-io/react-auth": "https://esm.sh/@privy-io/react-auth@2.25.0?external=react,react-dom"
521
+ "@privy-io/react-auth": "https://esm.sh/@privy-io/react-auth@1.73.1?external=react,react-dom"
522
522
  }
523
523
  }
524
524
  </script>
@@ -529,20 +529,17 @@ class PrivyAuthWalletManager {
529
529
  <script type="text/babel" data-type="module" data-presets="react">
530
530
  import React, { useState, useEffect } from 'react';
531
531
  import { createRoot } from 'react-dom/client';
532
- import { PrivyProvider, usePrivy, useSessionSigners, useWallets } from '@privy-io/react-auth';
532
+ import { PrivyProvider, usePrivy } from '@privy-io/react-auth';
533
533
 
534
534
  const PRIVY_APP_ID = '${this.appId}';
535
- const SESSION_SIGNER_ID = '${sessionSignerAddress || process.env.PRIVY_SESSION_SIGNER_ID || ''}';
535
+ const SESSION_SIGNER_ID = '${sessionSignerAddress || ''}';
536
536
  const CALLBACK_URL = 'http://localhost:${port}/callback';
537
537
  const STATE = '${state}';
538
538
 
539
539
  function LoginApp() {
540
- const { login, authenticated, user, ready, getAccessToken, logout } = usePrivy();
541
- const { addSessionSigners } = useSessionSigners();
542
- const { wallets, createWallet } = useWallets();
540
+ const { login, authenticated, user, ready, getAccessToken, logout, createWallet } = usePrivy();
543
541
  const [status, setStatus] = useState('');
544
- const [isDelegating, setIsDelegating] = useState(false);
545
- const [showManualCreate, setShowManualCreate] = useState(false);
542
+ const [isProcessing, setIsProcessing] = useState(false);
546
543
 
547
544
  useEffect(() => {
548
545
  if (ready && !authenticated) {
@@ -550,65 +547,38 @@ class PrivyAuthWalletManager {
550
547
  }
551
548
  }, [ready, authenticated]);
552
549
 
553
- // Show manual create button after 5 seconds if still delegating
554
- useEffect(() => {
555
- if (isDelegating) {
556
- const timer = setTimeout(() => setShowManualCreate(true), 5000);
557
- return () => clearTimeout(timer);
558
- }
559
- }, [isDelegating]);
560
-
561
- const handleDelegationAndCallback = async (walletAddress) => {
550
+ const handleCallback = async (walletAddress) => {
562
551
  try {
563
- setIsDelegating(true);
564
- setStatus('Adding session signer for CLI...');
565
- console.log('Attempting to add session signer:', walletAddress);
566
-
567
- if (!SESSION_SIGNER_ID) {
568
- setStatus('Server session signer not configured. Set PRIVY_SESSION_SIGNER_ID in your environment.');
569
- setIsDelegating(false);
570
- setShowManualCreate(true);
571
- return;
572
- }
573
-
574
- // SESSION_SIGNER_ID is "wallet-auth:<base64-spki>"
575
- const res = await addSessionSigners({
576
- address: walletAddress,
577
- signers: [{ signerId: SESSION_SIGNER_ID }],
552
+ setIsProcessing(true);
553
+ setStatus('Finalizing login...');
554
+
555
+ const token = await getAccessToken();
556
+ await fetch(CALLBACK_URL, {
557
+ method: 'POST',
558
+ headers: { 'Content-Type': 'application/json' },
559
+ body: JSON.stringify({
560
+ state: STATE,
561
+ userId: user.id,
562
+ walletId: walletAddress,
563
+ walletAddress: walletAddress,
564
+ accessToken: token,
565
+ email: user.email?.address
566
+ })
578
567
  });
579
- console.log('Session signer added result:', JSON.stringify(res));
580
-
581
- setStatus('Session signer added! Finalizing...');
582
-
583
- const token = await getAccessToken();
584
- await fetch(CALLBACK_URL, {
585
- method: 'POST',
586
- headers: { 'Content-Type': 'application/json' },
587
- body: JSON.stringify({
588
- state: STATE,
589
- userId: user.id,
590
- walletId: walletAddress,
591
- walletAddress: walletAddress,
592
- accessToken: token,
593
- email: user.email?.address
594
- })
595
- });
596
568
  setStatus('Done! You can close this window.');
597
569
  } catch (err) {
598
- console.error('Delegation error:', err);
599
- setStatus('Delegation failed: ' + err.message);
600
- setIsDelegating(false);
601
- setShowManualCreate(true);
570
+ console.error('Callback error:', err);
571
+ setStatus('Error: ' + err.message);
572
+ setIsProcessing(false);
602
573
  }
603
574
  };
604
575
 
605
- const createNewWallet = async () => {
576
+ const handleCreateWallet = async () => {
606
577
  try {
607
578
  setStatus('Creating new wallet...');
608
579
  const newWallet = await createWallet();
609
- setStatus('New wallet created: ' + newWallet.address);
610
- // Wait a moment for state to settle
611
- setTimeout(() => handleDelegationAndCallback(newWallet.address), 1000);
580
+ setStatus('Wallet created: ' + newWallet.address);
581
+ setTimeout(() => handleCallback(newWallet.address), 500);
612
582
  } catch (err) {
613
583
  console.error('Creation error:', err);
614
584
  setStatus('Failed to create wallet: ' + err.message);
@@ -623,44 +593,24 @@ class PrivyAuthWalletManager {
623
593
 
624
594
  useEffect(() => {
625
595
  async function handleAuth() {
626
- if (authenticated && user && !isDelegating && !status.includes('Error') && !status.includes('Done')) {
596
+ if (authenticated && user && !isProcessing && !status.includes('Error') && !status.includes('Done')) {
627
597
  try {
628
598
  // Find the *embedded* wallet
629
- const embeddedWallet = user.linkedAccounts.find(
599
+ const embeddedWallet = user.linkedAccounts?.find(
630
600
  (account) => account.type === 'wallet' && account.walletClientType === 'privy'
631
601
  );
632
602
 
633
603
  if (!embeddedWallet) {
634
604
  setStatus('No embedded wallet found. Creating one...');
635
- createNewWallet();
605
+ handleCreateWallet();
636
606
  return;
637
607
  }
638
608
 
639
- if (!embeddedWallet.delegated) {
640
- await handleDelegationAndCallback(embeddedWallet.address);
641
- } else {
642
- // Already delegated, just callback
643
- setStatus('Finalizing login...');
644
- const token = await getAccessToken();
645
- await fetch(CALLBACK_URL, {
646
- method: 'POST',
647
- headers: { 'Content-Type': 'application/json' },
648
- body: JSON.stringify({
649
- state: STATE,
650
- userId: user.id,
651
- walletId: embeddedWallet.address,
652
- walletAddress: embeddedWallet.address,
653
- accessToken: token,
654
- email: user.email?.address
655
- })
656
- });
657
- setStatus('Done! You can close this window.');
658
- }
609
+ await handleCallback(embeddedWallet.address);
659
610
  } catch (err) {
660
611
  console.error(err);
661
612
  setStatus('Error: ' + err.message);
662
- setIsDelegating(false);
663
- setShowManualCreate(true);
613
+ setIsProcessing(false);
664
614
  }
665
615
  }
666
616
  }
@@ -677,18 +627,18 @@ class PrivyAuthWalletManager {
677
627
  <p>Please log in to continue.</p>
678
628
  ) : (
679
629
  <div>
680
- <p>Logged in as {user?.email?.address}</p>
630
+ <p>Logged in as {user?.email?.address || 'User'}</p>
681
631
  {status && (
682
632
  <div className={"status " + (status.includes('Error') || status.includes('Failed') ? 'error' : 'success')}>
683
633
  {status}
684
634
  </div>
685
635
  )}
686
- {isDelegating && <div className="loader" style={{marginTop: '1rem'}}></div>}
687
-
688
- {(showManualCreate || status.includes('Error') || status.includes('Failed')) && (
636
+ {isProcessing && !status.includes('Done') && <div className="loader" style={{marginTop: '1rem'}}></div>}
637
+
638
+ {(status.includes('Error') || status.includes('Failed')) && (
689
639
  <div style={{marginTop: '1.5rem', borderTop: '1px solid #eee', paddingTop: '1rem'}}>
690
- <p style={{marginBottom: '0.5rem', fontSize: '0.9rem'}}>Stuck? Try creating a new wallet:</p>
691
- <button onClick={createNewWallet}>
640
+ <p style={{marginBottom: '0.5rem', fontSize: '0.9rem'}}>Stuck? Try these options:</p>
641
+ <button onClick={handleCreateWallet}>
692
642
  Create New Wallet & Retry
693
643
  </button>
694
644
  <button onClick={handleLogout} style={{marginTop: '0.5rem', background: '#eee', color: '#333'}}>
@@ -11,7 +11,9 @@ fi
11
11
  if [ -f ./.env ]; then
12
12
  while IFS= read -r line; do
13
13
  [[ -z "$line" || ${line:0:1} == "#" ]] && continue
14
- export "$line"
14
+ # Skip lines that already have 'export' prefix or contain special characters
15
+ [[ "$line" == export* ]] && continue
16
+ export "$line" 2>/dev/null || true
15
17
  done < ./.env
16
18
  fi
17
19
 
@@ -51,6 +53,10 @@ const pairs = [
51
53
  ['SIMPLE_CONTRIBUTOR_SYSTEM_ADDRESS', 'SimpleContributorSystem'],
52
54
  ['VOTING_MULTIPLIER_NFT_ADDRESS', 'VotingMultiplierNFT'],
53
55
  ['SAGE_AUCTION_HOUSE_ADDRESS', 'SageAuctionHouse'],
56
+ ['SBT_ADDRESS', 'SoulboundBadge'],
57
+ ['PREMIUM_PROMPTS_ADDRESS', 'PremiumPrompts'],
58
+ ['PREMIUM_RECEIPT_ADDRESS', 'PremiumReceipt'],
59
+ ['GOVERNANCE_CONFIG_ADDRESS', 'GovernanceConfig'],
54
60
  ];
55
61
  const lines = [];
56
62
  for (const [envKey, contractKey] of pairs) {
@@ -79,11 +85,4 @@ echo "GRAPH_STUDIO_PROJECT_ID: ${GRAPH_STUDIO_PROJECT_ID:-unset}"
79
85
  echo "BOOST_MANAGER_ADDRESS: ${BOOST_MANAGER_ADDRESS:-unset}"
80
86
  echo "SIMPLE_BOUNTY_SYSTEM_ADDRESS: ${SIMPLE_BOUNTY_SYSTEM_ADDRESS:-unset}"
81
87
  echo "SXXX_FAUCET_ADDRESS: ${SXXX_FAUCET_ADDRESS:-unset}"
82
-
83
- export BOOST_MANAGER_DIRECT_ADDRESS=0xBAf5E782f9Ff645992b623415938eC33b6eEEcc6
84
-
85
- export BOOST_VIEW_GLUE_ADDRESS=0x266F3386907de1713393c0ed51aD08775d3Df016
86
-
87
- export BOOST_LOGGER_GLUE_ADDRESS=0x6B72761193D32aa225CC1BB020F3A4215B5d92c2
88
-
89
- export BOOST_CREATION_GLUE_ADDRESS=0xC05cd2068fda3f0C9DF177a316A64cB9AA93071B
88
+ echo "SBT_ADDRESS: ${SBT_ADDRESS:-unset}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sage-protocol/cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Sage Protocol CLI for managing AI prompt libraries",
5
5
  "bin": {
6
6
  "sage": "./bin/sage.js"
@@ -39,7 +39,7 @@
39
39
  "@lit-protocol/lit-node-client-nodejs": "^7.3.1",
40
40
  "@privy-io/node": "^0.6.2",
41
41
  "@sage-protocol/contracts": "^0.1.0",
42
- "@sage-protocol/sdk": "^0.1.24",
42
+ "@sage-protocol/sdk": "workspace:*",
43
43
  "@sage-protocol/shared": "^0.1.0",
44
44
  "@sage-protocol/wallet-manager": "^0.1.0",
45
45
  "@walletconnect/sign-client": "^2.21.6",