diff --git a/docs/node/CATEGORIES/11-masternode.md b/docs/node/CATEGORIES/11-masternode.md index 340f62e365..4bc8e53582 100644 --- a/docs/node/CATEGORIES/11-masternode.md +++ b/docs/node/CATEGORIES/11-masternode.md @@ -206,6 +206,16 @@ interface masternode { } ``` +## isAppliedCustomTransaction + +Checks that custom transaction was affected on chain + +```ts title="client.masternode.isAppliedCustomTransaction()" +interface masternode { + isAppliedCustomTransaction (transactionId: string, blockHeight: number): Promise +} +``` + ## getAnchorTeams Returns the auth and confirm anchor masternode teams at current or specified height diff --git a/packages/jellyfish-api-core/__tests__/category/masternode/isAppliedCustomTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/masternode/isAppliedCustomTransaction.test.ts new file mode 100644 index 0000000000..f346954767 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/masternode/isAppliedCustomTransaction.test.ts @@ -0,0 +1,101 @@ +import { Testing } from '@defichain/jellyfish-testing' +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import { RpcApiError } from '@defichain/jellyfish-api-core' + +describe('Masternode', () => { + const testing = Testing.create(new MasterNodeRegTestContainer()) + + beforeAll(async () => { + await testing.container.start() + await testing.container.waitForWalletCoinbaseMaturity() + }) + + afterAll(async () => { + await testing.container.stop() + }) + + it('should be passed while using valid id and height', async () => { + const goldAddress = await testing.container.getNewAddress('', 'legacy') + const goldMetadata = { + symbol: 'GOLD', + name: 'shiny gold', + isDAT: false, + mintable: true, + tradeable: true, + collateralAddress: goldAddress + } + const goldTokenId = await testing.rpc.token.createToken(goldMetadata) + await testing.generate(1) + const goldHeight = await testing.rpc.blockchain.getBlockCount() + + const silverAddress = await testing.container.getNewAddress('', 'legacy') + const silverMetadata = { + symbol: 'SILVER', + name: 'just silver', + isDAT: false, + mintable: true, + tradeable: true, + collateralAddress: silverAddress + } + const silverTokenId = await testing.rpc.token.createToken(silverMetadata) + await testing.generate(1) + const silverHeight = await testing.rpc.blockchain.getBlockCount() + + const copperAddress = await testing.container.getNewAddress('', 'legacy') + const copperMetadata = { + symbol: 'COPPER', + name: 'just copper', + isDAT: false, + mintable: true, + tradeable: true, + collateralAddress: copperAddress + } + const copperTokenId = await testing.rpc.token.createToken(copperMetadata) + await testing.generate(1) + const copperHeight = await testing.rpc.blockchain.getBlockCount() + + const goldResult = await testing.rpc.masternode.isAppliedCustomTransaction(goldTokenId, goldHeight) + expect(goldResult).toStrictEqual(true) + + const silverResult = await testing.rpc.masternode.isAppliedCustomTransaction(silverTokenId, silverHeight) + expect(silverResult).toStrictEqual(true) + + const copperResult = await testing.rpc.masternode.isAppliedCustomTransaction(copperTokenId, copperHeight) + expect(copperResult).toStrictEqual(true) + }) + + it('should be failed while using invalid height', async () => { + const brassAddress = await testing.container.getNewAddress('', 'legacy') + const brassMetadata = { + symbol: 'BRASS', + name: 'shiny brass', + isDAT: false, + mintable: true, + tradeable: true, + collateralAddress: brassAddress + } + const brassTokenId = await testing.rpc.token.createToken(brassMetadata) + await testing.generate(1) + const brassHeight = await testing.rpc.blockchain.getBlockCount() + + const brassResult = await testing.rpc.masternode.isAppliedCustomTransaction(brassTokenId, brassHeight + 1) + expect(brassResult).toStrictEqual(false) + }) + + it('should be failed while using invalid id', async () => { + const blockHeight = await testing.rpc.blockchain.getBlockCount() + + const result = await testing.rpc.masternode.isAppliedCustomTransaction('b2bb09ffe9f9b292f13d23bafa1225ef26d0b9906da7af194c5738b63839b235', blockHeight) + expect(result).toStrictEqual(false) + + // Hex hash id with 63 chars + let promise = testing.rpc.masternode.isAppliedCustomTransaction('2bb09ffe9f9b292f13d23bafa1225ef26d0b9906da7af194c5738b63839b235', blockHeight) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('txid must be of length 64') + + // Invalid hash id with a non hex char + promise = testing.rpc.masternode.isAppliedCustomTransaction('b2bb09ffe9f9b292f13d23bafa1225ef26d0b9906da7af194c5738b63839b23z', blockHeight) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('txid must be hexadecimal string') + }) +}) diff --git a/packages/jellyfish-api-core/src/category/masternode.ts b/packages/jellyfish-api-core/src/category/masternode.ts index c197471f3c..e685cc8c23 100644 --- a/packages/jellyfish-api-core/src/category/masternode.ts +++ b/packages/jellyfish-api-core/src/category/masternode.ts @@ -198,6 +198,17 @@ export class Masternode { return await this.client.call('listgovs', [], 'bignumber') } + /** + * Checks that custom transaction was affected on chain + * + * @param {string} transactionId transaction hash + * @param {number} blockHeight height of block which contain transaction + * @return {Promise} indicate that custom transaction was affected on chain + */ + async isAppliedCustomTransaction (transactionId: string, blockHeight: number): Promise { + return await this.client.call('isappliedcustomtx', [transactionId, blockHeight], 'number') + } + /** * Returns the auth and confirm anchor masternode teams at current or specified height *