strade-stx 1.0.0
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/.activity_counter +1 -0
- package/.gitattributes +3 -0
- package/.vscode/settings.json +4 -0
- package/.vscode/tasks.json +19 -0
- package/CHANGELOG.md +1 -0
- package/Clarinet.toml +56 -0
- package/Clarinet.toml.backup +174 -0
- package/Clarinet.toml.old +146 -0
- package/DEPLOYMENT_RESULTS.md +160 -0
- package/README.md +344 -0
- package/TODO.md +34 -0
- package/contracts/CoreMarketPlace.clar +227 -0
- package/contracts/DisputeResolution_clar.clar +265 -0
- package/contracts/EscrowService.clar +171 -0
- package/contracts/UserProfile.clar +280 -0
- package/contracts/ft-trait.clar +24 -0
- package/contracts/token.clar +178 -0
- package/costs-reports.json +76026 -0
- package/deployments/default.mainnet-plan.yaml +67 -0
- package/deployments/default.simnet-plan.yaml +105 -0
- package/deployments/default.testnet-plan.yaml +67 -0
- package/deployments/new-contracts.testnet-plan.yaml +32 -0
- package/frontend/README.md +10 -0
- package/frontend/components.json +22 -0
- package/frontend/dist/assets/index-BacuuL66.css +1 -0
- package/frontend/dist/assets/index-jryypd5B.js +194 -0
- package/frontend/dist/favicon.png +0 -0
- package/frontend/dist/index.html +15 -0
- package/frontend/dist/manifest.json +15 -0
- package/frontend/dist/vite.svg +1 -0
- package/frontend/empty-mock.js +1 -0
- package/frontend/eslint.config.js +23 -0
- package/frontend/eslint.config.mjs +25 -0
- package/frontend/index.html +14 -0
- package/frontend/next.config.ts +17 -0
- package/frontend/package-lock.json +14740 -0
- package/frontend/package.json +56 -0
- package/frontend/postcss.config.js +5 -0
- package/frontend/postcss.config.mjs +5 -0
- package/frontend/public/favicon.png +0 -0
- package/frontend/public/file.svg +1 -0
- package/frontend/public/globe.svg +1 -0
- package/frontend/public/manifest.json +15 -0
- package/frontend/public/next.svg +1 -0
- package/frontend/public/vercel.svg +1 -0
- package/frontend/public/vite.svg +1 -0
- package/frontend/public/window.svg +1 -0
- package/frontend/src/App.css +42 -0
- package/frontend/src/App.tsx +177 -0
- package/frontend/src/app/about/page.tsx +208 -0
- package/frontend/src/app/favicon.ico +0 -0
- package/frontend/src/app/globals.css +129 -0
- package/frontend/src/app/help/page.tsx +167 -0
- package/frontend/src/app/how-it-works/page.tsx +274 -0
- package/frontend/src/app/layout.tsx +55 -0
- package/frontend/src/app/marketplace/page.tsx +324 -0
- package/frontend/src/app/my-listings/page.tsx +318 -0
- package/frontend/src/app/page.tsx +15 -0
- package/frontend/src/assets/react.svg +1 -0
- package/frontend/src/components/ConfirmDialog.tsx +54 -0
- package/frontend/src/components/CreateListingForm.tsx +231 -0
- package/frontend/src/components/ErrorBoundary.tsx +73 -0
- package/frontend/src/components/FilterPanel.tsx +10 -0
- package/frontend/src/components/Footer.tsx +100 -0
- package/frontend/src/components/Header.tsx +268 -0
- package/frontend/src/components/ImageUpload.tsx +147 -0
- package/frontend/src/components/LandingPage.tsx +322 -0
- package/frontend/src/components/ListingCard.tsx +154 -0
- package/frontend/src/components/LoadingSkeleton.tsx +44 -0
- package/frontend/src/components/MobileNav.tsx +89 -0
- package/frontend/src/components/NotificationBell.tsx +8 -0
- package/frontend/src/components/NotificationPanel.tsx +14 -0
- package/frontend/src/components/README.md +14 -0
- package/frontend/src/components/SearchBar.tsx +10 -0
- package/frontend/src/components/TestnetBanner.tsx +29 -0
- package/frontend/src/components/ThemeToggle.tsx +32 -0
- package/frontend/src/components/__tests__/Header.test.tsx +70 -0
- package/frontend/src/components/__tests__/ListingCard.test.tsx +86 -0
- package/frontend/src/components/providers/ThemeProvider.tsx +9 -0
- package/frontend/src/components/ui/alert-dialog.tsx +141 -0
- package/frontend/src/components/ui/avatar.tsx +53 -0
- package/frontend/src/components/ui/badge.tsx +46 -0
- package/frontend/src/components/ui/button.tsx +60 -0
- package/frontend/src/components/ui/card.tsx +92 -0
- package/frontend/src/components/ui/dialog.tsx +143 -0
- package/frontend/src/components/ui/dropdown-menu.tsx +257 -0
- package/frontend/src/components/ui/input.tsx +21 -0
- package/frontend/src/components/ui/label.tsx +24 -0
- package/frontend/src/components/ui/select.tsx +187 -0
- package/frontend/src/components/ui/sonner.tsx +40 -0
- package/frontend/src/components/ui/textarea.tsx +18 -0
- package/frontend/src/context/README.md +27 -0
- package/frontend/src/index.css +166 -0
- package/frontend/src/lib/notificationEvents.ts +10 -0
- package/frontend/src/lib/notificationStore.ts +13 -0
- package/frontend/src/lib/notifications.ts +13 -0
- package/frontend/src/lib/search.ts +28 -0
- package/frontend/src/lib/stacks.ts +189 -0
- package/frontend/src/lib/utils.ts +6 -0
- package/frontend/src/main.tsx +10 -0
- package/frontend/src/test/setup.ts +23 -0
- package/frontend/src/types.d.ts +9 -0
- package/frontend/tsconfig.app.json +28 -0
- package/frontend/tsconfig.json +41 -0
- package/frontend/tsconfig.node.json +26 -0
- package/frontend/vercel.json +4 -0
- package/frontend/vite.config.ts +6 -0
- package/frontend/vitest.config.ts +17 -0
- package/lcov.info +31338 -0
- package/mainnetcontracts.md +16 -0
- package/package.json +53 -0
- package/scripts/auto-activity.sh +9 -0
- package/scripts/cancel-pending.ts +67 -0
- package/scripts/check-balances.ts +23 -0
- package/scripts/distribute-evenly.ts +56 -0
- package/scripts/drain-accounts.ts +70 -0
- package/scripts/fund-accounts.ts +88 -0
- package/scripts/fund-active.ts +59 -0
- package/scripts/fund-unfunded.ts +88 -0
- package/scripts/generate-activity.ts +181 -0
- package/scripts/git-activity-generator.ts +154 -0
- package/scripts/mobile-server.ts +123 -0
- package/settings/Devnet.toml +155 -0
- package/settings/Mainnet.toml +7 -0
- package/settings/Testnet.toml +9 -0
- package/tests/CoreMarketPlace.fuzz.test.ts +435 -0
- package/tests/CoreMarketPlace.test.ts +564 -0
- package/tsconfig.json +26 -0
- package/vitest.config.js +49 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Strade Activity Generator
|
|
4
|
+
* Usage:
|
|
5
|
+
* 1. Set PRIVATE_KEY below (64-char hex)
|
|
6
|
+
* 2. Set DRY_RUN=false when ready
|
|
7
|
+
* 3. npx tsx scripts/generate-activity.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
broadcastTransaction,
|
|
12
|
+
makeContractCall,
|
|
13
|
+
noneCV,
|
|
14
|
+
principalCV,
|
|
15
|
+
stringUtf8CV,
|
|
16
|
+
uintCV,
|
|
17
|
+
AnchorMode,
|
|
18
|
+
} from '@stacks/transactions';
|
|
19
|
+
import { StacksMainnet } from '@stacks/network';
|
|
20
|
+
import { generateWallet, generateNewAccount } from '@stacks/wallet-sdk';
|
|
21
|
+
import { readFileSync } from 'fs';
|
|
22
|
+
import { resolve } from 'path';
|
|
23
|
+
import { execSync } from 'child_process';
|
|
24
|
+
|
|
25
|
+
const DRY_RUN = false; // set to false to broadcast
|
|
26
|
+
|
|
27
|
+
// curl-based fetch to bypass Node.js network restrictions
|
|
28
|
+
const curlFetch = async (url: string, opts: any = {}) => {
|
|
29
|
+
const method = opts.method || 'GET';
|
|
30
|
+
const headers = opts.headers ? Object.entries(opts.headers).map(([k,v]) => `-H '${k}: ${v}'`).join(' ') : '';
|
|
31
|
+
if (opts.body) {
|
|
32
|
+
const tmpFile = `/tmp/stx_req_${Date.now()}.bin`;
|
|
33
|
+
const { writeFileSync, unlinkSync } = await import('fs');
|
|
34
|
+
writeFileSync(tmpFile, opts.body);
|
|
35
|
+
const result = execSync(`curl -s --max-time 30 -X ${method} ${headers} --data-binary @${tmpFile} '${url}'`, { timeout: 35000 }).toString();
|
|
36
|
+
unlinkSync(tmpFile);
|
|
37
|
+
return { ok: true, json: async () => JSON.parse(result), text: async () => result };
|
|
38
|
+
}
|
|
39
|
+
const result = execSync(`curl -s -X ${method} ${headers} '${url}'`, { timeout: 15000 }).toString();
|
|
40
|
+
return { ok: true, json: async () => JSON.parse(result), text: async () => result };
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Read mnemonic from settings/Mainnet.toml
|
|
44
|
+
const toml = readFileSync(resolve('settings/Mainnet.toml'), 'utf8');
|
|
45
|
+
const mnemonicMatch = toml.match(/mnemonic\s*=\s*"([^"]+)"/);
|
|
46
|
+
if (!mnemonicMatch) { console.error('mnemonic not found in settings/Mainnet.toml'); process.exit(1); }
|
|
47
|
+
const MNEMONIC = mnemonicMatch[1];
|
|
48
|
+
|
|
49
|
+
// Derive 100 accounts from the same mnemonic (indices 0-99)
|
|
50
|
+
const NUM_ACCOUNTS = 50;
|
|
51
|
+
const baseWallet = await generateWallet({ secretKey: MNEMONIC, password: '' });
|
|
52
|
+
let wallet = baseWallet;
|
|
53
|
+
for (let i = 1; i < NUM_ACCOUNTS; i++) {
|
|
54
|
+
wallet = generateNewAccount(wallet);
|
|
55
|
+
}
|
|
56
|
+
const accounts = wallet.accounts.slice(0, NUM_ACCOUNTS).map(a => a.stxPrivateKey);
|
|
57
|
+
const CONTRACT_PRINCIPAL = 'SPB669EVRTKWYGY5GNQ7VEBZ7RF8A3K01EP6GN8N';
|
|
58
|
+
const DELAY_MS = 3000;
|
|
59
|
+
|
|
60
|
+
const network = new StacksMainnet({ fetchFn: curlFetch as any });
|
|
61
|
+
const rand = () => Math.random().toString(36).slice(2, 8);
|
|
62
|
+
|
|
63
|
+
async function getNonce(address: string): Promise<number> {
|
|
64
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
65
|
+
try {
|
|
66
|
+
const result = execSync(`curl -s --max-time 15 'https://api.hiro.so/extended/v1/address/${address}/nonces'`, { timeout: 20000 }).toString();
|
|
67
|
+
if (result.includes('Per-minute') || result.includes('rate limit')) throw new Error('rate limited');
|
|
68
|
+
const data = JSON.parse(result) as { possible_next_nonce: number };
|
|
69
|
+
return data.possible_next_nonce;
|
|
70
|
+
} catch (e: any) {
|
|
71
|
+
console.error(` getNonce attempt ${attempt}/3 failed: ${e.message}`);
|
|
72
|
+
if (attempt < 3) await new Promise(r => setTimeout(r, 10000)); // 10s backoff on rate limit
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error('Failed to get nonce after 3 attempts');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function sendTx(contractName: string, fn: string, args: any[], nonce: number, privateKey: string) {
|
|
79
|
+
const tx = await makeContractCall({
|
|
80
|
+
contractAddress: CONTRACT_PRINCIPAL,
|
|
81
|
+
contractName,
|
|
82
|
+
functionName: fn,
|
|
83
|
+
functionArgs: args,
|
|
84
|
+
senderKey: privateKey,
|
|
85
|
+
validateWithAbi: false,
|
|
86
|
+
network,
|
|
87
|
+
anchorMode: AnchorMode.Any,
|
|
88
|
+
nonce,
|
|
89
|
+
fee: 4_000, // 0.2 STX total per cycle across 50 accounts
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
console.log(`[${nonce}] ${contractName}.${fn}`);
|
|
93
|
+
|
|
94
|
+
if (DRY_RUN) {
|
|
95
|
+
console.log(' DRY-RUN: skipped');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const res = await broadcastTransaction(tx, network);
|
|
101
|
+
if ('txid' in res) {
|
|
102
|
+
console.log(` ✅ https://explorer.hiro.so/txid/${res.txid}`);
|
|
103
|
+
} else {
|
|
104
|
+
console.error(` ❌ ${JSON.stringify(res)}`);
|
|
105
|
+
}
|
|
106
|
+
} catch (e: any) {
|
|
107
|
+
console.error(` ❌ ${e.message}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await new Promise(r => setTimeout(r, DELAY_MS));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function main() {
|
|
114
|
+
const { getAddressFromPrivateKey } = await import('@stacks/transactions');
|
|
115
|
+
|
|
116
|
+
// Build per-account state sequentially to avoid rate limiting
|
|
117
|
+
const allStates = [];
|
|
118
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
119
|
+
const pk = accounts[i];
|
|
120
|
+
const { getAddressFromPrivateKey } = await import('@stacks/transactions');
|
|
121
|
+
const address = getAddressFromPrivateKey(pk, network.version);
|
|
122
|
+
const nonce = await getNonce(address);
|
|
123
|
+
let pending = 0, balance = 0;
|
|
124
|
+
try {
|
|
125
|
+
const mempool = JSON.parse(execSync(`curl -s --max-time 15 'https://api.hiro.so/extended/v1/address/${address}/mempool?limit=1'`, { timeout: 20000 }).toString());
|
|
126
|
+
pending = mempool.total ?? 0;
|
|
127
|
+
const balData = JSON.parse(execSync(`curl -s --max-time 15 'https://api.hiro.so/v2/accounts/${address}?proof=0'`, { timeout: 20000 }).toString());
|
|
128
|
+
balance = parseInt(balData.balance, 16);
|
|
129
|
+
} catch { pending = 0; }
|
|
130
|
+
console.log(`Account ${i}: ${address} (nonce: ${nonce}, pending: ${pending}, balance: ${(balance/1e6).toFixed(4)} STX)`);
|
|
131
|
+
allStates.push({ pk, address, nonce, pending, balance });
|
|
132
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const accountStates = allStates.filter(s => s.pending < 3 && s.balance > 1000);
|
|
136
|
+
if (accountStates.length === 0) { console.log('All accounts have too many pending txs. Try again later.'); return; }
|
|
137
|
+
console.log(`\nUsing ${accountStates.length}/${allStates.length} accounts\nDRY_RUN=${DRY_RUN}\n`);
|
|
138
|
+
|
|
139
|
+
// 1 tx per account per run — rotate through different contract calls
|
|
140
|
+
// Rotate through different contract calls - 1 per account per run
|
|
141
|
+
const calls = [
|
|
142
|
+
(s: any) => sendTx('UserProfile', 'update-profile', [
|
|
143
|
+
stringUtf8CV(`Bio ${rand()}`), stringUtf8CV(`${rand()}@test.com`)
|
|
144
|
+
], s.nonce++, s.pk),
|
|
145
|
+
|
|
146
|
+
(s: any) => sendTx('CoreMarketPlace', 'create-listing', [
|
|
147
|
+
stringUtf8CV(`Item ${rand()}`), stringUtf8CV(`Desc ${rand()}`), uintCV(500_000), uintCV(144)
|
|
148
|
+
], s.nonce++, s.pk),
|
|
149
|
+
|
|
150
|
+
(s: any) => sendTx('CoreMarketPlace', 'update-listing', [
|
|
151
|
+
uintCV(Math.floor(Math.random() * 100) + 1),
|
|
152
|
+
uintCV(750_000),
|
|
153
|
+
stringUtf8CV(`Updated desc ${rand()}`)
|
|
154
|
+
], s.nonce++, s.pk),
|
|
155
|
+
|
|
156
|
+
(s: any) => sendTx('UserProfile', 'rate-user', [
|
|
157
|
+
principalCV(accountStates[(accountStates.indexOf(s) + 1) % accountStates.length].address),
|
|
158
|
+
uintCV(Math.floor(Math.random() * 5) + 1)
|
|
159
|
+
], s.nonce++, s.pk),
|
|
160
|
+
|
|
161
|
+
(s: any) => sendTx('UserProfile', 'calculate-reputation', [
|
|
162
|
+
principalCV(s.address)
|
|
163
|
+
], s.nonce++, s.pk),
|
|
164
|
+
|
|
165
|
+
(s: any) => sendTx('CoreMarketPlace', 'create-listing', [
|
|
166
|
+
stringUtf8CV(`Product ${rand()}`), stringUtf8CV(`Details ${rand()}`), uintCV(1_000_000), uintCV(288)
|
|
167
|
+
], s.nonce++, s.pk),
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < accountStates.length; i++) {
|
|
171
|
+
const s = accountStates[i];
|
|
172
|
+
// Re-fetch nonce right before sending to avoid BadNonce
|
|
173
|
+
s.nonce = await getNonce(s.address);
|
|
174
|
+
await calls[i % calls.length](s);
|
|
175
|
+
await new Promise(r => setTimeout(r, 500));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
console.log('\nDone!');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Git Activity Generator for Strade
|
|
4
|
+
* Creates commits for GitHub activity. Supports resuming from existing commits.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx tsx scripts/git-activity-generator.ts --help
|
|
8
|
+
* npx tsx scripts/git-activity-generator.ts --dry-run
|
|
9
|
+
* npx tsx scripts/git-activity-generator.ts
|
|
10
|
+
* npx tsx scripts/git-activity-generator.ts --total 500
|
|
11
|
+
*
|
|
12
|
+
* WARNINGS:
|
|
13
|
+
* - Creates temp files in ./temp-commits/ and commits them.
|
|
14
|
+
* - Rate limited by GitHub (consider delays).
|
|
15
|
+
* - Check GitHub TOS; for testing only.
|
|
16
|
+
* - Runs `git push`, `gh pr create`. Ensure authenticated.
|
|
17
|
+
* - Cleanup: rm -rf temp-commits/ && git branch -D fake-activity-pr-*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { execSync } from 'child_process';
|
|
21
|
+
import { mkdirSync, writeFileSync, existsSync, rmSync, readdirSync } from 'fs';
|
|
22
|
+
import { dirname, join } from 'path';
|
|
23
|
+
import { fileURLToPath } from 'url';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const TEMP_DIR = join(__dirname, '../temp-commits');
|
|
27
|
+
const NUM_PRS = 5;
|
|
28
|
+
const TOTAL_COMMITS = process.argv.includes('--total') ? parseInt(process.argv[process.argv.indexOf('--total') + 1] || '100') : 100;
|
|
29
|
+
const COMMITS_PER_PR = Math.ceil(TOTAL_COMMITS / NUM_PRS);
|
|
30
|
+
const PR_START = 183;
|
|
31
|
+
const COUNTER_OFFSET = 34824;
|
|
32
|
+
const DRY_RUN = process.argv.includes('--dry-run');
|
|
33
|
+
const HELP = process.argv.includes('--help');
|
|
34
|
+
|
|
35
|
+
if (HELP) {
|
|
36
|
+
console.log(`Usage: npx tsx ${join('scripts/git-activity-generator.ts')} [--dry-run] [--help] [--total <num>]\n`);
|
|
37
|
+
console.log('Options:\n --dry-run Simulate without git/gh commands\n --help Show this help\n --total Number of commits to make (default: 500)\n');
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function run(cmd: string, options: { cwd?: string; dryRun?: boolean } = {}) {
|
|
42
|
+
const { cwd, dryRun } = options;
|
|
43
|
+
if (dryRun || DRY_RUN) {
|
|
44
|
+
console.log(`[DRY-RUN] cd ${cwd || process.cwd()} && ${cmd}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
execSync(cmd, { cwd, stdio: 'inherit' });
|
|
49
|
+
} catch (e: any) {
|
|
50
|
+
console.error(`Error: ${e.message}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function log(msg: string) {
|
|
56
|
+
console.log(`\n>>> ${msg}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function main() {
|
|
60
|
+
// Get existing file count to continue from where we left off
|
|
61
|
+
let startCommit = 1;
|
|
62
|
+
if (existsSync(TEMP_DIR)) {
|
|
63
|
+
const existingFiles = readdirSync(TEMP_DIR).filter(f => f.startsWith('counter') && f.endsWith('.txt'));
|
|
64
|
+
if (existingFiles.length > 0) {
|
|
65
|
+
const maxCounter = Math.max(...existingFiles.map(f => parseInt(f.replace('counter', '').replace('.txt', ''))));
|
|
66
|
+
startCommit = maxCounter - COUNTER_OFFSET + 1;
|
|
67
|
+
console.log(`\n>>> Continuing from existing commit ${startCommit} (found ${existingFiles.length} existing files, max counter: ${maxCounter})`);
|
|
68
|
+
} else {
|
|
69
|
+
// Cleanup previous if empty
|
|
70
|
+
rmSync(TEMP_DIR, { recursive: true });
|
|
71
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Create new temp files only for commits that don't exist yet
|
|
78
|
+
for (let i = startCommit; i <= TOTAL_COMMITS; i++) {
|
|
79
|
+
const file = join(TEMP_DIR, `counter${COUNTER_OFFSET + i}.txt`);
|
|
80
|
+
if (!existsSync(file)) {
|
|
81
|
+
writeFileSync(file, `Commit counter #${COUNTER_OFFSET + i} - ${Date.now()}\nMinor change for activity.\n`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
run('git add temp-commits/');
|
|
86
|
+
try { execSync('git commit -m "chore: add temp-commits dir for activity tracking"', { stdio: 'inherit' }); } catch {}
|
|
87
|
+
|
|
88
|
+
for (let pr = 1; pr <= NUM_PRS; pr++) {
|
|
89
|
+
log(`=== PR ${pr}/${NUM_PRS} (commits ${((pr-1)*COMMITS_PER_PR + 1)}-${pr*COMMITS_PER_PR}) ===`);
|
|
90
|
+
|
|
91
|
+
const branch = `fake-activity-pr-${PR_START + pr - 1}-${COUNTER_OFFSET}`;
|
|
92
|
+
|
|
93
|
+
// Create & switch branch
|
|
94
|
+
run(`git checkout -b ${branch}`, { dryRun: DRY_RUN });
|
|
95
|
+
|
|
96
|
+
// Make commits for this PR
|
|
97
|
+
for (let c = (pr-1)*COMMITS_PER_PR + 1; c <= Math.min(pr*COMMITS_PER_PR, TOTAL_COMMITS); c++) {
|
|
98
|
+
if (c > TOTAL_COMMITS) break;
|
|
99
|
+
const file = join(TEMP_DIR, `counter${COUNTER_OFFSET + c}.txt`);
|
|
100
|
+
const content = `Commit counter #${COUNTER_OFFSET + c} - ${Date.now() + c}\nUpdated at ${new Date().toISOString()}\nMinor change for activity.\n`;
|
|
101
|
+
writeFileSync(file, content);
|
|
102
|
+
|
|
103
|
+
run(`git add temp-commits/counter${COUNTER_OFFSET + c}.txt`, { cwd: process.cwd(), dryRun: DRY_RUN });
|
|
104
|
+
if ((c - 1) % 50 === 0 || c === Math.min(pr*COMMITS_PER_PR, TOTAL_COMMITS)) {
|
|
105
|
+
console.log(` Progress: PR${pr} commit ${c}/${Math.min(pr*COMMITS_PER_PR, TOTAL_COMMITS)} (${Math.min(TOTAL_COMMITS, pr*COMMITS_PER_PR)}/${TOTAL_COMMITS} total)`);
|
|
106
|
+
}
|
|
107
|
+
run(`git commit -m "chore: bump counter ${COUNTER_OFFSET + c} for activity tracking"`, { dryRun: DRY_RUN });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Push & create PR
|
|
111
|
+
run(`git push origin ${branch}`, { dryRun: DRY_RUN });
|
|
112
|
+
run(`gh pr create --title "chore: activity batch #${pr} - ${COMMITS_PER_PR} minor updates" --body "Batch of ${COMMITS_PER_PR} commits for activity tracking. Changes in temp-commits/. #automation" --base main`, { dryRun: DRY_RUN });
|
|
113
|
+
|
|
114
|
+
log(`PR ${pr} created! Merging to main...`);
|
|
115
|
+
|
|
116
|
+
// Switch back to main
|
|
117
|
+
run(`git checkout main`, { dryRun: DRY_RUN });
|
|
118
|
+
|
|
119
|
+
// Merge the PR and delete the remote branch
|
|
120
|
+
run(`gh pr merge ${branch} --merge --delete-branch --subject "chore: merge activity batch #${pr}"`, { dryRun: DRY_RUN });
|
|
121
|
+
|
|
122
|
+
// Delete local branch if it still exists
|
|
123
|
+
try { execSync(`git branch -D ${branch}`, { stdio: 'inherit' }); } catch {}
|
|
124
|
+
|
|
125
|
+
// Pull latest main
|
|
126
|
+
run(`git pull origin main`, { dryRun: DRY_RUN });
|
|
127
|
+
|
|
128
|
+
log(`PR ${pr} merged and deleted!`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Safety: stash if dirty, checkout main
|
|
132
|
+
try { execSync('git stash push -m "pre-activity auto-save"', { stdio: 'inherit' }); } catch {}
|
|
133
|
+
try { execSync('git checkout main', { stdio: 'inherit' }); } catch {
|
|
134
|
+
execSync('git checkout master', { stdio: 'inherit' });
|
|
135
|
+
}
|
|
136
|
+
try { execSync('git stash pop', { stdio: 'inherit' }); } catch {}
|
|
137
|
+
|
|
138
|
+
// Clean up temp-commits
|
|
139
|
+
if (existsSync(TEMP_DIR)) {
|
|
140
|
+
rmSync(TEMP_DIR, { recursive: true });
|
|
141
|
+
log('Temp files cleaned up');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Update counter file
|
|
145
|
+
writeFileSync('.activity_counter', TOTAL_COMMITS.toString());
|
|
146
|
+
console.log(`Updated .activity_counter to ${TOTAL_COMMITS}`);
|
|
147
|
+
|
|
148
|
+
log('✅ Complete! All PRs merged and deleted.');
|
|
149
|
+
if (!DRY_RUN) {
|
|
150
|
+
console.log(`\nSummary: ${TOTAL_COMMITS} commits across ${NUM_PRS} PRs, all merged to main and PRs deleted.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { join, dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { networkInterfaces } from "node:os";
|
|
7
|
+
|
|
8
|
+
const PORT = parseInt(process.env.PORT || "3456", 10);
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const REPO_DIR = join(__dirname, "..");
|
|
11
|
+
|
|
12
|
+
let childProcess: ReturnType<typeof spawn> | null = null;
|
|
13
|
+
|
|
14
|
+
const html = `<!DOCTYPE html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="UTF-8">
|
|
18
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
|
|
19
|
+
<title>Strade Auto-Activity</title>
|
|
20
|
+
<style>
|
|
21
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
22
|
+
body{font-family:system-ui,-apple-system,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100dvh;background:#0f172a;color:#e2e8f0}
|
|
23
|
+
.container{text-align:center;padding:2rem;width:100%;max-width:400px}
|
|
24
|
+
h1{font-size:1.5rem;margin-bottom:.5rem;color:#f8fafc}
|
|
25
|
+
p{font-size:.875rem;color:#94a3b8;margin-bottom:2rem}
|
|
26
|
+
.btn{display:block;width:100%;padding:1rem;font-size:1.25rem;font-weight:600;border:none;border-radius:12px;cursor:pointer;margin-bottom:1rem;transition:opacity .2s}
|
|
27
|
+
.btn:active{opacity:.7}
|
|
28
|
+
.btn:disabled{opacity:.4;cursor:not-allowed}
|
|
29
|
+
.btn-start{background:#22c55e;color:#052e16}
|
|
30
|
+
.btn-stop{background:#ef4444;color:#450a0a}
|
|
31
|
+
#status{margin-top:1rem;padding:.75rem 1rem;border-radius:8px;font-weight:600;font-size:1rem}
|
|
32
|
+
.running{background:#166534;color:#86efac}
|
|
33
|
+
.idle{background:#1e293b;color:#94a3b8}
|
|
34
|
+
.error{background:#7f1d1d;color:#fca5a5}
|
|
35
|
+
.log{background:#1e293b;border-radius:8px;padding:.75rem;margin-top:1rem;max-height:200px;overflow-y:auto;text-align:left;font-family:monospace;font-size:.75rem;line-height:1.4;color:#94a3b8}
|
|
36
|
+
</style>
|
|
37
|
+
</head>
|
|
38
|
+
<body>
|
|
39
|
+
<div class="container">
|
|
40
|
+
<h1>Strade Auto-Activity</h1>
|
|
41
|
+
<p>Start or stop the auto-activity loop</p>
|
|
42
|
+
<button class="btn btn-start" id="startBtn" onclick="run('/start')">▶ Start</button>
|
|
43
|
+
<button class="btn btn-stop" id="stopBtn" onclick="run('/stop')">■ Stop</button>
|
|
44
|
+
<div id="status" class="idle">Idle</div>
|
|
45
|
+
<div class="log" id="log">Ready.</div>
|
|
46
|
+
</div>
|
|
47
|
+
<script>
|
|
48
|
+
function log(msg){const el=document.getElementById('log');el.textContent+=msg;el.scrollTop=el.scrollHeight}
|
|
49
|
+
async function run(path){const btn=event.target;btn.disabled=true;try{const r=await fetch(path,{method:'POST'});log(await r.text()+'. ')}catch(e){log('Error: '+e.message+'. ')}finally{btn.disabled=false;poll()}}
|
|
50
|
+
async function poll(){try{const r=await fetch('/status');const d=await r.json();const el=document.getElementById('status');if(d.running){el.textContent='Running';el.className='running'}else if(d.error){el.textContent='Error';el.className='error';log('['+d.error+'] ')}else{el.textContent='Idle';el.className='idle'}}catch(e){const el=document.getElementById('status');el.textContent='Offline';el.className='error'}}
|
|
51
|
+
setInterval(poll,3000);poll()
|
|
52
|
+
</script>
|
|
53
|
+
</body>
|
|
54
|
+
</html>`;
|
|
55
|
+
|
|
56
|
+
const server = createServer((req, res) => {
|
|
57
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
58
|
+
|
|
59
|
+
if (req.method === "GET" && req.url === "/") {
|
|
60
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
61
|
+
res.end(html);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (req.method === "POST" && req.url === "/start") {
|
|
66
|
+
if (childProcess) {
|
|
67
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
68
|
+
res.end("Already running");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const scriptPath = join(REPO_DIR, "scripts", "auto-activity.sh");
|
|
72
|
+
childProcess = spawn("bash", [scriptPath], {
|
|
73
|
+
cwd: REPO_DIR,
|
|
74
|
+
stdio: "inherit",
|
|
75
|
+
});
|
|
76
|
+
childProcess.on("exit", (code) => {
|
|
77
|
+
childProcess = null;
|
|
78
|
+
});
|
|
79
|
+
childProcess.on("error", () => {
|
|
80
|
+
childProcess = null;
|
|
81
|
+
});
|
|
82
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
83
|
+
res.end("Started");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (req.method === "POST" && req.url === "/stop") {
|
|
88
|
+
if (childProcess) {
|
|
89
|
+
childProcess.kill("SIGTERM");
|
|
90
|
+
childProcess = null;
|
|
91
|
+
}
|
|
92
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
93
|
+
res.end("Stopped");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (req.method === "GET" && req.url === "/status") {
|
|
98
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
99
|
+
res.end(JSON.stringify({ running: childProcess !== null }));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
res.writeHead(404);
|
|
104
|
+
res.end("Not found");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
server.listen(PORT, "0.0.0.0", () => {
|
|
108
|
+
const ifaces = networkInterfaces();
|
|
109
|
+
const ips: string[] = [];
|
|
110
|
+
for (const name of Object.keys(ifaces)) {
|
|
111
|
+
for (const iface of ifaces[name] || []) {
|
|
112
|
+
if (iface.family === "IPv4" && !iface.internal) {
|
|
113
|
+
ips.push(iface.address);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
console.log(`Mobile control server running:`);
|
|
118
|
+
console.log(` Local: http://localhost:${PORT}`);
|
|
119
|
+
for (const ip of ips) {
|
|
120
|
+
console.log(` Network: http://${ip}:${PORT}`);
|
|
121
|
+
}
|
|
122
|
+
console.log(`Open one of the Network URLs on your phone's browser.`);
|
|
123
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
[network]
|
|
2
|
+
name = "devnet"
|
|
3
|
+
deployment_fee_rate = 10
|
|
4
|
+
|
|
5
|
+
[accounts.deployer]
|
|
6
|
+
mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
|
|
7
|
+
balance = 100_000_000_000_000
|
|
8
|
+
# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601
|
|
9
|
+
# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
|
|
10
|
+
# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH
|
|
11
|
+
|
|
12
|
+
[accounts.wallet_1]
|
|
13
|
+
mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild"
|
|
14
|
+
balance = 100_000_000_000_000
|
|
15
|
+
# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801
|
|
16
|
+
# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
|
|
17
|
+
# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC
|
|
18
|
+
|
|
19
|
+
[accounts.wallet_2]
|
|
20
|
+
mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital"
|
|
21
|
+
balance = 100_000_000_000_000
|
|
22
|
+
# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101
|
|
23
|
+
# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
|
|
24
|
+
# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG
|
|
25
|
+
|
|
26
|
+
[accounts.wallet_3]
|
|
27
|
+
mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high"
|
|
28
|
+
balance = 100_000_000_000_000
|
|
29
|
+
# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901
|
|
30
|
+
# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC
|
|
31
|
+
# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7
|
|
32
|
+
|
|
33
|
+
[accounts.wallet_4]
|
|
34
|
+
mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin"
|
|
35
|
+
balance = 100_000_000_000_000
|
|
36
|
+
# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701
|
|
37
|
+
# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND
|
|
38
|
+
# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8
|
|
39
|
+
|
|
40
|
+
[accounts.wallet_5]
|
|
41
|
+
mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase"
|
|
42
|
+
balance = 100_000_000_000_000
|
|
43
|
+
# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801
|
|
44
|
+
# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB
|
|
45
|
+
# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx
|
|
46
|
+
|
|
47
|
+
[accounts.wallet_6]
|
|
48
|
+
mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy"
|
|
49
|
+
balance = 100_000_000_000_000
|
|
50
|
+
# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01
|
|
51
|
+
# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0
|
|
52
|
+
# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt
|
|
53
|
+
|
|
54
|
+
[accounts.wallet_7]
|
|
55
|
+
mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow"
|
|
56
|
+
balance = 100_000_000_000_000
|
|
57
|
+
# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401
|
|
58
|
+
# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ
|
|
59
|
+
# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7
|
|
60
|
+
|
|
61
|
+
[accounts.wallet_8]
|
|
62
|
+
mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune"
|
|
63
|
+
balance = 100_000_000_000_000
|
|
64
|
+
# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01
|
|
65
|
+
# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP
|
|
66
|
+
# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw
|
|
67
|
+
|
|
68
|
+
[accounts.faucet]
|
|
69
|
+
mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform"
|
|
70
|
+
balance = 100_000_000_000_000
|
|
71
|
+
# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801
|
|
72
|
+
# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6
|
|
73
|
+
# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d
|
|
74
|
+
|
|
75
|
+
[devnet]
|
|
76
|
+
disable_stacks_explorer = false
|
|
77
|
+
disable_stacks_api = false
|
|
78
|
+
# disable_subnet_api = false
|
|
79
|
+
# disable_bitcoin_explorer = true
|
|
80
|
+
# working_dir = "tmp/devnet"
|
|
81
|
+
# stacks_node_events_observers = ["host.docker.internal:8002"]
|
|
82
|
+
# miner_mnemonic = "fragile loan twenty basic net assault jazz absorb diet talk art shock innocent float punch travel gadget embrace caught blossom hockey surround initial reduce"
|
|
83
|
+
# miner_derivation_path = "m/44'/5757'/0'/0/0"
|
|
84
|
+
# faucet_mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform"
|
|
85
|
+
# faucet_derivation_path = "m/44'/5757'/0'/0/0"
|
|
86
|
+
# orchestrator_port = 20445
|
|
87
|
+
# bitcoin_node_p2p_port = 18444
|
|
88
|
+
# bitcoin_node_rpc_port = 18443
|
|
89
|
+
# bitcoin_node_username = "devnet"
|
|
90
|
+
# bitcoin_node_password = "devnet"
|
|
91
|
+
# bitcoin_controller_block_time = 30_000
|
|
92
|
+
# stacks_node_rpc_port = 20443
|
|
93
|
+
# stacks_node_p2p_port = 20444
|
|
94
|
+
# stacks_api_port = 3999
|
|
95
|
+
# stacks_api_events_port = 3700
|
|
96
|
+
# bitcoin_explorer_port = 8001
|
|
97
|
+
# stacks_explorer_port = 8000
|
|
98
|
+
# postgres_port = 5432
|
|
99
|
+
# postgres_username = "postgres"
|
|
100
|
+
# postgres_password = "postgres"
|
|
101
|
+
# postgres_database = "postgres"
|
|
102
|
+
# bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:26.0"
|
|
103
|
+
# stacks_node_image_url = "quay.io/hirosystems/stacks-node:devnet-2.5"
|
|
104
|
+
# stacks_signer_image_url = "quay.io/hirosystems/stacks-signer:devnet-2.5"
|
|
105
|
+
# stacks_api_image_url = "hirosystems/stacks-blockchain-api:master"
|
|
106
|
+
# stacks_explorer_image_url = "hirosystems/explorer:latest"
|
|
107
|
+
# bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet"
|
|
108
|
+
# postgres_image_url = "postgres:alpine"
|
|
109
|
+
# enable_subnet_node = true
|
|
110
|
+
# subnet_node_image_url = "hirosystems/stacks-subnets:0.8.1"
|
|
111
|
+
# subnet_leader_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
|
|
112
|
+
# subnet_leader_derivation_path = "m/44'/5757'/0'/0/0"
|
|
113
|
+
# subnet_contract_id = "ST173JK7NZBA4BS05ZRATQH1K89YJMTGEH1Z5J52E.subnet-v3-0-1"
|
|
114
|
+
# subnet_node_rpc_port = 30443
|
|
115
|
+
# subnet_node_p2p_port = 30444
|
|
116
|
+
# subnet_events_ingestion_port = 30445
|
|
117
|
+
# subnet_node_events_observers = ["host.docker.internal:8002"]
|
|
118
|
+
# subnet_api_image_url = "hirosystems/stacks-blockchain-api:master"
|
|
119
|
+
# subnet_api_postgres_database = "subnet_api"
|
|
120
|
+
|
|
121
|
+
# epoch_2_0 = 100
|
|
122
|
+
# epoch_2_05 = 100
|
|
123
|
+
# epoch_2_1 = 101
|
|
124
|
+
# epoch_2_2 = 102
|
|
125
|
+
# epoch_2_3 = 103
|
|
126
|
+
# epoch_2_4 = 104
|
|
127
|
+
# epoch_2_5 = 108
|
|
128
|
+
# epoch_3_0 = 144
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Send some stacking orders
|
|
132
|
+
[[devnet.pox_stacking_orders]]
|
|
133
|
+
start_at_cycle = 1
|
|
134
|
+
duration = 10
|
|
135
|
+
auto_extend = true
|
|
136
|
+
wallet = "wallet_1"
|
|
137
|
+
slots = 2
|
|
138
|
+
btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC"
|
|
139
|
+
|
|
140
|
+
[[devnet.pox_stacking_orders]]
|
|
141
|
+
start_at_cycle = 1
|
|
142
|
+
duration = 10
|
|
143
|
+
auto_extend = true
|
|
144
|
+
wallet = "wallet_2"
|
|
145
|
+
slots = 2
|
|
146
|
+
btc_address = "muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG"
|
|
147
|
+
|
|
148
|
+
[[devnet.pox_stacking_orders]]
|
|
149
|
+
start_at_cycle = 1
|
|
150
|
+
duration = 10
|
|
151
|
+
auto_extend = true
|
|
152
|
+
wallet = "wallet_3"
|
|
153
|
+
slots = 2
|
|
154
|
+
btc_address = "mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7"
|
|
155
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[network]
|
|
2
|
+
name = "testnet"
|
|
3
|
+
stacks_node_rpc_address = "https://api.testnet.hiro.so"
|
|
4
|
+
deployment_fee_rate = 10
|
|
5
|
+
|
|
6
|
+
[accounts.deployer]
|
|
7
|
+
mnemonic = "desert replace point glare unit shift heart kid sample motor stock lizard public spirit crime attract quarter motor volume good mimic smart item prevent"
|
|
8
|
+
# After adding your mnemonic, the address will be derived automatically
|
|
9
|
+
# You can get testnet STX from: https://explorer.hiro.so/sandbox/faucet?chain=testnet
|