-
Notifications
You must be signed in to change notification settings - Fork 3
Module I #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Majormaxx
wants to merge
18
commits into
collabberry:main
Choose a base branch
from
Majormaxx:Module-I
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Module I #101
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
68970de
feat(safe): install safe-core-sdk and safe-ethers-lib
Majormaxx 8db5d4c
feat(org): add safe configuration fields to organization entity
Majormaxx cce211e
refactor(controllers): removed any casts and fixed type augmentation
Majormaxx 1f7d519
feat(org): updated RecognitionTokenMode enum to support MINT and TRANβ¦
Majormaxx 0a04315
feat(org): updated updateSafeConfiguration to use new enum
Majormaxx f6dd48f
feat(payout): added Payout, TxProposal, and PayoutRecipient entities
Majormaxx 82c075f
feat(payout): created PayoutService with initial structure
Majormaxx 563ccfc
feat(org): add MINTER_ROLE validation for recognition token
Majormaxx 969afd8
feat(org): add controller and router for configuration
Majormaxx dc9d5fc
fix(payout): removed previewPayout and fixed error handling in controβ¦
Majormaxx ad7b448
Added MINTER_ROLE enforcement for TeamPoints minting scenarios
Majormaxx 2f55055
Removed sensitive configuration
Majormaxx 8805767
refactor: fetch token decimals from contract instead of accepting as β¦
Majormaxx 936fb81
refactor: standardized router and controller patterns with dependencyβ¦
Majormaxx fba064b
chore: removed unnecessary gitignore entry
Majormaxx caa1bab
docs: clarified payout methods are deferred to Module-II
Majormaxx 285dbaa
refactor: converted payout router to class-based pattern for consistency
Majormaxx 2793f3d
fix: resolved TypeScript compilation errors
Majormaxx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,4 +65,4 @@ package-lock.json | |
| /lib/ | ||
| .env | ||
| dist | ||
| mysql-data | ||
| mysql-data | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| /** | ||
| * Script to check existing test data and create mock data if needed | ||
| */ | ||
| import { config as dotenv_config } from 'dotenv'; | ||
| import mysql from 'mysql2/promise'; | ||
|
|
||
| dotenv_config(); | ||
|
|
||
| interface TestDataResult { | ||
| hasData: boolean; | ||
| testOrgId?: string; | ||
| testRoundId?: string; | ||
| orgName?: string; | ||
| roundNumber?: number; | ||
| error?: string; | ||
| } | ||
|
|
||
| async function createConnection() { | ||
| return await mysql.createConnection({ | ||
| host: process.env.DB_HOST, | ||
| port: Number(process.env.DB_PORT) || 3306, | ||
| user: process.env.DB_UNAME, | ||
| password: process.env.DB_PASS, | ||
| database: process.env.DB_NAME | ||
| }); | ||
| } | ||
|
|
||
| async function checkTestData(): Promise<TestDataResult> { | ||
| let connection; | ||
| try { | ||
| connection = await createConnection(); | ||
| console.log('π Checking existing test data...\n'); | ||
|
|
||
| // Check organizations with Safe configuration | ||
| const [orgsWithSafe] = await connection.execute(` | ||
| SELECT id, name, safeAddress, safeChainId, stablecoinAddress, recognitionTokenAddress | ||
| FROM organizations | ||
| WHERE safeAddress IS NOT NULL | ||
| LIMIT 5 | ||
| `) as any[]; | ||
|
|
||
| console.log(`π Organizations with Safe config: ${orgsWithSafe.length}`); | ||
| if (orgsWithSafe.length > 0) { | ||
| console.log('Sample organizations:'); | ||
| orgsWithSafe.forEach((org: any) => { | ||
| console.log(` - ${org.name} (${org.id})`); | ||
| console.log(` Safe: ${org.safeAddress} (Chain: ${org.safeChainId})`); | ||
| console.log(` Stablecoin: ${org.stablecoinAddress || 'Not configured'}`); | ||
| }); | ||
| } | ||
|
|
||
| // Check completed rounds without payouts | ||
| const [incompleteRounds] = await connection.execute(` | ||
| SELECT r.id, r.roundNumber, r.isCompleted, r.txHash, o.name as orgName | ||
| FROM rounds r | ||
| JOIN organizations o ON r.organization_id = o.id | ||
| WHERE r.isCompleted = true AND r.txHash IS NULL | ||
| LIMIT 5 | ||
| `) as any[]; | ||
|
|
||
| console.log(`\nπ Completed rounds without payouts: ${incompleteRounds.length}`); | ||
| if (incompleteRounds.length > 0) { | ||
| console.log('Sample rounds:'); | ||
| incompleteRounds.forEach((round: any) => { | ||
| console.log(` - Round ${round.roundNumber} (${round.id}) - ${round.orgName}`); | ||
| }); | ||
| } | ||
|
|
||
| // Check compensation data | ||
| const [compensationData] = await connection.execute(` | ||
| SELECT COUNT(*) as count, r.id as roundId, r.roundNumber | ||
| FROM contributor_round_compensations crc | ||
| JOIN rounds r ON crc.round_id = r.id | ||
| WHERE r.isCompleted = true AND r.txHash IS NULL | ||
| GROUP BY r.id, r.roundNumber | ||
| LIMIT 5 | ||
| `) as any[]; | ||
|
|
||
| console.log(`\nπ° Rounds with compensation data: ${compensationData.length}`); | ||
| if (compensationData.length > 0) { | ||
| console.log('Sample compensation data:'); | ||
| compensationData.forEach((comp: any) => { | ||
| console.log(` - Round ${comp.roundNumber}: ${comp.count} contributors`); | ||
| }); | ||
| } | ||
|
|
||
| // Check users with wallet addresses | ||
| const [usersWithWallets] = await connection.execute(` | ||
| SELECT COUNT(*) as count FROM users WHERE walletAddress IS NOT NULL | ||
| `) as any[]; | ||
|
|
||
| console.log(`\nπ₯ Users with wallet addresses: ${usersWithWallets[0].count}`); | ||
|
|
||
| // Summary | ||
| console.log('\nπ Test Data Summary:'); | ||
| console.log(`β Organizations with Safe: ${orgsWithSafe.length > 0 ? 'YES' : 'NO'}`); | ||
| console.log(`β Rounds ready for payout: ${incompleteRounds.length > 0 ? 'YES' : 'NO'}`); | ||
| console.log(`β Compensation data: ${compensationData.length > 0 ? 'YES' : 'NO'}`); | ||
| console.log(`β Users with wallets: ${usersWithWallets[0].count > 0 ? 'YES' : 'NO'}`); | ||
|
|
||
| const hasTestData = orgsWithSafe.length > 0 && incompleteRounds.length > 0 && | ||
| compensationData.length > 0 && usersWithWallets[0].count > 0; | ||
|
|
||
| if (hasTestData) { | ||
| console.log('\nπ Sufficient test data exists! Ready to proceed with implementation.'); | ||
|
|
||
| return { | ||
| hasData: true, | ||
| testOrgId: orgsWithSafe[0].id, | ||
| testRoundId: incompleteRounds[0].id, | ||
| orgName: orgsWithSafe[0].name, | ||
| roundNumber: incompleteRounds[0].roundNumber | ||
| }; | ||
| } else { | ||
| console.log('\nβ οΈ Insufficient test data. Mock data creation needed.'); | ||
| return { hasData: false }; | ||
| } | ||
|
|
||
| } catch (error: any) { | ||
| console.error('β Error checking test data:', error.message); | ||
| return { hasData: false, error: error.message }; | ||
| } finally { | ||
| if (connection) { | ||
| await connection.end(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Run the check | ||
| checkTestData().then(result => { | ||
| if (result.hasData) { | ||
| console.log('\nπ Test Data Available:'); | ||
| console.log(` Organization ID: ${result.testOrgId}`); | ||
| console.log(` Round ID: ${result.testRoundId}`); | ||
| console.log(` Test URLs:`); | ||
| console.log(` GET /api/v1/payouts/rounds?orgId=${result.testOrgId}`); | ||
| console.log(` GET /api/v1/payouts/preview?roundId=${result.testRoundId}`); | ||
| } else { | ||
| console.log('\nπ Next Step: Create mock data'); | ||
| } | ||
| }).catch(console.error); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| /** | ||
| * Create mock test data for Module II implementation | ||
| * This will be removed once real data is available | ||
| */ | ||
|
|
||
| interface MockOrganization { | ||
| id: string; | ||
| name: string; | ||
| safeAddress: string; | ||
| safeChainId: number; | ||
| stablecoinAddress: string; | ||
| stablecoinDecimals: number; | ||
| recognitionTokenAddress: string; | ||
| recognitionTokenDecimals: number; | ||
| recognitionTokenMode: string; | ||
| } | ||
|
|
||
| interface MockRound { | ||
| id: string; | ||
| roundNumber: number; | ||
| isCompleted: boolean; | ||
| txHash: string | null; | ||
| organizationId: string; | ||
| startDate: string; | ||
| endDate: string; | ||
| compensationCycleStartDate: string; | ||
| compensationCycleEndDate: string; | ||
| } | ||
|
|
||
| interface MockContributor { | ||
| id: string; | ||
| walletAddress: string; | ||
| name: string; | ||
| fiat: number; | ||
| tp: number; | ||
| culturalScore: number; | ||
| workScore: number; | ||
| } | ||
|
|
||
| interface MockData { | ||
| organization: MockOrganization; | ||
| round: MockRound; | ||
| contributors: MockContributor[]; | ||
| } | ||
|
|
||
| const mockData: MockData = { | ||
| // Mock organization with Safe configuration (from Module A) | ||
| organization: { | ||
| id: 'mock-org-123', | ||
| name: 'Test Organization', | ||
| safeAddress: '0x1234567890123456789012345678901234567890', | ||
| safeChainId: 421614, // Arbitrum Sepolia | ||
| stablecoinAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd', | ||
| stablecoinDecimals: 6, | ||
| recognitionTokenAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedcba', | ||
| recognitionTokenDecimals: 18, | ||
| recognitionTokenMode: 'MINT' | ||
| }, | ||
|
|
||
| // Mock completed round without payout | ||
| round: { | ||
| id: 'mock-round-456', | ||
| roundNumber: 5, | ||
| isCompleted: true, | ||
| txHash: null, // No payout yet | ||
| organizationId: 'mock-org-123', | ||
| startDate: '2024-01-01', | ||
| endDate: '2024-01-31', | ||
| compensationCycleStartDate: '2024-01-01', | ||
| compensationCycleEndDate: '2024-01-31' | ||
| }, | ||
|
|
||
| // Mock contributors with compensation data | ||
| contributors: [ | ||
| { | ||
| id: 'user-1', | ||
| walletAddress: '0x1111111111111111111111111111111111111111', | ||
| name: 'Alice Developer', | ||
| fiat: 1500.00, | ||
| tp: 500, | ||
| culturalScore: 4.2, | ||
| workScore: 4.5 | ||
| }, | ||
| { | ||
| id: 'user-2', | ||
| walletAddress: '0x2222222222222222222222222222222222222222', | ||
| name: 'Bob Designer', | ||
| fiat: 1200.00, | ||
| tp: 800, | ||
| culturalScore: 4.0, | ||
| workScore: 4.1 | ||
| }, | ||
| { | ||
| id: 'user-3', | ||
| walletAddress: '0x3333333333333333333333333333333333333333', | ||
| name: 'Carol Manager', | ||
| fiat: 2000.00, | ||
| tp: 300, | ||
| culturalScore: 4.8, | ||
| workScore: 4.3 | ||
| } | ||
| ] | ||
| }; | ||
|
|
||
| console.log('π Mock Test Data Created for Module II Implementation\n'); | ||
|
|
||
| console.log('π’ Mock Organization:'); | ||
| console.log(` ID: ${mockData.organization.id}`); | ||
| console.log(` Name: ${mockData.organization.name}`); | ||
| console.log(` Safe: ${mockData.organization.safeAddress} (Chain: ${mockData.organization.safeChainId})`); | ||
| console.log(` Stablecoin: ${mockData.organization.stablecoinAddress} (${mockData.organization.stablecoinDecimals} decimals)`); | ||
| console.log(` Recognition Token: ${mockData.organization.recognitionTokenAddress} (${mockData.organization.recognitionTokenDecimals} decimals)`); | ||
|
|
||
| console.log('\nπ Mock Round:'); | ||
| console.log(` ID: ${mockData.round.id}`); | ||
| console.log(` Round Number: ${mockData.round.roundNumber}`); | ||
| console.log(` Status: Completed, No Payout Yet`); | ||
|
|
||
| console.log('\nπ₯ Mock Contributors:'); | ||
| mockData.contributors.forEach(contributor => { | ||
| console.log(` - ${contributor.name} (${contributor.id})`); | ||
| console.log(` Wallet: ${contributor.walletAddress}`); | ||
| console.log(` Fiat: $${contributor.fiat}, TP: ${contributor.tp}`); | ||
| console.log(` Scores: Cultural ${contributor.culturalScore}, Work ${contributor.workScore}`); | ||
| }); | ||
|
|
||
| const totalFiat = mockData.contributors.reduce((sum, c) => sum + c.fiat, 0); | ||
| const totalTP = mockData.contributors.reduce((sum, c) => sum + c.tp, 0); | ||
|
|
||
| console.log('\nπ° Totals:'); | ||
| console.log(` Total Fiat Payout: $${totalFiat}`); | ||
| console.log(` Total TP Payout: ${totalTP}`); | ||
| console.log(` Recipients: ${mockData.contributors.length}`); | ||
|
|
||
| console.log('\nπ§ͺ Test URLs (once API is implemented):'); | ||
| console.log(` GET /api/v1/payouts/rounds?orgId=${mockData.organization.id}`); | ||
| console.log(` GET /api/v1/payouts/preview?roundId=${mockData.round.id}`); | ||
| console.log(` POST /api/v1/payouts/propose { "roundId": "${mockData.round.id}", "tokenType": "STABLECOIN" }`); | ||
| console.log(` POST /api/v1/payouts/propose { "roundId": "${mockData.round.id}", "tokenType": "RECOGNITION" }`); | ||
| console.log(` GET /api/v1/payouts/status?roundId=${mockData.round.id}`); | ||
|
|
||
| console.log('\nβ οΈ Note: This mock data will be replaced with real database data once available.'); | ||
| console.log('ποΈ Mock data removal: After successful testing with real data'); | ||
|
|
||
| // Export for use in tests | ||
| export default mockData; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.