diff --git a/contracts/__test__/contracts.test.ts b/contracts/__test__/contracts.test.ts index 4ec08b24..bd7ee16f 100644 --- a/contracts/__test__/contracts.test.ts +++ b/contracts/__test__/contracts.test.ts @@ -152,9 +152,9 @@ describe('reti', () => { const origMbr = (await fixture.algorand.account.getInformation(validatorMasterClient.appAddress)).minBalance const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) let expectedID = 1 let validatorId = await addValidator( @@ -205,9 +205,9 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 50000, // 5% @@ -754,9 +754,9 @@ describe('reti', () => { suppressLog: true, }) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, percentToValidator: 50000, @@ -905,8 +905,8 @@ describe('reti', () => { // Figure out the timestamp of prior block and use that as the 'current time' for purposes // of matching the epoch payout calculations in the contract const curStatus = await context.algod.status().do() - const lastBlock = curStatus['last-round'] - const thisEpochBegin = lastBlock - (lastBlock % epochRoundLength) + const lastBlock = curStatus.lastRound + const thisEpochBegin = lastBlock - (lastBlock % BigInt(epochRoundLength)) let numStakers = 0 for (let i = 0; i < stakersPriorToReward.length; i += 1) { if (stakersPriorToReward[i].account === ALGORAND_ZERO_ADDRESS_STRING) { @@ -1037,12 +1037,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), epochRoundLength, }) validatorId = await addValidator( @@ -1233,8 +1233,11 @@ describe('reti', () => { }) const params = await fixture.context.algod.getTransactionParams().do() // add blocks to get to exact start of new epoch - if (params.firstRound % epochRoundLength !== 0) { - await incrementRoundNumberBy(fixture.context, epochRoundLength - (params.firstRound % epochRoundLength)) + if (params.firstValid % BigInt(epochRoundLength) !== 0n) { + await incrementRoundNumberBy( + fixture.context, + epochRoundLength - (Number(params.firstValid) % epochRoundLength), + ) } // this payout should work... await epochBalanceUpdate(firstPoolClient) @@ -1281,7 +1284,10 @@ describe('reti', () => { const params = await fixture.context.algod.getTransactionParams().do() // add blocks to get to block prior to start of new epoch - await incrementRoundNumberBy(fixture.context, epochRoundLength - 1 - (params.firstRound % epochRoundLength)) + await incrementRoundNumberBy( + fixture.context, + epochRoundLength - 1 - (Number(params.firstValid) % epochRoundLength), + ) // double-check no one should be left and be 0 balance const checkPoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey) @@ -1394,12 +1400,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( fixture.context, @@ -1569,12 +1575,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( fixture.context, @@ -1762,12 +1768,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), rewardTokenId, rewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch epochRoundLength, @@ -1966,7 +1972,10 @@ describe('reti', () => { const params = await fixture.context.algod.getTransactionParams().do() // add blocks to get to block prior to start of new epoch - await incrementRoundNumberBy(fixture.context, epochRoundLength - 1 - (params.firstRound % epochRoundLength)) + await incrementRoundNumberBy( + fixture.context, + epochRoundLength - 1 - (Number(params.firstValid) % epochRoundLength), + ) // double-check no one should be left and be 0 balance const checkPoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey) @@ -2072,7 +2081,7 @@ describe('reti', () => { // should fail - not owner of validator await expect( validatorMasterClient.send.emptyTokenRewards({ - args: { validatorId, receiver: tokenCreatorAccount.addr }, + args: { validatorId, receiver: tokenCreatorAccount.addr.toString() }, staticFee: AlgoAmount.MicroAlgos(3000), populateAppCallResources: true, }), @@ -2085,7 +2094,7 @@ describe('reti', () => { const sentAmount = ( await validatorClient.send.emptyTokenRewards({ - args: { validatorId, receiver: tokenCreatorAccount.addr }, + args: { validatorId, receiver: tokenCreatorAccount.addr.toString() }, staticFee: AlgoAmount.MicroAlgos(3000), populateAppCallResources: true, }) @@ -2120,12 +2129,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), epochRoundLength, }) validatorId = await addValidator( @@ -2195,7 +2204,7 @@ describe('reti', () => { 0n, ) const params = await fixture.context.algod.status().do() - let lastBlock = params['last-round'] + let lastBlock = params.lastRound // should match info from first staking pool expect(stakedPoolKey.id).toEqual(firstPoolKey.id) @@ -2224,7 +2233,7 @@ describe('reti', () => { const stakeAmount2 = AlgoAmount.Algos(1000) await addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount2, 0n) roundsPerDay = (await firstPoolClient.state.global.roundsPerDay())! - lastBlock = (await fixture.context.algod.status().do())['last-round'] + lastBlock = (await fixture.context.algod.status().do()).lastRound roundsRemaining = binRoundStart + roundsPerDay - BigInt(lastBlock) poolGS = await firstPoolClient.state.global.getAll() const secondStakeAccum = poolGS.stakeAccumulator! @@ -2233,7 +2242,7 @@ describe('reti', () => { // remove bits of stake await removeStake(firstPoolClient, stakerAccounts[0], AlgoAmount.Algos(50)) roundsPerDay = (await firstPoolClient.state.global.roundsPerDay())! - lastBlock = (await fixture.context.algod.status().do())['last-round'] + lastBlock = (await fixture.context.algod.status().do()).lastRound roundsRemaining = binRoundStart + roundsPerDay - BigInt(lastBlock) poolGS = await firstPoolClient.state.global.getAll() const newStakeAccum = poolGS.stakeAccumulator! @@ -2242,7 +2251,7 @@ describe('reti', () => { // remove bits of stake await removeStake(firstPoolClient, stakerAccounts[0], AlgoAmount.Algos(60)) roundsPerDay = (await firstPoolClient.state.global.roundsPerDay())! - lastBlock = (await fixture.context.algod.status().do())['last-round'] + lastBlock = (await fixture.context.algod.status().do()).lastRound roundsRemaining = binRoundStart + roundsPerDay - BigInt(lastBlock) poolGS = await firstPoolClient.state.global.getAll() const thirdStakeAccum = poolGS.stakeAccumulator! @@ -2283,12 +2292,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 5 * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), rewardTokenId, rewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch }) @@ -2454,12 +2463,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: AlgoAmount.Algos(5_000).microAlgos, // just do 5k per pool percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), rewardTokenId, rewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch }) @@ -2711,15 +2720,15 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 5 * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), // stakers must possess any token created by tokenCreatorAccount entryGatingType: GATING_TYPE_ASSETS_CREATED_BY, - entryGatingAddress: tokenCreatorAccount.addr, + entryGatingAddress: tokenCreatorAccount.addr.toString(), gatingAssetMinBalance: 2n, // require 2 so we can see if only having 1 fails us }) validatorId = await addValidator( @@ -2907,12 +2916,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 5 * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), // stakers must possess ONLY the second gating token - explicit id ! entryGatingType: GATING_TYPE_ASSET_ID, entryGatingAssets: [gatingToken2Id, 0n, 0n, 0n], @@ -3085,12 +3094,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 5 * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), // stakers must possess ONLY the second gating token - explicit id ! entryGatingType: GATING_TYPE_ASSET_ID, entryGatingAssets: [gatingTokens[0], gatingTokens[1], gatingTokens[2], gatingTokens[3]], @@ -3262,12 +3271,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: 0n, percentToValidator: 5 * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( fixture.context, @@ -3449,9 +3458,9 @@ describe('reti', () => { suppressLog: true, }) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 50000, // 5% @@ -3565,9 +3574,9 @@ describe('reti', () => { suppressLog: true, }) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1).microAlgos, maxAlgoPerPool: MaxAlgoPerPool, // this comes into play in later tests !! percentToValidator: 50000, // 5% @@ -3702,12 +3711,12 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, maxAlgoPerPool: AlgoAmount.Algos(1000 * NumStakers).microAlgos, // this comes into play in later tests !! percentToValidator: PctToValidator * 10000, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( fixture.context, @@ -3909,10 +3918,10 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), rewardTokenId, rewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch epochRoundLength, @@ -3983,7 +3992,10 @@ describe('reti', () => { const params = await fixture.context.algod.getTransactionParams().do() // increment rounds to get to the start of new epoch. This means that staking will occur 1 round after. - await incrementRoundNumberBy(fixture.context, epochRoundLength - (params.firstRound % epochRoundLength)) + await incrementRoundNumberBy( + fixture.context, + epochRoundLength - (Number(params.firstValid) % epochRoundLength), + ) // Stake 1000 Algos + MBR const stakeAmount = AlgoAmount.MicroAlgos( @@ -4041,7 +4053,7 @@ describe('reti', () => { let validatorId: number let validatorOwnerAccount: Account let stakerAccount: Account - let newSunset: number + let newSunset: bigint beforeAll(async () => { // Fund a 'validator account' that will be the validator owner. @@ -4052,10 +4064,10 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( @@ -4077,7 +4089,7 @@ describe('reti', () => { ) // set sunset 1 round after now - newSunset = (await fixture.context.algod.getTransactionParams().do()).firstRound + 1 + newSunset = (await fixture.context.algod.getTransactionParams().do()).firstValid + 1n await validatorMasterClient .newGroup() @@ -4108,7 +4120,7 @@ describe('reti', () => { await incrementRoundNumberBy(fixture.context, 3) // Let's check that we are past the new sunset value - expect(newSunset).toBeLessThan((await fixture.context.algod.getTransactionParams().do()).firstRound) + expect(newSunset).toBeLessThan((await fixture.context.algod.getTransactionParams().do()).firstValid) const stakeAmount = AlgoAmount.MicroAlgos( AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(mbrs.addStakerMbr).microAlgos, @@ -4148,11 +4160,11 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) validatorConfig = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), minEntryStake: AlgoAmount.Algos(1000).microAlgos, percentToValidator: PctToValidator * 10000, // 5 % - validatorCommissionAddress: validatorOwnerAccount.addr, + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), epochRoundLength, }) validatorId = await addValidator( @@ -4326,9 +4338,9 @@ describe('reti', () => { consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`) const config = createValidatorConfig({ - owner: validatorOwnerAccount.addr, - manager: validatorOwnerAccount.addr, - validatorCommissionAddress: validatorOwnerAccount.addr, + owner: validatorOwnerAccount.addr.toString(), + manager: validatorOwnerAccount.addr.toString(), + validatorCommissionAddress: validatorOwnerAccount.addr.toString(), }) validatorId = await addValidator( @@ -4369,7 +4381,7 @@ describe('reti', () => { args: { validatorId, entryGatingType: badGatingType, - entryGatingAddress: validatorOwnerAccount.addr, + entryGatingAddress: validatorOwnerAccount.addr.toString(), entryGatingAssets: [0, 0, 0, 0], gatingAssetMinBalance: 0, rewardPerPayout: 0, diff --git a/contracts/bootstrap/index.ts b/contracts/bootstrap/index.ts index eccea031..b056702f 100644 --- a/contracts/bootstrap/index.ts +++ b/contracts/bootstrap/index.ts @@ -200,13 +200,13 @@ async function main() { { initialFunds: AlgoAmount.Algos(100_000_000), suppressLog: true }, algorand, ) - console.log(`Created test account 1:${staker1.addr}`) - console.log(`Created test account 2:${staker2.addr}`) + console.log(`Created test account 1: ${staker1.addr.toString()}`) + console.log(`Created test account 2: ${staker2.addr.toString()}`) // Write the mnemonic to a .sandbox file in ../../nodemgr directory fs.writeFileSync( '../../nodemgr/.env.sandbox', - `ALGO_MNEMONIC_${creatorAcct.addr.substring(0, 4)}=${secretKeyToMnemonic(creatorAcct.sk)}\nRETI_APPID=${validatorApp.appClient.appId}\nALGO_MNEMONIC_${staker1.addr.substring(0, 4)}=${secretKeyToMnemonic(staker1.sk)}\nALGO_MNEMONIC_${staker2.addr.substring(0, 4)}=${secretKeyToMnemonic(staker2.sk)}\n`, + `ALGO_MNEMONIC_${creatorAcct.addr.toString().substring(0, 4)}=${secretKeyToMnemonic(creatorAcct.sk)}\nRETI_APPID=${validatorApp.appClient.appId}\nALGO_MNEMONIC_${staker1.addr.toString().substring(0, 4)}=${secretKeyToMnemonic(staker1.sk)}\nALGO_MNEMONIC_${staker2.addr.toString().substring(0, 4)}=${secretKeyToMnemonic(staker2.sk)}\n`, ) console.log('Modified .env.sandbox in nodemgr directory with these values for testing') diff --git a/contracts/bootstrap/package.json b/contracts/bootstrap/package.json index 6a2b1134..c13ed6f1 100644 --- a/contracts/bootstrap/package.json +++ b/contracts/bootstrap/package.json @@ -11,8 +11,8 @@ }, "license": "MIT", "dependencies": { - "@algorandfoundation/algokit-utils": "7.0.0", - "algosdk": "2.9.0", + "@algorandfoundation/algokit-utils": "8.0.0", + "algosdk": "3.0.0", "prompts": "^2.4.2", "yargs": "^17.7.2" }, diff --git a/contracts/helpers/helpers.ts b/contracts/helpers/helpers.ts index 78512169..10f62fac 100644 --- a/contracts/helpers/helpers.ts +++ b/contracts/helpers/helpers.ts @@ -178,7 +178,9 @@ export async function getStakedPoolsForAccount( validatorClient: ValidatorRegistryClient, stakerAccount: Account, ): Promise { - const results = await validatorClient.send.getStakedPoolsForAccount({ args: { staker: stakerAccount.addr } }) + const results = await validatorClient.send.getStakedPoolsForAccount({ + args: { staker: stakerAccount.addr.toString() }, + }) const retPoolKeys: ValidatorPoolKey[] = [] results.return!.forEach((poolKey) => { @@ -188,7 +190,7 @@ export async function getStakedPoolsForAccount( } export async function getStakerInfo(stakeClient: StakingPoolClient, staker: Account) { - return (await stakeClient.send.getStakerInfo({ args: { staker: staker.addr } })).return! + return (await stakeClient.send.getStakerInfo({ args: { staker: staker.addr.toString() } })).return! } export async function getTokenPayoutRatio(validatorClient: ValidatorRegistryClient, validatorId: number) { @@ -208,7 +210,11 @@ export async function addStake( .newGroup() .gas() .findPoolForStaker({ - args: { validatorId: vldtrId, staker: staker.addr, amountToStake: algoAmount.microAlgos }, + args: { + validatorId: vldtrId, + staker: staker.addr.toString(), + amountToStake: algoAmount.microAlgos, + }, staticFee: AlgoAmount.MicroAlgos(2000), }) .simulate({ allowUnnamedResources: true }) @@ -300,7 +306,7 @@ export async function removeStake( .gas({ args: [], note: '1', staticFee: AlgoAmount.MicroAlgos(0) }) .gas({ args: [], note: '2', staticFee: AlgoAmount.MicroAlgos(0) }) .removeStake({ - args: { staker: staker.addr, amountToUnstake: unstakeAmount.microAlgos }, + args: { staker: staker.addr.toString(), amountToUnstake: unstakeAmount.microAlgos }, staticFee: AlgoAmount.MicroAlgos(240000), sender: (altSender || staker).addr, }) @@ -317,7 +323,7 @@ export async function removeStake( .gas({ args: [], note: '1', staticFee: AlgoAmount.MicroAlgos(0) }) .gas({ args: [], note: '2', staticFee: AlgoAmount.MicroAlgos(0) }) .removeStake({ - args: { staker: staker.addr, amountToUnstake: unstakeAmount.microAlgos }, + args: { staker: staker.addr.toString(), amountToUnstake: unstakeAmount.microAlgos }, staticFee: AlgoAmount.MicroAlgos(itxnfees.microAlgo), sender: (altSender || staker).addr, }) @@ -444,7 +450,7 @@ export async function incrementRoundNumberBy(context: AlgorandTestAutomationCont } // Send `rounds` number of 'dummy' pay self 0 transactions let params = await context.algod.getTransactionParams().do() - console.log('block before incrementRoundNumberBy:', params.firstRound) + console.log('block before incrementRoundNumberBy:', params.firstValid) for (let i = 0; i < rounds; i += 1) { await context.algorand.send.payment({ sender: context.testAccount.addr, @@ -455,5 +461,5 @@ export async function incrementRoundNumberBy(context: AlgorandTestAutomationCont } params = await context.algod.getTransactionParams().do() - console.log('block AFTER incrementRoundNumberBy:', params.firstRound) + console.log('block AFTER incrementRoundNumberBy:', params.firstValid) } diff --git a/contracts/package.json b/contracts/package.json index bc44760e..34552afa 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -14,11 +14,12 @@ "lint": "eslint . --ext ts --max-warnings 0", "lint:fix": "eslint . --ext ts --max-warnings 0 --fix", "prettier": "pnpx prettier --check .", - "prettier:fix": "pnpx prettier --write ." + "prettier:fix": "pnpx prettier --write .", + "typecheck": "tsc --noEmit" }, "dependencies": { - "@algorandfoundation/algokit-utils": "7.0.0", - "algosdk": "2.9.0" + "@algorandfoundation/algokit-utils": "8.0.0", + "algosdk": "3.0.0" }, "devDependencies": { "@algorandfoundation/algokit-client-generator": "4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7869c176..1cf004db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,15 +11,15 @@ importers: contracts: dependencies: '@algorandfoundation/algokit-utils': - specifier: 7.0.0 - version: 7.0.0(algosdk@2.9.0) + specifier: 8.0.0 + version: 8.0.0(algosdk@3.0.0) algosdk: - specifier: 2.9.0 - version: 2.9.0 + specifier: 3.0.0 + version: 3.0.0 devDependencies: '@algorandfoundation/algokit-client-generator': specifier: 4.0.0 - version: 4.0.0(@algorandfoundation/algokit-utils@7.0.0(algosdk@2.9.0))(algosdk@2.9.0) + version: 4.0.0(@algorandfoundation/algokit-utils@8.0.0(algosdk@3.0.0))(algosdk@3.0.0) '@algorandfoundation/tealscript': specifier: 0.106.0 version: 0.106.0 @@ -63,11 +63,11 @@ importers: contracts/bootstrap: dependencies: '@algorandfoundation/algokit-utils': - specifier: 7.0.0 - version: 7.0.0(algosdk@2.9.0) + specifier: 8.0.0 + version: 8.0.0(algosdk@3.0.0) algosdk: - specifier: 2.9.0 - version: 2.9.0 + specifier: 3.0.0 + version: 3.0.0 prompts: specifier: ^2.4.2 version: 2.4.2 @@ -94,17 +94,17 @@ importers: ui: dependencies: '@algorandfoundation/algokit-utils': - specifier: 7.0.0 - version: 7.0.0(algosdk@2.9.0) + specifier: 8.0.0 + version: 8.0.0(algosdk@3.0.0) '@blockshake/defly-connect': specifier: 1.1.6 - version: 1.1.6(algosdk@2.9.0) + version: 1.1.6(algosdk@3.0.0) '@hookform/resolvers': specifier: 3.9.0 version: 3.9.0(react-hook-form@7.53.0(react@18.3.1)) '@perawallet/connect': specifier: 1.3.5 - version: 1.3.5(algosdk@2.9.0) + version: 1.3.5(algosdk@3.0.0) '@radix-ui/react-avatar': specifier: 1.1.1 version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -172,14 +172,14 @@ importers: specifier: 3.18.3 version: 3.18.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))) '@txnlab/use-wallet-react': - specifier: 3.7.2 - version: 3.7.2(@blockshake/defly-connect@1.1.6(algosdk@2.9.0))(@perawallet/connect@1.3.5(algosdk@2.9.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@2.9.0)(lute-connect@1.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 4.0.0-beta.2 + version: 4.0.0-beta.2(@blockshake/defly-connect@1.1.6(algosdk@3.0.0))(@perawallet/connect@1.3.5(algosdk@3.0.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@3.0.0)(lute-connect@1.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@walletconnect/modal-sign-html': specifier: 2.7.0 version: 2.7.0(@types/react@18.3.11)(react@18.3.1) algosdk: - specifier: 2.9.0 - version: 2.9.0 + specifier: 3.0.0 + version: 3.0.0 axios: specifier: 1.7.7 version: 1.7.7 @@ -354,11 +354,11 @@ packages: '@algorandfoundation/algokit-utils': ^7.0.0 || ^8.0.0 algosdk: ^2.9.0 || ^3.0.0 - '@algorandfoundation/algokit-utils@7.0.0': - resolution: {integrity: sha512-L+8ykFgQVEs802yozldp+QFwW5z0sFXxSeHFYztZIVAACwVK4C/z5DnIF/AA+g8L98sv3VPkOvjjvPSya5szZQ==} + '@algorandfoundation/algokit-utils@8.0.0': + resolution: {integrity: sha512-SIrQpWFJaAbqwN6dMvvEPYxggUjtq2OCpfRLvmBWksJ/Psi2CLdsS3R84vmilszRaLX5C1aRTv0c1rBxYEe3+w==} engines: {node: '>=20.0'} peerDependencies: - algosdk: '>=2.9.0 <3.0' + algosdk: ^3.0.0 '@algorandfoundation/tealscript@0.106.0': resolution: {integrity: sha512-CN3TmBqIrOW5rsnB3NvaNRe3XAGMOItQkvZBobFrxn9M8HxTona7ZrkbJX9IpgzNE7Byond8fSn8gqXex0Tuew==} @@ -1838,18 +1838,18 @@ packages: '@tsconfig/node18@18.2.4': resolution: {integrity: sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==} - '@txnlab/use-wallet-react@3.7.2': - resolution: {integrity: sha512-ofVE3XHNkkQ8wAgL1Pf4CcL/2DizlruPx64mjjjmgbvjQ90ldcCNuvxK0k/Tc/BobJcmJqTugM3T9t7JxEIT7w==} + '@txnlab/use-wallet-react@4.0.0-beta.2': + resolution: {integrity: sha512-XG2paXNehv2CJyR5Q4I08JEeToz213SHpLiQJWUAC0P2/oj9NfY6bwoELaJsSe9x6h5OYyIsUFL5GNIBTZVz3g==} peerDependencies: '@blockshake/defly-connect': ^1.1.6 - '@magic-ext/algorand': ^23.6.0 - '@perawallet/connect': ^1.3.4 - '@perawallet/connect-beta': ^2.0.14 - '@walletconnect/modal': ^2.6.2 - '@walletconnect/sign-client': ^2.16.1 - algosdk: ^2.7.0 + '@magic-ext/algorand': ^23.13.0 + '@perawallet/connect': ^1.3.5 + '@perawallet/connect-beta': ^2.0.21 + '@walletconnect/modal': ^2.7.0 + '@walletconnect/sign-client': ^2.17.1 + algosdk: ^3.0.0 lute-connect: ^1.4.1 - magic-sdk: ^28.6.0 + magic-sdk: ^28.13.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: @@ -1870,20 +1870,23 @@ packages: magic-sdk: optional: true - '@txnlab/use-wallet@3.7.2': - resolution: {integrity: sha512-UfvgCeZrJ4sItU/WrcDtdFf+3V9c9Gi7umthlQRHJ3iNCWFZs136GGSCDhy/tb6pUgpRPP2Lz/8bUuzAcx+Cgg==} + '@txnlab/use-wallet@4.0.0-beta.2': + resolution: {integrity: sha512-K6tYxouxibT3lo2SWbC1T1SFCcu6sI6vgbxUP1wuuAvTv9Wuae5a+WH87MSvkBqRBzK6YYD6n4hgUmZPznyrIw==} peerDependencies: - '@agoralabs-sh/avm-web-provider': ^1.6.2 + '@agoralabs-sh/avm-web-provider': ^1.7.0 + '@algorandfoundation/liquid-auth-use-wallet-client': 1.1.0 '@blockshake/defly-connect': ^1.1.6 - '@perawallet/connect': ^1.3.4 - '@perawallet/connect-beta': ^2.0.14 - '@walletconnect/modal': ^2.6.2 - '@walletconnect/sign-client': ^2.16.1 - algosdk: ^2.7.0 + '@perawallet/connect': ^1.3.5 + '@perawallet/connect-beta': ^2.0.21 + '@walletconnect/modal': ^2.7.0 + '@walletconnect/sign-client': ^2.17.1 + algosdk: ^3.0.0 lute-connect: ^1.4.1 peerDependenciesMeta: '@agoralabs-sh/avm-web-provider': optional: true + '@algorandfoundation/liquid-auth-use-wallet-client': + optional: true '@blockshake/defly-connect': optional: true '@perawallet/connect': @@ -2248,8 +2251,12 @@ packages: resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} engines: {node: '>= 10'} - algosdk@2.9.0: - resolution: {integrity: sha512-o0n0nLMbTX6SFQdMUk2/2sy50jmEmZk5OTPYSh2aAeP8DUPxrhjMPfwGsYNvaO+qk75MixC2eWpfA9vygCQ/Mg==} + algorand-msgpack@1.1.0: + resolution: {integrity: sha512-08k7pBQnkaUB5p+jL7f1TRaUIlTSDE0cesFu1mD7llLao+1cAhtvvZmGE3OnisTd0xOn118QMw74SRqddqaYvw==} + engines: {node: '>= 14'} + + algosdk@3.0.0: + resolution: {integrity: sha512-PIKZ/YvbBpCudduug4KSH1CY/pTotI7/ccbUIbXKtcI9Onevl+57E+K5X4ow4gsCdysZ8zVvSLdxuCcXvsmPOw==} engines: {node: '>=18.0.0'} ansi-escapes@4.3.2: @@ -5132,18 +5139,18 @@ snapshots: '@adobe/css-tools@4.4.0': {} - '@algorandfoundation/algokit-client-generator@4.0.0(@algorandfoundation/algokit-utils@7.0.0(algosdk@2.9.0))(algosdk@2.9.0)': + '@algorandfoundation/algokit-client-generator@4.0.0(@algorandfoundation/algokit-utils@8.0.0(algosdk@3.0.0))(algosdk@3.0.0)': dependencies: - '@algorandfoundation/algokit-utils': 7.0.0(algosdk@2.9.0) - algosdk: 2.9.0 + '@algorandfoundation/algokit-utils': 8.0.0(algosdk@3.0.0) + algosdk: 3.0.0 chalk: 4.1.2 change-case: 5.4.4 commander: 11.1.0 jsonschema: 1.4.1 - '@algorandfoundation/algokit-utils@7.0.0(algosdk@2.9.0)': + '@algorandfoundation/algokit-utils@8.0.0(algosdk@3.0.0)': dependencies: - algosdk: 2.9.0 + algosdk: 3.0.0 buffer: 6.0.3 '@algorandfoundation/tealscript@0.106.0': @@ -5310,11 +5317,11 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@blockshake/defly-connect@1.1.6(algosdk@2.9.0)': + '@blockshake/defly-connect@1.1.6(algosdk@3.0.0)': dependencies: '@walletconnect/client': 1.8.0 '@walletconnect/types': 1.8.0 - algosdk: 2.9.0 + algosdk: 3.0.0 bowser: 2.11.0 buffer: 6.0.3 lottie-web: 5.12.2 @@ -5777,12 +5784,12 @@ snapshots: '@parcel/watcher-win32-ia32': 2.4.1 '@parcel/watcher-win32-x64': 2.4.1 - '@perawallet/connect@1.3.5(algosdk@2.9.0)': + '@perawallet/connect@1.3.5(algosdk@3.0.0)': dependencies: '@evanhahn/lottie-web-light': 5.8.1 '@walletconnect/client': 1.8.0 '@walletconnect/types': 1.8.0 - algosdk: 2.9.0 + algosdk: 3.0.0 bowser: 2.11.0 buffer: 6.0.3 qr-code-styling: 1.6.0-rc.1 @@ -6607,28 +6614,29 @@ snapshots: '@tsconfig/node18@18.2.4': {} - '@txnlab/use-wallet-react@3.7.2(@blockshake/defly-connect@1.1.6(algosdk@2.9.0))(@perawallet/connect@1.3.5(algosdk@2.9.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@2.9.0)(lute-connect@1.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@txnlab/use-wallet-react@4.0.0-beta.2(@blockshake/defly-connect@1.1.6(algosdk@3.0.0))(@perawallet/connect@1.3.5(algosdk@3.0.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@3.0.0)(lute-connect@1.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/react-store': 0.5.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@txnlab/use-wallet': 3.7.2(@blockshake/defly-connect@1.1.6(algosdk@2.9.0))(@perawallet/connect@1.3.5(algosdk@2.9.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@2.9.0)(lute-connect@1.4.1) - algosdk: 2.9.0 + '@txnlab/use-wallet': 4.0.0-beta.2(@blockshake/defly-connect@1.1.6(algosdk@3.0.0))(@perawallet/connect@1.3.5(algosdk@3.0.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@3.0.0)(lute-connect@1.4.1) + algosdk: 3.0.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@blockshake/defly-connect': 1.1.6(algosdk@2.9.0) - '@perawallet/connect': 1.3.5(algosdk@2.9.0) + '@blockshake/defly-connect': 1.1.6(algosdk@3.0.0) + '@perawallet/connect': 1.3.5(algosdk@3.0.0) '@walletconnect/modal': 2.7.0(@types/react@18.3.11)(react@18.3.1) lute-connect: 1.4.1 transitivePeerDependencies: - '@agoralabs-sh/avm-web-provider' + - '@algorandfoundation/liquid-auth-use-wallet-client' - '@txnlab/use-wallet@3.7.2(@blockshake/defly-connect@1.1.6(algosdk@2.9.0))(@perawallet/connect@1.3.5(algosdk@2.9.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@2.9.0)(lute-connect@1.4.1)': + '@txnlab/use-wallet@4.0.0-beta.2(@blockshake/defly-connect@1.1.6(algosdk@3.0.0))(@perawallet/connect@1.3.5(algosdk@3.0.0))(@walletconnect/modal@2.7.0(@types/react@18.3.11)(react@18.3.1))(algosdk@3.0.0)(lute-connect@1.4.1)': dependencies: '@tanstack/store': 0.5.5 - algosdk: 2.9.0 + algosdk: 3.0.0 optionalDependencies: - '@blockshake/defly-connect': 1.1.6(algosdk@2.9.0) - '@perawallet/connect': 1.3.5(algosdk@2.9.0) + '@blockshake/defly-connect': 1.1.6(algosdk@3.0.0) + '@perawallet/connect': 1.3.5(algosdk@3.0.0) '@walletconnect/modal': 2.7.0(@types/react@18.3.11)(react@18.3.1) lute-connect: 1.4.1 @@ -7275,10 +7283,11 @@ snapshots: algo-msgpack-with-bigint@2.1.1: {} - algosdk@2.9.0: + algorand-msgpack@1.1.0: {} + + algosdk@3.0.0: dependencies: - algo-msgpack-with-bigint: 2.1.1 - buffer: 6.0.3 + algorand-msgpack: 1.1.0 hi-base32: 0.5.1 js-sha256: 0.9.0 js-sha3: 0.8.0 diff --git a/ui/package.json b/ui/package.json index b4d8d869..25b12cd8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -37,7 +37,7 @@ "vitest": "2.1.2" }, "dependencies": { - "@algorandfoundation/algokit-utils": "7.0.0", + "@algorandfoundation/algokit-utils": "8.0.0", "@blockshake/defly-connect": "1.1.6", "@hookform/resolvers": "3.9.0", "@perawallet/connect": "1.3.5", @@ -63,9 +63,9 @@ "@tanstack/react-table": "8.20.5", "@tanstack/router-devtools": "1.63.2", "@tremor/react": "3.18.3", - "@txnlab/use-wallet-react": "3.7.2", + "@txnlab/use-wallet-react": "4.0.0-beta.2", "@walletconnect/modal-sign-html": "2.7.0", - "algosdk": "2.9.0", + "algosdk": "3.0.0", "axios": "1.7.7", "axios-cache-interceptor": "1.6.0", "big.js": "6.2.2", diff --git a/ui/src/api/algod.ts b/ui/src/api/algod.ts index 0161eca5..54c8880d 100644 --- a/ui/src/api/algod.ts +++ b/ui/src/api/algod.ts @@ -1,17 +1,8 @@ import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' import { ClientManager } from '@algorandfoundation/algokit-utils/types/client-manager' -import { - AccountAssetInformation, - AccountBalance, - AccountInformation, - AlgodHttpError, - Asset, - AssetCreatorHolding, - AssetHolding, - BlockResponse, - Exclude, - NodeStatusResponse, -} from '@/interfaces/algod' +import algosdk from 'algosdk' +import { AccountBalance, AlgodHttpError, AssetCreatorHolding, Exclude } from '@/interfaces/algod' +import { BigMath } from '@/utils/bigint' import { getAlgodConfigFromViteEnvironment } from '@/utils/network/getAlgoClientConfigs' const algodConfig = getAlgodConfigFromViteEnvironment() @@ -24,24 +15,24 @@ const algodClient = ClientManager.getAlgodClient({ export async function fetchAccountInformation( address: string, exclude: Exclude = 'none', -): Promise { +): Promise { const accountInfo = await algodClient.accountInformation(address).exclude(exclude).do() - return accountInfo as AccountInformation + return accountInfo } export async function fetchAccountBalance( address: string, availableBalance = false, -): Promise { +): Promise { const accountInfo = await fetchAccountInformation(address, 'all') - return availableBalance ? accountInfo.amount - accountInfo['min-balance'] : accountInfo.amount + return availableBalance ? accountInfo.amount - accountInfo.minBalance : accountInfo.amount } -export async function fetchAsset(assetId: bigint | number): Promise { +export async function fetchAsset(assetId: bigint | number): Promise { try { - const asset = await algodClient.getAssetByID(Number(assetId)).do() - return asset as Asset + const asset = await algodClient.getAssetByID(assetId).do() + return asset // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { if (error.message && error.response) { @@ -59,8 +50,8 @@ export async function fetchBalance(address: string | null): Promise { +export async function fetchAssetHoldings( + address: string | null, +): Promise { if (!address) { throw new Error('No address provided') } @@ -80,8 +73,8 @@ export async function fetchAssetHoldings(address: string | null): Promise { + assetId: bigint, +): Promise { if (!address) { throw new Error('No address provided') } @@ -90,7 +83,7 @@ export async function fetchAccountAssetInformation( } try { const accountAssetInfo = await algodClient.accountAssetInformation(address, assetId).do() - return accountAssetInfo as AccountAssetInformation + return accountAssetInfo // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { if (error.message && error.response) { @@ -103,7 +96,7 @@ export async function fetchAccountAssetInformation( export async function isOptedInToAsset(address: string | null, assetId: bigint): Promise { try { - await fetchAccountAssetInformation(address, Number(assetId)) + await fetchAccountAssetInformation(address, assetId) return true } catch (error: unknown) { if (error instanceof AlgodHttpError && error.response.status === 404) { @@ -137,7 +130,7 @@ export async function fetchAssetCreatorHoldings( const batches = chunkArray(assetHoldings, batchSize) for (const batch of batches) { - const promises = batch.map((holding) => fetchAsset(holding['asset-id'])) + const promises = batch.map((holding) => fetchAsset(holding.assetId)) const assets = await Promise.all(promises) const assetCreatorHoldings = assets.map((asset, index) => { return { @@ -158,19 +151,19 @@ export async function fetchAssetCreatorHoldings( */ export async function fetchBlockTimes(numRounds: number = 10): Promise { try { - const status = (await algodClient.status().do()) as NodeStatusResponse + const status = await algodClient.status().do() if (!status) { throw new Error('Failed to fetch node status') } - const lastRound = Number(status['last-round']) + const lastRound = Number(status.lastRound) const blockTimes: number[] = [] for (let round = lastRound - numRounds; round < lastRound; round++) { try { - const blockResponse = (await algodClient.block(round).do()) as BlockResponse + const blockResponse = await algodClient.block(round).do() const block = blockResponse.block - blockTimes.push(block.ts) + blockTimes.push(Number(block.header.timestamp)) } catch (error) { throw new Error(`Unable to fetch block for round ${round}: ${error}`) } diff --git a/ui/src/api/contracts.ts b/ui/src/api/contracts.ts index 63f12bad..237e1431 100644 --- a/ui/src/api/contracts.ts +++ b/ui/src/api/contracts.ts @@ -26,7 +26,6 @@ import { ValidatorConfig, ValidatorRegistryClient, } from '@/contracts/ValidatorRegistryClient' -import { Asset } from '@/interfaces/algod' import { StakerPoolData, StakerValidatorData } from '@/interfaces/staking' import { EntryGatingAssets, @@ -65,23 +64,23 @@ export function callGetValidatorState( } async function processPool(pool: LocalPoolInfo): Promise { - const poolBalance = await fetchAccountBalance(algosdk.getApplicationAddress(pool.poolAppId), true) - if (poolBalance === 0) { - return { balance: 0n } + const poolAddress = algosdk.getApplicationAddress(pool.poolAppId) + const poolBalance = await fetchAccountBalance(poolAddress.toString(), true) + + const poolData: PoolData = { balance: poolBalance } + + if (poolData.balance === 0n) { + return poolData } const stakingPoolClient = await getSimulateStakingPoolClient(pool.poolAppId) const stakingPoolGS = await stakingPoolClient.state.global.getAll() + poolData.lastPayout = stakingPoolGS.lastPayout - const lastPayout = stakingPoolGS.lastPayout const ewma = stakingPoolGS.weightedMovingAverage - const apy = ewma ? Number(ewma) / 10000 : undefined + poolData.apy = ewma ? Number(ewma) / 10000 : undefined - return { - balance: BigInt(poolBalance), - lastPayout, - apy, - } + return poolData } async function setValidatorPoolMetrics(validator: Validator, queryClient?: QueryClient) { @@ -98,7 +97,7 @@ async function setValidatorPoolMetrics(validator: Validator, queryClient?: Query poolsData, validator.state.totalAlgoStaked, epochRoundLength, - BigInt(params.firstRound), + BigInt(params.firstValid), ) validator.rewardsBalance = rewardsBalance @@ -185,7 +184,7 @@ export async function fetchValidator( }), ) - validator.gatingAssets = gatingAssets.filter(Boolean) as Asset[] + validator.gatingAssets = gatingAssets.filter(Boolean) as algosdk.modelsv2.Asset[] } if (validator.config.nfdForInfo > 0) { @@ -268,7 +267,7 @@ export async function addValidator( }) // Check balance - const requiredBalance = Number(payValidatorMbr.amount) + payValidatorMbr.fee + 1000 + const requiredBalance = (payValidatorMbr.payment?.amount ?? 0n) + payValidatorMbr.fee + 1000n await BalanceChecker.check(activeAddress, requiredBalance, 'Add validator') const entryGatingType = Number(values.entryGatingType || 0) @@ -276,7 +275,7 @@ export async function addValidator( const entryGatingAssets = new Array(4).fill(0n) as EntryGatingAssets for (let i = 0; i < values.entryGatingAssets.length && i < 4; i++) { - entryGatingAssets[i] = BigInt(values.entryGatingAssets[i] || 0n) + entryGatingAssets[i] = BigInt(values.entryGatingAssets[i] ?? 0n) } const validatorConfig: ValidatorConfig = { @@ -288,8 +287,8 @@ export async function addValidator( entryGatingAddress, entryGatingAssets, gatingAssetMinBalance: BigInt(values.gatingAssetMinBalance || 0), - rewardTokenId: BigInt(values.rewardTokenId) || 0n, - rewardPerPayout: BigInt(values.rewardPerPayout) || 0n, + rewardTokenId: BigInt(values.rewardTokenId) ?? 0n, + rewardPerPayout: BigInt(values.rewardPerPayout) ?? 0n, epochRoundLength: Number(values.epochRoundLength), percentToValidator: Number(values.percentToValidator) * 10000, validatorCommissionAddress: values.validatorCommissionAddress, @@ -362,9 +361,15 @@ export async function addStakingPool( sender: activeAddress, amount: AlgoAmount.MicroAlgo(poolMbr), }) + // Check balance const requiredBalance = - Number(payValidatorAddPoolMbr.amount) + payValidatorAddPoolMbr.fee + 1000 + 1000 + 2000 + (payValidatorAddPoolMbr.payment?.amount ?? 0n) + + payValidatorAddPoolMbr.fee + + 1000n + + 1000n + + 2000n + await BalanceChecker.check(activeAddress, requiredBalance, 'Add staking pool') const addPoolResponse = await validatorClient @@ -393,15 +398,20 @@ export async function initStakingPoolStorage( const mbrAmount = optInRewardToken ? poolInitMbr + AlgoAmount.Algos(0.1).microAlgos : poolInitMbr const payPoolInitStorageMbr = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: algosdk.getApplicationAddress(poolAppId), + sender: activeAddress, + receiver: algosdk.getApplicationAddress(poolAppId), amount: mbrAmount, suggestedParams, }) // Check balance const requiredBalance = - Number(payPoolInitStorageMbr.amount) + payPoolInitStorageMbr.fee + 1000 + 1000 + 3000 + (payPoolInitStorageMbr.payment?.amount ?? 0n) + + payPoolInitStorageMbr.fee + + 1000n + + 1000n + + 3000n + await BalanceChecker.check(activeAddress, requiredBalance, 'Pool storage requirement payment') const stakingPoolClient = await getStakingPoolClient(poolAppId, signer, activeAddress) @@ -480,7 +490,7 @@ export async function findPoolForStaker( export async function addStake( validatorId: number, - stakeAmount: bigint | number, // microalgos + stakeAmount: bigint, // microalgos valueToVerify: bigint, rewardTokenId: bigint, signer: algosdk.TransactionSigner, @@ -517,8 +527,8 @@ export async function addStake( if (needsOptInTxn) { const rewardTokenOptInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: activeAddress, + sender: activeAddress, + receiver: activeAddress, amount: 0, assetIndex: Number(rewardTokenId), suggestedParams, @@ -543,7 +553,7 @@ export async function addStake( ) let requiredBalance = - BigInt(stakeTransferPayment.amount) + BigInt(stakeTransferPayment.fee) + feeAmount.microAlgos + (stakeTransferPayment.payment?.amount ?? 0n) + stakeTransferPayment.fee + feeAmount.microAlgos const composer = validatorClient .newGroup() @@ -551,7 +561,7 @@ export async function addStake( .addStake({ args: { // -- - // This the actual send of stake to the validator contract (which then sends to the staking pool) + // This is the actual send of stake to the validator contract (which then sends to the staking pool) stakedAmountPayment: { txn: stakeTransferPayment, signer }, // -- validatorId, @@ -562,20 +572,20 @@ export async function addStake( if (needsOptInTxn) { const rewardTokenOptInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: activeAddress, + sender: activeAddress, + receiver: activeAddress, amount: 0, assetIndex: Number(rewardTokenId), suggestedParams, }) - requiredBalance += BigInt(rewardTokenOptInTxn.fee) + requiredBalance += rewardTokenOptInTxn.fee composer.addTransaction(rewardTokenOptInTxn) } // Check balance - await BalanceChecker.check(activeAddress, Number(requiredBalance), 'Add stake') + await BalanceChecker.check(activeAddress, requiredBalance, 'Add stake') const result = await composer.send({ populateAppCallResources: true }) @@ -585,7 +595,7 @@ export async function addStake( export async function callFindPoolForStaker( validatorId: number | bigint, staker: string, - amountToStake: number | bigint, + amountToStake: bigint, validatorClient: ValidatorRegistryClient, ) { return validatorClient.send.findPoolForStaker({ args: { validatorId, staker, amountToStake } }) @@ -594,7 +604,7 @@ export async function callFindPoolForStaker( export async function isNewStakerToValidator( validatorId: number | bigint, staker: string, - minEntryStake: number | bigint, + minEntryStake: bigint, ) { const validatorClient = await getSimulateValidatorClient() const result = await callFindPoolForStaker(validatorId, staker, minEntryStake, validatorClient) @@ -748,7 +758,7 @@ export async function fetchProtocolConstraints( export async function removeStake( poolAppId: bigint, - amountToUnstake: number, + amountToUnstake: bigint, rewardTokenId: bigint, signer: algosdk.TransactionSigner, activeAddress: string, @@ -775,8 +785,8 @@ export async function removeStake( if (needsOptInTxn) { const rewardTokenOptInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: activeAddress, + sender: activeAddress, + receiver: activeAddress, amount: 0, assetIndex: Number(rewardTokenId), suggestedParams, @@ -813,20 +823,20 @@ export async function removeStake( if (needsOptInTxn) { const rewardTokenOptInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: activeAddress, + sender: activeAddress, + receiver: activeAddress, amount: 0, assetIndex: Number(rewardTokenId), suggestedParams, }) - requiredBalance += BigInt(rewardTokenOptInTxn.fee) + requiredBalance += rewardTokenOptInTxn.fee composer.addTransaction(rewardTokenOptInTxn) } // Check balance - await BalanceChecker.check(activeAddress, Number(requiredBalance), 'Remove stake') + await BalanceChecker.check(activeAddress, requiredBalance, 'Remove stake') await composer.send({ populateAppCallResources: true }) } @@ -915,7 +925,7 @@ export async function fetchPoolInfo( const poolInfo = result.return! const stakingPoolClient = await getSimulateStakingPoolClient(poolKey.poolAppId) - const poolAddress = stakingPoolClient.appAddress + const poolAddress = stakingPoolClient.appAddress.toString() return { poolId: poolKey.poolId, @@ -956,7 +966,7 @@ export async function fetchValidatorPools( for (const poolInfo of poolsInfo) { const stakingPoolClient = await getSimulateStakingPoolClient(poolInfo[0]) - poolAddresses.push(stakingPoolClient.appAddress) + poolAddresses.push(stakingPoolClient.appAddress.toString()) poolAlgodVersions.push((await stakingPoolClient.state.global.algodVer()).asString()) } @@ -1056,7 +1066,7 @@ export async function changeValidatorManager( const validatorClient = await getValidatorClient(signer, activeAddress) // Check balance - await BalanceChecker.check(activeAddress, 1000, 'Change validator manager') + await BalanceChecker.check(activeAddress, 1000n, 'Change validator manager') validatorClient.send.changeValidatorManager({ args: { validatorId, manager }, @@ -1074,7 +1084,7 @@ export async function changeValidatorSunsetInfo( const validatorClient = await getValidatorClient(signer, activeAddress) // Check balance - await BalanceChecker.check(activeAddress, 1000, 'Change validator sunset info') + await BalanceChecker.check(activeAddress, 1000n, 'Change validator sunset info') return validatorClient.send.changeValidatorSunsetInfo({ args: { validatorId, sunsettingOn, sunsettingTo }, @@ -1092,7 +1102,7 @@ export async function changeValidatorNfd( const validatorClient = await getValidatorClient(signer, activeAddress) // Check balance - await BalanceChecker.check(activeAddress, 1000, 'Change validator NFD') + await BalanceChecker.check(activeAddress, 1000n, 'Change validator NFD') return validatorClient.send.changeValidatorNfd({ args: { validatorId, nfdAppId, nfdName }, @@ -1110,7 +1120,7 @@ export async function changeValidatorCommissionAddress( const validatorClient = await getValidatorClient(signer, activeAddress) // Check balance - await BalanceChecker.check(activeAddress, 1000, 'Change validator commission address') + await BalanceChecker.check(activeAddress, 1000n, 'Change validator commission address') return validatorClient.send.changeValidatorCommissionAddress({ args: { validatorId, commissionAddress }, @@ -1123,15 +1133,15 @@ export async function changeValidatorRewardInfo( entryGatingType: number, entryGatingAddress: string, entryGatingAssets: EntryGatingAssets, - gatingAssetMinBalance: number | bigint, - rewardPerPayout: number | bigint, + gatingAssetMinBalance: bigint, + rewardPerPayout: bigint, signer: algosdk.TransactionSigner, activeAddress: string, ) { const validatorClient = await getValidatorClient(signer, activeAddress) // Check balance - await BalanceChecker.check(activeAddress, 1000, 'Change validator reward info') + await BalanceChecker.check(activeAddress, 1000n, 'Change validator reward info') return validatorClient.send.changeValidatorRewardInfo({ args: { @@ -1178,28 +1188,28 @@ export async function linkPoolToNfd( const feeAmount = AlgoAmount.MicroAlgos(5000) const payBoxStorageMbrTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: nfdAppAddress, + sender: activeAddress, + receiver: nfdAppAddress, amount: boxStorageMbrAmount.microAlgos, suggestedParams: await ParamsCache.getSuggestedParams(), }) const updateNfdAppCall = algosdk.makeApplicationNoOpTxnFromObject({ appIndex: nfdAppId, - from: activeAddress, + sender: activeAddress, suggestedParams: await ParamsCache.getSuggestedParams(), appArgs: [ new TextEncoder().encode('update_field'), new TextEncoder().encode('u.cav.algo.a'), - algosdk.decodeAddress(poolAppAddress).publicKey, + poolAppAddress.publicKey, ], }) // Check balance const requiredBalance = - BigInt(payBoxStorageMbrTxn.amount) + - BigInt(payBoxStorageMbrTxn.fee) + - BigInt(updateNfdAppCall.fee) + + (payBoxStorageMbrTxn.payment?.amount ?? 0n) + + payBoxStorageMbrTxn.fee + + updateNfdAppCall.fee + feeAmount.microAlgos await BalanceChecker.check(activeAddress, requiredBalance, 'Link pool to NFD') diff --git a/ui/src/components/AddPoolModal.tsx b/ui/src/components/AddPoolModal.tsx index 6ca469fb..06f1a403 100644 --- a/ui/src/components/AddPoolModal.tsx +++ b/ui/src/components/AddPoolModal.tsx @@ -87,9 +87,9 @@ export function AddPoolModal({ enabled: !!activeAddress && !!validator, // wait until modal is open }) - const { amount = 0, 'min-balance': minBalance = 0 } = accountInfoQuery.data || {} + const { amount = 0n, minBalance = 0n } = accountInfoQuery.data || {} - const availableBalance = Math.max(0, amount - minBalance) + const availableBalance = amount - minBalance < 0n ? 0n : amount - minBalance const mbrQuery = useQuery(mbrQueryOptions) const { addPoolMbr = 0n, poolInitMbr = 0n } = mbrQuery.data || {} @@ -231,7 +231,7 @@ export function AddPoolModal({ setPoolKey(stakingPoolKey) const poolAppAddress = algosdk.getApplicationAddress(stakingPoolKey.poolAppId) - setPoolAddress(poolAppAddress) + setPoolAddress(poolAppAddress.toString()) toast.success(`Staking pool ${stakingPoolKey.poolId} created!`, { id: toastId, diff --git a/ui/src/components/AddStakeModal.tsx b/ui/src/components/AddStakeModal.tsx index e80d7d19..cc624ad4 100644 --- a/ui/src/components/AddStakeModal.tsx +++ b/ui/src/components/AddStakeModal.tsx @@ -54,6 +54,7 @@ import { ellipseAddressJsx } from '@/utils/ellipseAddress' import { ExplorerLink } from '@/utils/explorer' import { formatAlgoAmount, formatAmount } from '@/utils/format' import { Constraints } from '@/contracts/ValidatorRegistryClient' +import { BigMath } from '@/utils/bigint' interface AddStakeModalProps { validator: Validator | null @@ -89,13 +90,9 @@ export function AddStakeModal({ enabled: !!activeAddress && !!validator, // wait until modal is open }) - const { - amount = 0, - 'min-balance': minBalance = 0, - assets: heldAssets = [], - } = accountInfoQuery.data || {} + const { amount = 0n, minBalance = 0n, assets: heldAssets = [] } = accountInfoQuery.data || {} - const availableBalance = Math.max(0, amount - minBalance) + const availableBalance = amount - minBalance < 0n ? 0n : amount - minBalance const heldGatingAssetQuery = useQuery({ queryKey: ['held-gating-asset', validator?.id, activeAddress], @@ -132,16 +129,19 @@ export function AddStakeModal({ () => stakesByValidator.find((data) => Number(data.validatorId) === validator?.id)?.pools || [], [stakesByValidator, validator], ) - const minimumStake = stakerPoolsData.length === 0 ? Number(validator?.config.minEntryStake) : 0 + const minimumStake = stakerPoolsData.length === 0 ? (validator?.config.minEntryStake ?? 0n) : 0n - const poolMaximumStake = validator ? calculateMaxAvailableToStake(validator, constraints) : 0 + const poolMaximumStake = validator ? calculateMaxAvailableToStake(validator, constraints) : 0n const stakerMaximumStake = React.useMemo(() => { const estimatedFee = AlgoAmount.MicroAlgos(240_000).microAlgos - return Math.max(0, availableBalance - Number(mbrAmount) - Number(estimatedFee)) + return BigMath.max(0n, availableBalance - mbrAmount - estimatedFee) }, [availableBalance, mbrAmount]) - const maximumStake = Math.min(stakerMaximumStake, poolMaximumStake || stakerMaximumStake) + const maximumStake = BigMath.min( + stakerMaximumStake, + poolMaximumStake === 0n ? stakerMaximumStake : poolMaximumStake, + ) const formSchema = z.object({ amountToStake: z diff --git a/ui/src/components/AddValidatorForm.tsx b/ui/src/components/AddValidatorForm.tsx index b77126fb..fa8835cc 100644 --- a/ui/src/components/AddValidatorForm.tsx +++ b/ui/src/components/AddValidatorForm.tsx @@ -2,6 +2,7 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useQueryClient } from '@tanstack/react-query' import { useNavigate } from '@tanstack/react-router' import { useWallet } from '@txnlab/use-wallet-react' +import algosdk from 'algosdk' import { isAxiosError } from 'axios' import { ArrowUpRight, Check, Monitor, MonitorCheck, WalletMinimal, X } from 'lucide-react' import * as React from 'react' @@ -37,7 +38,6 @@ import { import { Separator } from '@/components/ui/separator' import { GatingType } from '@/constants/gating' import { useBlockTime } from '@/hooks/useBlockTime' -import { Asset } from '@/interfaces/algod' import { useAuthAddress } from '@/providers/AuthAddressProvider' import { InsufficientBalanceError } from '@/utils/balanceChecker' import { @@ -66,9 +66,9 @@ export function AddValidatorForm({ constraints }: AddValidatorFormProps) { const [isFetchingNfdCreator, setIsFetchingNfdCreator] = React.useState(false) const [nfdParentAppId, setNfdParentAppId] = React.useState(0n) const [isFetchingNfdParent, setIsFetchingNfdParent] = React.useState(false) - const [rewardToken, setRewardToken] = React.useState(null) + const [rewardToken, setRewardToken] = React.useState(null) const [isFetchingRewardToken, setIsFetchingRewardToken] = React.useState(false) - const [gatingAssets, setGatingAssets] = React.useState>([]) + const [gatingAssets, setGatingAssets] = React.useState>([]) const [isFetchingGatingAssetIndex, setIsFetchingGatingAssetIndex] = React.useState(-1) const [epochTimeframe, setEpochTimeframe] = React.useState('blocks') const [isSigning, setIsSigning] = React.useState(false) @@ -155,7 +155,7 @@ export function AddValidatorForm({ constraints }: AddValidatorFormProps) { }) } - const handleSetGatingAssetById = async (index: number, value: Asset | null) => { + const handleSetGatingAssetById = async (index: number, value: algosdk.modelsv2.Asset | null) => { setGatingAssets((prev) => { const newAssets = [...prev] newAssets[index] = value diff --git a/ui/src/components/AssetLookup.tsx b/ui/src/components/AssetLookup.tsx index ea10f06b..2d94e2c9 100644 --- a/ui/src/components/AssetLookup.tsx +++ b/ui/src/components/AssetLookup.tsx @@ -1,3 +1,4 @@ +import algosdk from 'algosdk' import { Check } from 'lucide-react' import * as React from 'react' import { FieldPath, FieldValues, UseFormReturn } from 'react-hook-form' @@ -5,7 +6,7 @@ import { useDebouncedCallback } from 'use-debounce' import { fetchAsset as fetchAssetInformation } from '@/api/algod' import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form' import { Input } from '@/components/ui/input' -import { AlgodHttpError, Asset } from '@/interfaces/algod' +import { AlgodHttpError } from '@/interfaces/algod' import { cn } from '@/utils/ui' const ERROR_EMPTY_FIELD = 'No asset ID entered' @@ -20,8 +21,8 @@ interface AssetLookupProps< form: UseFormReturn id: string name: TName - asset: Asset | null - setAsset: (asset: Asset | null) => void + asset: algosdk.modelsv2.Asset | null + setAsset: (asset: algosdk.modelsv2.Asset | null) => void isFetching: boolean setIsFetching: (isFetching: boolean) => void errorMessage?: string @@ -162,7 +163,7 @@ export function AssetLookup< ) : asset ? (
- {asset.params['unit-name']} + {asset.params.unitName}
diff --git a/ui/src/components/DisplayAsset.tsx b/ui/src/components/DisplayAsset.tsx index c8578fa5..38e3a618 100644 --- a/ui/src/components/DisplayAsset.tsx +++ b/ui/src/components/DisplayAsset.tsx @@ -1,10 +1,10 @@ +import algosdk from 'algosdk' import * as React from 'react' -import { Asset } from '@/interfaces/algod' import { ExplorerLink } from '@/utils/explorer' import { cn } from '@/utils/ui' interface DisplayAssetProps { - asset?: Asset + asset?: algosdk.modelsv2.Asset show?: 'name' | 'unit-name' | 'full' link?: boolean fallback?: React.ReactNode @@ -22,8 +22,8 @@ export function DisplayAsset({ return {unitName} } - const renderDisplayAsset = (asset: Asset) => { - const { name, 'unit-name': unitName } = asset.params + const renderDisplayAsset = (asset: algosdk.modelsv2.Asset) => { + const { name, unitName } = asset.params if (unitName && show === 'unit-name') { return renderUnitName(unitName) @@ -51,7 +51,7 @@ export function DisplayAsset({ return renderUnitName(unitName) } - return asset.index + return asset.index.toString() } if (!asset) { diff --git a/ui/src/components/UnstakeModal.tsx b/ui/src/components/UnstakeModal.tsx index 6392aa05..40975b8f 100644 --- a/ui/src/components/UnstakeModal.tsx +++ b/ui/src/components/UnstakeModal.tsx @@ -199,7 +199,7 @@ export function UnstakeModal({ validator, setValidator, stakesByValidator }: Uns await removeStake( pool.poolKey.poolAppId, - Number(amountToUnstake), + amountToUnstake, validator!.config.rewardTokenId, transactionSigner, activeAddress, diff --git a/ui/src/components/ValidatorDetails/EditEntryGating.tsx b/ui/src/components/ValidatorDetails/EditEntryGating.tsx index bcb2862e..35449d64 100644 --- a/ui/src/components/ValidatorDetails/EditEntryGating.tsx +++ b/ui/src/components/ValidatorDetails/EditEntryGating.tsx @@ -1,6 +1,7 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useQuery, useQueryClient } from '@tanstack/react-query' import { useWallet } from '@txnlab/use-wallet-react' +import algosdk from 'algosdk' import { isAxiosError } from 'axios' import { ArrowUpRight, Check, RotateCcw, X } from 'lucide-react' import * as React from 'react' @@ -36,7 +37,6 @@ import { import { EditValidatorModal } from '@/components/ValidatorDetails/EditValidatorModal' import { ALGORAND_ZERO_ADDRESS_STRING } from '@/constants/accounts' import { GatingType } from '@/constants/gating' -import { Asset } from '@/interfaces/algod' import { EntryGatingAssets, Validator } from '@/interfaces/validator' import { InsufficientBalanceError } from '@/utils/balanceChecker' import { setValidatorQueriesData, transformEntryGatingAssets } from '@/utils/contracts' @@ -55,7 +55,7 @@ interface EditEntryGatingProps { export function EditEntryGating({ validator }: EditEntryGatingProps) { const [isOpen, setIsOpen] = React.useState(false) const [isSigning, setIsSigning] = React.useState(false) - const [gatingAssets, setGatingAssets] = React.useState>([]) + const [gatingAssets, setGatingAssets] = React.useState>([]) const [isFetchingGatingAssetIndex, setIsFetchingGatingAssetIndex] = React.useState(-1) const { @@ -151,7 +151,7 @@ export function EditEntryGating({ validator }: EditEntryGatingProps) { }) } - const handleSetGatingAssetById = async (index: number, value: Asset | null) => { + const handleSetGatingAssetById = async (index: number, value: algosdk.modelsv2.Asset | null) => { setGatingAssets((prev) => { const newAssets = [...prev] newAssets[index] = value diff --git a/ui/src/components/ValidatorDetails/EditRewardPerPayout.tsx b/ui/src/components/ValidatorDetails/EditRewardPerPayout.tsx index 61d5809c..1ab1c354 100644 --- a/ui/src/components/ValidatorDetails/EditRewardPerPayout.tsx +++ b/ui/src/components/ValidatorDetails/EditRewardPerPayout.tsx @@ -48,7 +48,7 @@ export function EditRewardPerPayout({ validator }: EditRewardPerPayoutProps) { rewardPerPayout, } = validator.config - const tokenUnitName = validator.rewardToken?.params['unit-name'] + const tokenUnitName = validator.rewardToken?.params.unitName const tokenDecimals = validator.rewardToken?.params.decimals const rewardPerPayoutWholeUnits = convertFromBaseUnits(rewardPerPayout, tokenDecimals) diff --git a/ui/src/components/ValidatorRewards.tsx b/ui/src/components/ValidatorRewards.tsx index c0881e35..c323d722 100644 --- a/ui/src/components/ValidatorRewards.tsx +++ b/ui/src/components/ValidatorRewards.tsx @@ -17,13 +17,14 @@ import { ParamsCache } from '@/utils/paramsCache' */ async function fetchRewardBalances(validator: Validator) { try { - let totalBalances = 0 + let totalBalances = 0n for (const pool of validator.pools) { - const poolBal = await fetchAccountBalance(getApplicationAddress(pool.poolAppId), true) + const poolAddress = getApplicationAddress(pool.poolAppId) + const poolBal = await fetchAccountBalance(poolAddress.toString(), true) totalBalances += poolBal } // Truncate to nearest whole ALGO - return Math.round((totalBalances - Number(validator.state.totalAlgoStaked)) / 1e6) * 1e6 + return Math.round((Number(totalBalances) - Number(validator.state.totalAlgoStaked)) / 1e6) * 1e6 } catch (error) { console.error(error) return 0 @@ -36,7 +37,8 @@ async function epochPayoutFetch(validator: Validator) { try { let oldestRound = 0n for (const pool of validator.pools) { - const poolBal = await fetchAccountBalance(getApplicationAddress(pool.poolAppId), true) + const poolAddress = getApplicationAddress(pool.poolAppId) + const poolBal = await fetchAccountBalance(poolAddress.toString(), true) if (poolBal > 0) { const stakingPoolClient = await getSimulateStakingPoolClient(pool.poolAppId) const stakingPoolGS = await stakingPoolClient.appClient.getGlobalState() @@ -54,7 +56,7 @@ async function epochPayoutFetch(validator: Validator) { } } } - return BigInt(params.firstRound) - oldestRound + return BigInt(params.firstValid) - oldestRound } catch (error) { console.error(error) return 0n diff --git a/ui/src/components/ValidatorTable.tsx b/ui/src/components/ValidatorTable.tsx index 629ee033..9ecf28a2 100644 --- a/ui/src/components/ValidatorTable.tsx +++ b/ui/src/components/ValidatorTable.tsx @@ -326,7 +326,7 @@ export function ValidatorTable({ return ( - {validator.rewardToken.params['unit-name']} + {validator.rewardToken.params.unitName} ) }, diff --git a/ui/src/interfaces/algod.ts b/ui/src/interfaces/algod.ts index 5f6ac020..d1c415c2 100644 --- a/ui/src/interfaces/algod.ts +++ b/ui/src/interfaces/algod.ts @@ -1,32 +1,11 @@ import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' -import { AssetParams } from '@algorandfoundation/algokit-utils/types/indexer' -import { BaseHTTPClientError, BaseHTTPClientResponse } from 'algosdk' +import algosdk, { BaseHTTPClientError, BaseHTTPClientResponse } from 'algosdk' -export interface AssetHolding { - amount: number - 'asset-id': number - 'is-frozen': boolean -} - -export interface AssetCreatorHolding extends AssetHolding { +export interface AssetCreatorHolding + extends Omit { creator: string } -export interface AccountInformation { - address: string - amount: number - 'min-balance': number - assets?: AssetHolding[] - 'auth-addr'?: string - 'created-assets'?: Asset[] - // add more fields as needed -} - -export interface AccountAssetInformation { - 'asset-holding': AssetHolding - round: number -} - export type AccountBalance = { amount: AlgoAmount available: AlgoAmount @@ -41,11 +20,6 @@ export type Exclude = | 'created-apps' | 'none' -export interface Asset { - index: number - params: AssetParams -} - export class AlgodHttpError extends Error implements BaseHTTPClientError { constructor( message: string, diff --git a/ui/src/interfaces/simulate.ts b/ui/src/interfaces/simulate.ts deleted file mode 100644 index 1a29f7d8..00000000 --- a/ui/src/interfaces/simulate.ts +++ /dev/null @@ -1,594 +0,0 @@ -import { EncodedSignedTransaction } from 'algosdk' - -/** - * Request type for simulation endpoint. - */ -export interface SimulateRequest { - /** - * The transaction groups to simulate. - */ - 'txn-groups': SimulateRequestTransactionGroup[] - /** - * Allows transactions without signatures to be simulated as if they had correct - * signatures. - */ - 'allow-empty-signatures'?: boolean - /** - * Lifts limits on log opcode usage during simulation. - */ - 'allow-more-logging'?: boolean - /** - * Allows access to unnamed resources during simulation. - */ - 'allow-unnamed-resources'?: boolean - /** - * An object that configures simulation execution trace. - */ - 'exec-trace-config'?: SimulateTraceConfig - /** - * Applies extra opcode budget during simulation for each transaction group. - */ - 'extra-opcode-budget'?: number | bigint - /** - * If provided, specifies the round preceding the simulation. State changes through - * this round will be used to run this simulation. Usually only the 4 most recent - * rounds will be available (controlled by the node config value MaxAcctLookback). - * If not specified, defaults to the latest available round. - */ - round?: number | bigint -} - -/** - * A transaction group to simulate. - */ -export interface SimulateRequestTransactionGroup { - /** - * An atomic transaction group. - */ - txns: EncodedSignedTransaction[] -} - -/** - * Result of a transaction group simulation. - */ -export interface SimulateResponse { - /** - * The round immediately preceding this simulation. State changes through this - * round were used to run this simulation. - */ - 'last-round': number | bigint - /** - * A result object for each transaction group that was simulated. - */ - 'txn-groups': SimulateTransactionGroupResult[] - /** - * The version of this response object. - */ - version: number | bigint - /** - * The set of parameters and limits override during simulation. If this set of - * parameters is present, then evaluation parameters may differ from standard - * evaluation in certain ways. - */ - 'eval-overrides'?: SimulationEvalOverrides - /** - * An object that configures simulation execution trace. - */ - 'exec-trace-config'?: SimulateTraceConfig - /** - * Initial states of resources that were accessed during simulation. - */ - 'initial-states'?: SimulateInitialStates -} - -/** - * Simulation result for an atomic transaction group - */ -export interface SimulateTransactionGroupResult { - /** - * Simulation result for individual transactions - */ - 'txn-results': SimulateTransactionResult[] - /** - * Total budget added during execution of app calls in the transaction group. - */ - 'app-budget-added'?: number | bigint - /** - * Total budget consumed during execution of app calls in the transaction group. - */ - 'app-budget-consumed'?: number | bigint - /** - * If present, indicates which transaction in this group caused the failure. This - * array represents the path to the failing transaction. Indexes are zero based, - * the first element indicates the top-level transaction, and successive elements - * indicate deeper inner transactions. - */ - 'failed-at'?: (number | bigint)[] - /** - * If present, indicates that the transaction group failed and specifies why that - * happened - */ - 'failure-message'?: string - /** - * These are resources that were accessed by this group that would normally have - * caused failure, but were allowed in simulation. Depending on where this object - * is in the response, the unnamed resources it contains may or may not qualify for - * group resource sharing. If this is a field in SimulateTransactionGroupResult, - * the resources do qualify, but if this is a field in SimulateTransactionResult, - * they do not qualify. In order to make this group valid for actual submission, - * resources that qualify for group sharing can be made available by any - * transaction of the group; otherwise, resources must be placed in the same - * transaction which accessed them. - */ - 'unnamed-resources-accessed'?: SimulateUnnamedResourcesAccessed -} - -/** - * Simulation result for an atomic transaction group - */ -export interface SimulateTransactionResult { - /** - * Details about a pending transaction. If the transaction was recently confirmed, - * includes confirmation details like the round and reward details. - */ - 'txn-result': PendingTransactionResponse - /** - * Budget used during execution of an app call transaction. This value includes - * budged used by inner app calls spawned by this transaction. - */ - 'app-budget-consumed'?: number | bigint - /** - * The execution trace of calling an app or a logic sig, containing the inner app - * call trace in a recursive way. - */ - 'exec-trace'?: SimulationTransactionExecTrace - /** - * Budget used during execution of a logic sig transaction. - */ - 'logic-sig-budget-consumed'?: number | bigint - /** - * These are resources that were accessed by this group that would normally have - * caused failure, but were allowed in simulation. Depending on where this object - * is in the response, the unnamed resources it contains may or may not qualify for - * group resource sharing. If this is a field in SimulateTransactionGroupResult, - * the resources do qualify, but if this is a field in SimulateTransactionResult, - * they do not qualify. In order to make this group valid for actual submission, - * resources that qualify for group sharing can be made available by any - * transaction of the group; otherwise, resources must be placed in the same - * transaction which accessed them. - */ - 'unnamed-resources-accessed'?: SimulateUnnamedResourcesAccessed -} - -/** - * Details about a pending transaction. If the transaction was recently confirmed, - * includes confirmation details like the round and reward details. - */ -export interface PendingTransactionResponse { - /** - * Indicates that the transaction was kicked out of this node's transaction pool - * (and specifies why that happened). An empty string indicates the transaction - * wasn't kicked out of this node's txpool due to an error. - */ - 'pool-error': string - /** - * The raw signed transaction. - */ - txn: EncodedSignedTransaction - /** - * The application index if the transaction was found and it created an - * application. - */ - 'application-index'?: number | bigint - /** - * The number of the asset's unit that were transferred to the close-to address. - */ - 'asset-closing-amount'?: number | bigint - /** - * The asset index if the transaction was found and it created an asset. - */ - 'asset-index'?: number | bigint - /** - * Rewards in microalgos applied to the close remainder to account. - */ - 'close-rewards'?: number | bigint - /** - * Closing amount for the transaction. - */ - 'closing-amount'?: number | bigint - /** - * The round where this transaction was confirmed, if present. - */ - 'confirmed-round'?: number | bigint - /** - * Global state key/value changes for the application being executed by this - * transaction. - */ - 'global-state-delta'?: EvalDeltaKeyValue[] - /** - * Inner transactions produced by application execution. - */ - 'inner-txns'?: PendingTransactionResponse[] - /** - * Local state key/value changes for the application being executed by this - * transaction. - */ - 'local-state-delta'?: AccountStateDelta[] - /** - * Logs for the application being executed by this transaction. - */ - logs?: Uint8Array[] - /** - * Rewards in microalgos applied to the receiver account. - */ - 'receiver-rewards'?: number | bigint - /** - * Rewards in microalgos applied to the sender account. - */ - 'sender-rewards'?: number | bigint -} - -/** - * The execution trace of calling an app or a logic sig, containing the inner app - * call trace in a recursive way. - */ -export interface SimulationTransactionExecTrace { - /** - * SHA512_256 hash digest of the approval program executed in transaction. - */ - 'approval-program-hash'?: Uint8Array - /** - * Program trace that contains a trace of opcode effects in an approval program. - */ - 'approval-program-trace'?: SimulationOpcodeTraceUnit[] - /** - * SHA512_256 hash digest of the clear state program executed in transaction. - */ - 'clear-state-program-hash'?: Uint8Array - /** - * Program trace that contains a trace of opcode effects in a clear state program. - */ - 'clear-state-program-trace'?: SimulationOpcodeTraceUnit[] - /** - * An array of SimulationTransactionExecTrace representing the execution trace of - * any inner transactions executed. - */ - 'inner-trace'?: SimulationTransactionExecTrace[] - /** - * SHA512_256 hash digest of the logic sig executed in transaction. - */ - 'logic-sig-hash'?: Uint8Array - /** - * Program trace that contains a trace of opcode effects in a logic sig. - */ - 'logic-sig-trace'?: SimulationOpcodeTraceUnit[] -} - -/** - * These are resources that were accessed by this group that would normally have - * caused failure, but were allowed in simulation. Depending on where this object - * is in the response, the unnamed resources it contains may or may not qualify for - * group resource sharing. If this is a field in SimulateTransactionGroupResult, - * the resources do qualify, but if this is a field in SimulateTransactionResult, - * they do not qualify. In order to make this group valid for actual submission, - * resources that qualify for group sharing can be made available by any - * transaction of the group; otherwise, resources must be placed in the same - * transaction which accessed them. - */ -export interface SimulateUnnamedResourcesAccessed { - /** - * The unnamed accounts that were referenced. The order of this array is arbitrary. - */ - accounts?: string[] - /** - * The unnamed application local states that were referenced. The order of this - * array is arbitrary. - */ - 'app-locals'?: ApplicationLocalReference[] - /** - * The unnamed applications that were referenced. The order of this array is - * arbitrary. - */ - apps?: (number | bigint)[] - /** - * The unnamed asset holdings that were referenced. The order of this array is - * arbitrary. - */ - 'asset-holdings'?: AssetHoldingReference[] - /** - * The unnamed assets that were referenced. The order of this array is arbitrary. - */ - assets?: (number | bigint)[] - /** - * The unnamed boxes that were referenced. The order of this array is arbitrary. - */ - boxes?: BoxReference[] - /** - * The number of extra box references used to increase the IO budget. This is in - * addition to the references defined in the input transaction group and any - * referenced to unnamed boxes. - */ - 'extra-box-refs'?: number | bigint -} - -/** - * Key-value pairs for StateDelta. - */ -export interface EvalDeltaKeyValue { - key: string - /** - * Represents a TEAL value delta. - */ - value: EvalDelta -} - -/** - * Represents a TEAL value delta. - */ -export interface EvalDelta { - /** - * (at) delta action. - */ - action: number | bigint - /** - * (bs) bytes value. - */ - bytes?: string - /** - * (ui) uint value. - */ - uint?: number | bigint -} - -/** - * Application state delta. - */ -export interface AccountStateDelta { - address: string - /** - * Application state delta. - */ - delta: EvalDeltaKeyValue[] -} - -/** - * The set of trace information and effect from evaluating a single opcode. - */ -export interface SimulationOpcodeTraceUnit { - /** - * The program counter of the current opcode being evaluated. - */ - pc: number | bigint - /** - * The writes into scratch slots. - */ - 'scratch-changes'?: ScratchChange[] - /** - * The indexes of the traces for inner transactions spawned by this opcode, if any. - */ - 'spawned-inners'?: (number | bigint)[] - /** - * The values added by this opcode to the stack. - */ - 'stack-additions'?: AvmValue[] - /** - * The number of deleted stack values by this opcode. - */ - 'stack-pop-count'?: number | bigint - /** - * The operations against the current application's states. - */ - 'state-changes'?: ApplicationStateOperation[] -} - -/** - * A write operation into a scratch slot. - */ -export interface ScratchChange { - /** - * Represents an AVM value. - */ - 'new-value': AvmValue - /** - * The scratch slot written. - */ - slot: number | bigint -} - -/** - * An operation against an application's global/local/box state. - */ -export interface ApplicationStateOperation { - /** - * Type of application state. Value `g` is **global state**, `l` is **local - * state**, `b` is **boxes**. - */ - 'app-state-type': string - /** - * The key (name) of the global/local/box state. - */ - key: Uint8Array - /** - * Operation type. Value `w` is **write**, `d` is **delete**. - */ - operation: string - /** - * For local state changes, the address of the account associated with the local - * state. - */ - account?: string - /** - * Represents an AVM value. - */ - 'new-value'?: AvmValue -} - -/** - * Represents an AVM value. - */ -export interface AvmValue { - /** - * value type. Value `1` refers to **bytes**, value `2` refers to **uint64** - */ - type: number | bigint - /** - * bytes value. - */ - bytes?: Uint8Array - /** - * uint value. - */ - uint?: number | bigint -} - -/** - * Represents an AVM key-value pair in an application store. - */ -export interface AvmKeyValue { - key: Uint8Array - /** - * Represents an AVM value. - */ - value: AvmValue -} - -/** - * References an account's local state for an application. - */ -export interface ApplicationLocalReference { - /** - * Address of the account with the local state. - */ - account: string - /** - * Application ID of the local state application. - */ - app: number | bigint -} - -/** - * References an asset held by an account. - */ -export interface AssetHoldingReference { - /** - * Address of the account holding the asset. - */ - account: string - /** - * Asset ID of the holding. - */ - asset: number | bigint -} - -/** - * References a box of an application. - */ -export interface BoxReference { - /** - * Application ID which this box belongs to - */ - app: number | bigint - /** - * Base64 encoded box name - */ - name: Uint8Array -} - -/** - * The set of parameters and limits override during simulation. If this set of - * parameters is present, then evaluation parameters may differ from standard - * evaluation in certain ways. - */ -export interface SimulationEvalOverrides { - /** - * If true, transactions without signatures are allowed and simulated as if they - * were properly signed. - */ - 'allow-empty-signatures'?: boolean - /** - * If true, allows access to unnamed resources during simulation. - */ - 'allow-unnamed-resources'?: boolean - /** - * The extra opcode budget added to each transaction group during simulation - */ - 'extra-opcode-budget'?: number | bigint - /** - * The maximum log calls one can make during simulation - */ - 'max-log-calls'?: number | bigint - /** - * The maximum byte number to log during simulation - */ - 'max-log-size'?: number | bigint -} - -export interface SimulateTraceConfig { - /** - * A boolean option for opting in execution trace features simulation endpoint. - */ - enable?: boolean - /** - * A boolean option enabling returning scratch slot changes together with execution - * trace during simulation. - */ - 'scratch-change'?: boolean - /** - * A boolean option enabling returning stack changes together with execution trace - * during simulation. - */ - 'stack-change'?: boolean - /** - * A boolean option enabling returning application state changes (global, local, - * and box changes) with the execution trace during simulation. - */ - 'state-change'?: boolean -} - -/** - * Initial states of resources that were accessed during simulation. - */ -export interface SimulateInitialStates { - /** - * The initial states of accessed application before simulation. The order of this - * array is arbitrary. - */ - 'app-initial-states'?: ApplicationInitialStates[] -} - -/** - * An application's initial global/local/box states that were accessed during - * simulation. - */ -export interface ApplicationInitialStates { - /** - * Application index. - */ - id: number | bigint - /** - * An application's global/local/box state. - */ - 'app-boxes'?: ApplicationKVStorage - /** - * An application's global/local/box state. - */ - 'app-globals'?: ApplicationKVStorage - /** - * An application's initial local states tied to different accounts. - */ - 'app-locals'?: ApplicationKVStorage[] -} - -/** - * An application's global/local/box state. - */ -export interface ApplicationKVStorage { - /** - * Key-Value pairs representing application states. - */ - kvs: AvmKeyValue[] - /** - * The address of the account associated with the local state. - */ - account?: string -} diff --git a/ui/src/interfaces/validator.ts b/ui/src/interfaces/validator.ts index c47dca50..12fa7aa4 100644 --- a/ui/src/interfaces/validator.ts +++ b/ui/src/interfaces/validator.ts @@ -1,4 +1,4 @@ -import { Asset } from '@/interfaces/algod' +import algosdk from 'algosdk' import { Nfd } from '@/interfaces/nfd' import { ToStringTypes } from '@/interfaces/utils' import { @@ -43,8 +43,8 @@ export type Validator = { nodePoolAssignment: NodePoolAssignmentConfig rewardsBalance?: bigint roundsSinceLastPayout?: bigint - rewardToken?: Asset - gatingAssets?: Asset[] + rewardToken?: algosdk.modelsv2.Asset + gatingAssets?: algosdk.modelsv2.Asset[] nfd?: Nfd apy?: number } diff --git a/ui/src/lib/makeEmptyTransactionSigner.ts b/ui/src/lib/makeEmptyTransactionSigner.ts index ddf7e075..b14e03f0 100644 --- a/ui/src/lib/makeEmptyTransactionSigner.ts +++ b/ui/src/lib/makeEmptyTransactionSigner.ts @@ -1,4 +1,4 @@ -import algosdk, { Transaction, TransactionSigner, EncodedSignedTransaction } from 'algosdk' +import algosdk from 'algosdk' /** * This is a "polyfill" for algosdk's `makeEmptyTransactionSigner` function that supports simulate @@ -8,23 +8,20 @@ import algosdk, { Transaction, TransactionSigner, EncodedSignedTransaction } fro * @param {string} authAddr - Optional authorized address (spending key) for a rekeyed account. * @returns A function that can be used with simulate w/ the "allow empty signatures" option. */ -export const makeEmptyTransactionSigner = (authAddr?: string): TransactionSigner => { - return async (txns: Transaction[], indexesToSign: number[]): Promise => { +export const makeEmptyTransactionSigner = (authAddr?: string): algosdk.TransactionSigner => { + return async (txns: algosdk.Transaction[], indexesToSign: number[]): Promise => { const emptySigTxns: Uint8Array[] = [] indexesToSign.forEach((i) => { - const encodedStxn: EncodedSignedTransaction = { - txn: txns[i].get_obj_for_encoding(), - } + const txn = txns[i] + const encodedStxn: Map = new Map([['txn', txn.toEncodingData()]]) // If authAddr is provided, use its decoded publicKey as the signer if (authAddr) { - const { publicKey } = algosdk.decodeAddress(authAddr) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - encodedStxn.sgnr = publicKey as any as Buffer + encodedStxn.set('sgnr', algosdk.decodeAddress(authAddr).publicKey) } - emptySigTxns.push(algosdk.encodeObj(encodedStxn)) + emptySigTxns.push(algosdk.msgpackRawEncode(encodedStxn)) }) return emptySigTxns diff --git a/ui/src/main.tsx b/ui/src/main.tsx index 4a741c0a..791d15a2 100644 --- a/ui/src/main.tsx +++ b/ui/src/main.tsx @@ -52,15 +52,20 @@ if (import.meta.env.VITE_ALGOD_NETWORK === 'localnet') { } const algodConfig = getAlgodConfigFromViteEnvironment() -const network = getAlgodNetwork() +const defaultNetwork = getAlgodNetwork() const walletManager = new WalletManager({ wallets, - network, - algod: { - baseServer: algodConfig.server, - port: algodConfig.port, - token: algodConfig.token as string, + defaultNetwork, + networks: { + [defaultNetwork]: { + name: defaultNetwork, + algod: { + baseServer: algodConfig.server, + port: algodConfig.port, + token: algodConfig.token as string, + }, + }, }, options: { resetNetwork: true, diff --git a/ui/src/providers/AuthAddressProvider.tsx b/ui/src/providers/AuthAddressProvider.tsx index adada5ba..d1182aec 100644 --- a/ui/src/providers/AuthAddressProvider.tsx +++ b/ui/src/providers/AuthAddressProvider.tsx @@ -27,8 +27,8 @@ export function AuthAddressProvider({ children }: { children: React.ReactNode }) const fetchAuthAddress = async () => { try { const accountInfo = await fetchAccountInformation(activeAddress!, 'all') - const authAddr = accountInfo['auth-addr'] - setAuthAddress(authAddr) + const authAddr = accountInfo.authAddr + setAuthAddress(authAddr?.toString()) } catch (error) { console.error(`Error fetching active wallet's authorized address:`, error) setAuthAddress(undefined) diff --git a/ui/src/utils/balanceChecker.ts b/ui/src/utils/balanceChecker.ts index d1d69b97..71c29622 100644 --- a/ui/src/utils/balanceChecker.ts +++ b/ui/src/utils/balanceChecker.ts @@ -1,5 +1,6 @@ import { ClientManager } from '@algorandfoundation/algokit-utils/types/client-manager' import algosdk from 'algosdk' +import { BigMath } from '@/utils/bigint' import { formatAlgoAmount } from '@/utils/format' import { getAlgodConfigFromViteEnvironment } from '@/utils/network/getAlgoClientConfigs' @@ -7,8 +8,8 @@ export class InsufficientBalanceError extends Error { public toastMessage: string constructor( - public required: number, - public available: number, + public required: bigint, + public available: bigint, action?: string, ) { const message = action @@ -37,13 +38,13 @@ export class BalanceChecker { }) } - private async getAvailableBalance(): Promise { + private async getAvailableBalance(): Promise { const accountInfo = await this.algodClient.accountInformation(this.address).exclude('all').do() - const availableBalance = Math.max(0, accountInfo.amount - accountInfo['min-balance']) + const availableBalance = BigMath.max(0n, accountInfo.amount - accountInfo.minBalance) return availableBalance } - private async checkAccountBalance(requiredBalance: number, action?: string): Promise { + private async checkAccountBalance(requiredBalance: bigint, action?: string): Promise { const availableBalance = await this.getAvailableBalance() if (availableBalance < requiredBalance) { throw new InsufficientBalanceError(requiredBalance, availableBalance, action) @@ -52,10 +53,10 @@ export class BalanceChecker { public static async check( address: string, - requiredBalance: bigint | number, + requiredBalance: bigint, action?: string, ): Promise { const checker = new BalanceChecker(address) - await checker.checkAccountBalance(Number(requiredBalance), action) + await checker.checkAccountBalance(requiredBalance, action) } } diff --git a/ui/src/utils/bigint.ts b/ui/src/utils/bigint.ts new file mode 100644 index 00000000..08c08fe5 --- /dev/null +++ b/ui/src/utils/bigint.ts @@ -0,0 +1,40 @@ +/** + * Utility object that provides mathematical operations for bigint values, + * mimicking the behavior of the native Math object. + * + * This provides equivalent functionality to Math.min(), Math.max(), and Math.abs() + * but operates on bigint values instead of numbers. + * + * @example + * BigMath.min(5n, 3n, 7n) // returns 3n + * BigMath.max(5n, 3n, 7n) // returns 7n + * BigMath.abs(-5n) // returns 5n + */ +export const BigMath = { + /** + * Returns the smaller of two or more bigint values + */ + min: (...values: bigint[]): bigint => { + if (values.length === 0) { + throw new Error('Cannot find minimum of empty array') + } + return values.reduce((min, val) => (val < min ? val : min)) + }, + + /** + * Returns the larger of two or more bigint values + */ + max: (...values: bigint[]): bigint => { + if (values.length === 0) { + throw new Error('Cannot find maximum of empty array') + } + return values.reduce((max, val) => (val > max ? val : max)) + }, + + /** + * Returns the absolute value of a bigint + */ + abs: (value: bigint): bigint => { + return value < 0n ? -value : value + }, +} diff --git a/ui/src/utils/contracts.ts b/ui/src/utils/contracts.ts index a132f469..3ef27f43 100644 --- a/ui/src/utils/contracts.ts +++ b/ui/src/utils/contracts.ts @@ -4,7 +4,6 @@ import { fetchAccountAssetInformation, fetchAccountInformation } from '@/api/alg import { fetchNfd, fetchNfdSearch } from '@/api/nfd' import { GatingType } from '@/constants/gating' import { Indicator } from '@/constants/indicator' -import { Asset, AssetHolding } from '@/interfaces/algod' import { NfdSearchV2Params } from '@/interfaces/nfd' import { StakerValidatorData } from '@/interfaces/staking' import { LocalPoolInfo, NodeInfo, PoolData, Validator } from '@/interfaces/validator' @@ -120,7 +119,7 @@ interface TransformedGatingAssets { export function transformEntryGatingAssets( type: string, assetIds: Array<{ value: string }>, - assets: Array, + assets: Array, minBalance: string, nfdCreatorAppId: bigint, nfdParentAppId: bigint, @@ -325,7 +324,7 @@ export function canManageValidator(activeAddress: string | null, validator: Vali export async function fetchValueToVerify( validator: Validator | null, activeAddress: string | null, - heldAssets: AssetHolding[], + heldAssets: algosdk.modelsv2.AssetHolding[], ): Promise { if (!validator || !activeAddress) { throw new Error('Validator or active address not found') @@ -338,8 +337,8 @@ export async function fetchValueToVerify( const creatorAddress = entryGatingAddress const accountInfo = await fetchAccountInformation(creatorAddress) - if (accountInfo['created-assets']) { - const assetIds = accountInfo['created-assets'].map((asset) => BigInt(asset.index)) + if (accountInfo.createdAssets) { + const assetIds = accountInfo.createdAssets.map((asset) => BigInt(asset.index)) return findValueToVerify(heldAssets, assetIds, minBalance) } } @@ -357,7 +356,7 @@ export async function fetchValueToVerify( const promises = addresses.map((address) => fetchAccountInformation(address)) const accountsInfo = await Promise.all(promises) const assetIds = accountsInfo - .map((accountInfo) => accountInfo['created-assets']) + .map((accountInfo) => accountInfo.createdAssets) .flat() .filter((asset) => !!asset) .map((asset) => BigInt(asset!.index)) @@ -398,40 +397,40 @@ export async function fetchValueToVerify( * @returns {number} Gating asset ID that meets the minimum balance requirement or 0 if not found */ export function findValueToVerify( - heldAssets: AssetHolding[], + heldAssets: algosdk.modelsv2.AssetHolding[], gatingAssets: bigint[], minBalance: bigint, ): bigint { const asset = heldAssets.find( - (asset) => gatingAssets.includes(BigInt(asset['asset-id'])) && asset.amount >= minBalance, + (asset) => gatingAssets.includes(asset.assetId) && asset.amount >= minBalance, ) - return BigInt(asset?.['asset-id'] || 0n) + return asset?.assetId ?? 0n } /** * Calculate the maximum amount of algo that can be staked based on the validator's configuration * @param {Validator} validator - Validator object * @param {Constraints} constraints - Protocol constraints object - * @returns {number} Maximum amount of algo that can be staked + * @returns {bigint} Maximum amount of algo that can be staked */ export function calculateMaxAvailableToStake( validator: Validator, constraints?: Constraints, -): number { +): bigint { let { maxAlgoPerPool } = validator.config if (maxAlgoPerPool === 0n) { if (!constraints) { - return 0 + return 0n } maxAlgoPerPool = constraints.maxAlgoPerPool } // For each pool, subtract the totalAlgoStaked from maxAlgoPerPool and return the highest value const maxAvailableToStake = validator.pools.reduce((acc, pool) => { - const availableToStake = Number(maxAlgoPerPool) - Number(pool.totalAlgoStaked) + const availableToStake = maxAlgoPerPool - pool.totalAlgoStaked return availableToStake > acc ? availableToStake : acc - }, 0) + }, 0n) return maxAvailableToStake } @@ -516,8 +515,8 @@ export async function fetchRemainingRewardsBalance(validator: Validator): Promis const poolAppId = validator.pools[0].poolAppId const poolAddress = algosdk.getApplicationAddress(poolAppId) - const accountAssetInfo = await fetchAccountAssetInformation(poolAddress, Number(rewardTokenId)) - const rewardTokenAmount = BigInt(accountAssetInfo['asset-holding'].amount) + const accountAssetInfo = await fetchAccountAssetInformation(poolAddress.toString(), rewardTokenId) + const rewardTokenAmount = accountAssetInfo.assetHolding?.amount ?? 0n const remainingBalance = rewardTokenAmount - rewardTokenHeldBack diff --git a/ui/src/utils/development.tsx b/ui/src/utils/development.tsx index 16b56fde..99487c59 100644 --- a/ui/src/utils/development.tsx +++ b/ui/src/utils/development.tsx @@ -42,8 +42,8 @@ export async function incrementRoundNumberBy(rounds: number) { let result = { rounds, - startRound: startParams.firstRound, - resultRound: startParams.firstRound, + startRound: startParams.firstValid, + resultRound: startParams.firstValid, } if (rounds === 0) { @@ -68,16 +68,16 @@ export async function incrementRoundNumberBy(rounds: number) { let txnId = '' for (let i = 0; i < rounds; i++) { const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: testAccount.addr, - to: testAccount.addr, + sender: testAccount.addr, + receiver: testAccount.addr, amount: 0, note: new TextEncoder().encode(`${i}`), suggestedParams: startParams, }) const signedTransaction = await algokit.signTransaction(txn, testAccount) - const { txId } = await algodClient.sendRawTransaction(signedTransaction).do() - txnId = txId + const { txid } = await algodClient.sendRawTransaction(signedTransaction).do() + txnId = txid } await algokit.waitForConfirmation(txnId, rounds + 1, algodClient) @@ -86,7 +86,7 @@ export async function incrementRoundNumberBy(rounds: number) { result = { ...result, - resultRound: resultParams.firstRound, + resultRound: resultParams.firstValid, } // console.log(`Increment round number result: ${result.resultRound}`) @@ -185,8 +185,8 @@ export async function simulateEpoch( const poolKey = pool.poolKey const paymentTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: algosdk.getApplicationAddress(poolKey.poolAppId), + sender: activeAddress, + receiver: algosdk.getApplicationAddress(poolKey.poolAppId), amount: AlgoAmount.Algos(rewardAmount).microAlgos, suggestedParams, }) @@ -213,7 +213,7 @@ export async function simulateEpoch( Simulated {data.rounds} rounds:{' '} - {data.startRound} → {data.resultRound} + {data.startRound.toString()} → {data.resultRound.toString()} ), @@ -257,7 +257,7 @@ export async function sendRewardTokensToPool( try { const tokenId = validator.config.rewardTokenId const asset = await fetchAsset(tokenId) - const unitName = asset.params['unit-name'] + const unitName = asset.params.unitName toast.loading(`Sign to send ${rewardTokenAmount} ${unitName} tokens to pool`, { id: toastId, @@ -271,8 +271,8 @@ export async function sendRewardTokensToPool( const suggestedParams = await ParamsCache.getSuggestedParams() const assetTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ - from: activeAddress, - to: poolAddress, + sender: activeAddress, + receiver: poolAddress, assetIndex: Number(tokenId), amount: convertToBaseUnits(rewardTokenAmount, 6), suggestedParams, @@ -281,8 +281,8 @@ export async function sendRewardTokensToPool( atc.addTransaction({ txn: assetTxn, signer }) await atc.execute(algodClient, 4) - const poolAccountInfo = await fetchAccountInformation(poolAddress) - const assetHolding = poolAccountInfo.assets?.find((a) => a['asset-id'] === Number(tokenId)) + const poolAccountInfo = await fetchAccountInformation(poolAddress.toString()) + const assetHolding = poolAccountInfo.assets?.find((a) => a.assetId === tokenId) const balanceStr = formatAssetAmount(asset, assetHolding?.amount || 0) const balanceMsg = assetHolding?.amount ? `${balanceStr} ${unitName}` : 'unknown' diff --git a/ui/src/utils/explorer.spec.ts b/ui/src/utils/explorer.spec.ts index 8bfd0390..e6774e91 100644 --- a/ui/src/utils/explorer.spec.ts +++ b/ui/src/utils/explorer.spec.ts @@ -29,13 +29,13 @@ describe('ExplorerLink', () => { }) it('should generate correct asset URL using static method', () => { - const id = 12345 + const id = 12345n const expectedUrl = `${mockConfig.assetUrl}/${id}` expect(ExplorerLink.asset(id)).toBe(expectedUrl) }) it('should generate correct app URL using static method', () => { - const id = 67890 + const id = 67890n const expectedUrl = `${mockConfig.appUrl}/${id}` expect(ExplorerLink.app(id)).toBe(expectedUrl) }) diff --git a/ui/src/utils/explorer.ts b/ui/src/utils/explorer.ts index e8c28419..034c75f4 100644 --- a/ui/src/utils/explorer.ts +++ b/ui/src/utils/explorer.ts @@ -36,11 +36,11 @@ export class ExplorerLink { return new ExplorerLink(id).transactionUrl() } - static asset(id: number | bigint) { - return new ExplorerLink(Number(id).toString()).assetUrl() + static asset(id: bigint) { + return new ExplorerLink(id.toString()).assetUrl() } - static app(id: number | bigint) { - return new ExplorerLink(Number(id).toString()).appUrl() + static app(id: bigint) { + return new ExplorerLink(id.toString()).appUrl() } } diff --git a/ui/src/utils/format.spec.ts b/ui/src/utils/format.spec.ts index d4605ec9..01ab1c1e 100644 --- a/ui/src/utils/format.spec.ts +++ b/ui/src/utils/format.spec.ts @@ -1,4 +1,4 @@ -import { Asset } from '@/interfaces/algod' +import algosdk from 'algosdk' import { convertFromBaseUnits, convertToBaseUnits, @@ -158,16 +158,17 @@ describe('formatWithPrecision', () => { }) describe('formatAssetAmount', () => { - const asset: Asset = { - params: { - creator: '', - decimals: 6, - name: 'Test Asset', - total: 1000000, - 'unit-name': 'TEST', - }, - index: 12345, - } + const params = new algosdk.modelsv2.AssetParams({ + creator: '', + decimals: 6, + name: 'Test Asset', + total: 1000000n, + unitName: 'TEST', + }) + const asset = new algosdk.modelsv2.Asset({ + params, + index: 12345n, + }) it('should format asset amount correctly with default options', () => { const result = formatAssetAmount(asset, 1234567890) diff --git a/ui/src/utils/format.ts b/ui/src/utils/format.ts index e29c51db..80eef44b 100644 --- a/ui/src/utils/format.ts +++ b/ui/src/utils/format.ts @@ -1,6 +1,5 @@ +import algosdk from 'algosdk' import Big from 'big.js' -import { Asset } from '@/interfaces/algod' - /** * Convert an asset amount from base units to whole units * @param {number | bigint | string} amount - The amount in base units @@ -197,13 +196,13 @@ type FormatAssetAmountOptions = Omit & { * @see {@link formatAmount} */ export function formatAssetAmount( - asset: Asset, + asset: algosdk.modelsv2.Asset, amount: number | bigint | string, options: FormatAssetAmountOptions = {}, ): string { const { precision, trim, maxLength, compact, unitName } = options const decimals = Number(asset.params.decimals) - const assetUnitName = unitName ? asset.params['unit-name'] : '' + const assetUnitName = unitName ? asset.params.unitName : '' const formatOptions = { precision, trim, maxLength, compact, decimals } diff --git a/ui/src/utils/paramsCache.spec.ts b/ui/src/utils/paramsCache.spec.ts index f0c72a89..2cc40ad2 100644 --- a/ui/src/utils/paramsCache.spec.ts +++ b/ui/src/utils/paramsCache.spec.ts @@ -4,10 +4,10 @@ import { ParamsCache } from '@/utils/paramsCache' const mockParams: algosdk.SuggestedParams = { fee: 1000, - firstRound: 1000, - lastRound: 2000, + minFee: 1000, + firstValid: 1000, + lastValid: 2000, genesisID: 'dockernet-v1', - genesisHash: 'v1lkQZYrxQn1XDRkIAlsUrSSECXU6OFMbPMhj/QQ9dk=', } // Mock getTransactionParams diff --git a/ui/src/utils/table.ts b/ui/src/utils/table.ts index 6d695398..9f39e932 100644 --- a/ui/src/utils/table.ts +++ b/ui/src/utils/table.ts @@ -18,7 +18,7 @@ export const globalFilterFn: FilterFn = (row, columnId, filterValue) const rewardToken = validator.rewardToken if (rewardToken) { const tokenId = rewardToken.index.toString() - const { name, 'unit-name': unitName } = rewardToken.params + const { name, unitName } = rewardToken.params const tokenName = name?.toLowerCase() ?? '' const tokenUnitName = unitName?.toLowerCase() ?? '' @@ -31,9 +31,7 @@ export const globalFilterFn: FilterFn = (row, columnId, filterValue) if (gatingAssets) { const assetIds = gatingAssets.map((asset) => asset.index.toString()) const assetNames = gatingAssets.map((asset) => asset.params.name?.toLowerCase() ?? '') - const assetUnitnames = gatingAssets.map( - (asset) => asset.params['unit-name']?.toLowerCase() ?? '', - ) + const assetUnitnames = gatingAssets.map((asset) => asset.params.unitName?.toLowerCase() ?? '') if (assetIds.some((id) => id === search)) return true if (assetNames.some((name) => name.includes(search))) return true diff --git a/ui/src/utils/tests/msw/handlers.ts b/ui/src/utils/tests/msw/handlers.ts index ee85c122..3a678c7f 100644 --- a/ui/src/utils/tests/msw/handlers.ts +++ b/ui/src/utils/tests/msw/handlers.ts @@ -1,9 +1,8 @@ import * as msgpack from 'algo-msgpack-with-bigint' -import { ABIMethod, ABIType, getMethodByName } from 'algosdk' +import algosdk, { ABIMethod, ABIType, getMethodByName } from 'algosdk' import { HttpResponse, http } from 'msw' import { APP_SPEC as ValidatorRegistrySpec } from '@/contracts/ValidatorRegistryClient' import { Application, BlockHeader } from '@/interfaces/algod' -import { SimulateRequest, SimulateResponse } from '@/interfaces/simulate' import { concatUint8Arrays } from '@/utils/bytes' import { MethodCallParams } from '@/utils/tests/abi' import { @@ -109,10 +108,12 @@ const handlers = [ /* Inspect request */ const requestBody = await request.arrayBuffer() - const decodedRequest = msgpack.decode(new Uint8Array(requestBody)) as SimulateRequest + const decodedRequest = msgpack.decode( + new Uint8Array(requestBody), + ) as algosdk.modelsv2.SimulateRequest // console.log('decodedRequest', decodedRequest) - const txns = decodedRequest['txn-groups'][0].txns + const txns = decodedRequest.txnGroups[0].txns const txn = txns[0] if (!txn.txn.note) { @@ -140,7 +141,8 @@ const handlers = [ const returnValue = returnType.encode(fixtureData) const returnLogs = [concatUint8Arrays(RETURN_PREFIX, returnValue)] - const mockResponse: SimulateResponse = { + // algosdk.modelsv2.SimulateResponse + const mockResponse = { 'last-round': LAST_ROUND, version: 2, 'txn-groups': [ diff --git a/ui/src/utils/validation.ts b/ui/src/utils/validation.ts index a59aad52..1156b6b8 100644 --- a/ui/src/utils/validation.ts +++ b/ui/src/utils/validation.ts @@ -3,7 +3,6 @@ import algosdk from 'algosdk' import { RefinementCtx, z } from 'zod' import { ALGORAND_ZERO_ADDRESS_STRING } from '@/constants/accounts' import { GatingType } from '@/constants/gating' -import { Asset } from '@/interfaces/algod' import { convertToBaseUnits } from '@/utils/format' import { isValidName, isValidRoot } from '@/utils/nfd' import { Constraints } from '@/contracts/ValidatorRegistryClient' @@ -283,7 +282,7 @@ export const entryGatingRefinement = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any data: any, ctx: RefinementCtx, - assets: Array, + assets: Array, ) => { const { entryGatingType, @@ -444,7 +443,7 @@ export const entryGatingRefinement = ( message: 'Invalid minimum balance', }) } else { - const asset = assets.find((asset) => asset?.index === Number(entryGatingAssets[0].value)) + const asset = assets.find((asset) => asset?.index === entryGatingAssets[0].value) if (asset) { const minBalanceBaseUnits = convertToBaseUnits( gatingAssetMinBalance, @@ -454,7 +453,7 @@ export const entryGatingRefinement = ( ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['gatingAssetMinBalance'], - message: `Minimum balance cannot exceed ${asset.params['unit-name'] || 'gating asset'} total supply`, + message: `Minimum balance cannot exceed ${asset.params.unitName || 'gating asset'} total supply`, }) } }