@sage-protocol/cli 0.6.2 → 0.6.4
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 (
|
|
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
|
|
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
|
-
|
|
1026
|
-
|
|
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
|
-
|
|
1046
|
-
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
1141
|
-
|
|
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
|
|
1167
|
-
|
|
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
|
-
|
|
1173
|
-
cancelableByProposer: inCancelableState,
|
|
1174
|
-
reason: !inCancelableState
|
|
1221
|
+
reason: !inNormalCancelableState && !inGuardianCancelableState
|
|
1175
1222
|
? `Proposal in ${stateName} state (not cancelable)`
|
|
1176
|
-
:
|
|
1177
|
-
?
|
|
1178
|
-
:
|
|
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 (!
|
|
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('
|
|
1249
|
+
ui.info('Cancelable by proposer or guardian');
|
|
1198
1250
|
}
|
|
1199
1251
|
}
|
|
1200
1252
|
|
|
1201
|
-
|
|
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.
|
|
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@
|
|
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
|
|
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 ||
|
|
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 [
|
|
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
|
-
|
|
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
|
-
|
|
564
|
-
setStatus('
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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('
|
|
599
|
-
setStatus('
|
|
600
|
-
|
|
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
|
|
576
|
+
const handleCreateWallet = async () => {
|
|
606
577
|
try {
|
|
607
578
|
setStatus('Creating new wallet...');
|
|
608
579
|
const newWallet = await createWallet();
|
|
609
|
-
setStatus('
|
|
610
|
-
|
|
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 && !
|
|
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
|
|
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
|
-
|
|
605
|
+
handleCreateWallet();
|
|
636
606
|
return;
|
|
637
607
|
}
|
|
638
608
|
|
|
639
|
-
|
|
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
|
-
|
|
663
|
-
setShowManualCreate(true);
|
|
613
|
+
setIsProcessing(false);
|
|
664
614
|
}
|
|
665
615
|
}
|
|
666
616
|
}
|
|
@@ -670,25 +620,27 @@ class PrivyAuthWalletManager {
|
|
|
670
620
|
|
|
671
621
|
if (!ready) return <div className="card"><div className="loader"></div><p>Loading Privy...</p></div>;
|
|
672
622
|
|
|
623
|
+
// Don't show our card when not authenticated - let Privy modal be the only UI
|
|
624
|
+
if (!authenticated) {
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
|
|
673
628
|
return (
|
|
674
629
|
<div className="card">
|
|
675
630
|
<h1>Sage CLI Login</h1>
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
) : (
|
|
679
|
-
<div>
|
|
680
|
-
<p>Logged in as {user?.email?.address}</p>
|
|
631
|
+
<div>
|
|
632
|
+
<p>Logged in as {user?.email?.address || 'User'}</p>
|
|
681
633
|
{status && (
|
|
682
634
|
<div className={"status " + (status.includes('Error') || status.includes('Failed') ? 'error' : 'success')}>
|
|
683
635
|
{status}
|
|
684
636
|
</div>
|
|
685
637
|
)}
|
|
686
|
-
{
|
|
687
|
-
|
|
688
|
-
{(
|
|
638
|
+
{isProcessing && !status.includes('Done') && <div className="loader" style={{marginTop: '1rem'}}></div>}
|
|
639
|
+
|
|
640
|
+
{(status.includes('Error') || status.includes('Failed')) && (
|
|
689
641
|
<div style={{marginTop: '1.5rem', borderTop: '1px solid #eee', paddingTop: '1rem'}}>
|
|
690
|
-
<p style={{marginBottom: '0.5rem', fontSize: '0.9rem'}}>Stuck? Try
|
|
691
|
-
<button onClick={
|
|
642
|
+
<p style={{marginBottom: '0.5rem', fontSize: '0.9rem'}}>Stuck? Try these options:</p>
|
|
643
|
+
<button onClick={handleCreateWallet}>
|
|
692
644
|
Create New Wallet & Retry
|
|
693
645
|
</button>
|
|
694
646
|
<button onClick={handleLogout} style={{marginTop: '0.5rem', background: '#eee', color: '#333'}}>
|
|
@@ -696,8 +648,7 @@ class PrivyAuthWalletManager {
|
|
|
696
648
|
</button>
|
|
697
649
|
</div>
|
|
698
650
|
)}
|
|
699
|
-
|
|
700
|
-
)}
|
|
651
|
+
</div>
|
|
701
652
|
</div>
|
|
702
653
|
);
|
|
703
654
|
}
|
|
@@ -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
|
|
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.
|
|
3
|
+
"version": "0.6.4",
|
|
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": "
|
|
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",
|