From cd327abd5cbb660317449214ce267674802ce88e Mon Sep 17 00:00:00 2001 From: Pegasus <83475418+0xp3gasus@users.noreply.github.com> Date: Mon, 17 Jun 2024 09:24:21 +0200 Subject: [PATCH] Get MAYANames by owner (#1195) * Get MAYANames by address * Changeset version file --- .changeset/brown-fireants-bow.md | 6 +++ .changeset/thick-ants-work.md | 5 +++ .../__mocks__/midgard-api/midgard-api.ts | 4 ++ .../midgard-api/responses/owner.json | 3 ++ .../__tests__/mayachainAMM.test.ts | 42 +++++++++++++++++++ .../xchain-mayachain-amm/src/mayachain-amm.ts | 22 +++++++++- .../__e2e__/mayachain-estimateSwap.e2e.ts | 17 ++++++++ .../__mocks__/midgard-api.ts | 8 ++++ .../__mocks__/responses/midgard/mayaname.json | 30 +++++++++++++ .../__mocks__/responses/midgard/owner.json | 3 ++ .../__tests__/mayachain-query.test.ts | 42 +++++++++++++++++++ .../src/mayachain-query.ts | 25 +++++++++-- packages/xchain-mayachain-query/src/types.ts | 3 ++ 13 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 .changeset/brown-fireants-bow.md create mode 100644 .changeset/thick-ants-work.md create mode 100644 packages/xchain-mayachain-amm/__mocks__/midgard-api/responses/owner.json create mode 100644 packages/xchain-mayachain-query/__mocks__/responses/midgard/mayaname.json create mode 100644 packages/xchain-mayachain-query/__mocks__/responses/midgard/owner.json diff --git a/.changeset/brown-fireants-bow.md b/.changeset/brown-fireants-bow.md new file mode 100644 index 000000000..06b81b6a0 --- /dev/null +++ b/.changeset/brown-fireants-bow.md @@ -0,0 +1,6 @@ +--- +'@xchainjs/xchain-mayachain-query': patch +'@xchainjs/xchain-mayachain-amm': patch +--- + +New method `getMAYANamesByOwner` to retrieve the MAYANames owned by an address diff --git a/.changeset/thick-ants-work.md b/.changeset/thick-ants-work.md new file mode 100644 index 000000000..9730f6427 --- /dev/null +++ b/.changeset/thick-ants-work.md @@ -0,0 +1,5 @@ +--- +'@xchainjs/xchain-mayachain-amm': patch +--- + +New method `getMAYANameDetails` to retrieve the details of a certain MAYAName. diff --git a/packages/xchain-mayachain-amm/__mocks__/midgard-api/midgard-api.ts b/packages/xchain-mayachain-amm/__mocks__/midgard-api/midgard-api.ts index f879c88b5..5b9af9797 100644 --- a/packages/xchain-mayachain-amm/__mocks__/midgard-api/midgard-api.ts +++ b/packages/xchain-mayachain-amm/__mocks__/midgard-api/midgard-api.ts @@ -16,5 +16,9 @@ export default { } return [404, 'Not found'] }) + mock.onGet(/\/v2\/mayaname\/rlookup\/maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09/).reply(function () { + const resp = require(`./responses/owner.json`) + return [200, resp] + }) }, } diff --git a/packages/xchain-mayachain-amm/__mocks__/midgard-api/responses/owner.json b/packages/xchain-mayachain-amm/__mocks__/midgard-api/responses/owner.json new file mode 100644 index 000000000..d4b52cc5f --- /dev/null +++ b/packages/xchain-mayachain-amm/__mocks__/midgard-api/responses/owner.json @@ -0,0 +1,3 @@ +[ + "eld" +] \ No newline at end of file diff --git a/packages/xchain-mayachain-amm/__tests__/mayachainAMM.test.ts b/packages/xchain-mayachain-amm/__tests__/mayachainAMM.test.ts index d9452d787..79beb646c 100644 --- a/packages/xchain-mayachain-amm/__tests__/mayachainAMM.test.ts +++ b/packages/xchain-mayachain-amm/__tests__/mayachainAMM.test.ts @@ -188,4 +188,46 @@ describe('Mayachain Client Test', () => { expect(quoteSwap.errors[0]).toBe('affiliateAddress randomAffiliateAddress is not a valid MAYA address') expect(quoteSwap.warning).toBe('') }) + + it('Should get MAYAName details', async () => { + const details = await mayachainAmm.getMAYANameDetails('eld') + expect(details).toBeTruthy() + expect(details?.name).toBe('eld') + expect(details?.expire).toBe('66751601') + expect(details?.owner).toBe('maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09') + expect(details?.entries.length).toBe(6) + expect(details?.entries[0].address).toBe('bc1qdjqcm3fsadjn9zth9wk30gy5su6hkwkhfr0re9') + expect(details?.entries[0].chain).toBe('BTC') + expect(details?.entries[1].address).toBe('XiKv7A7vVQmYwNUp4TjCq8ZamkjB8zZtsL') + expect(details?.entries[1].chain).toBe('DASH') + expect(details?.entries[2].address).toBe('0x1509b1fe69be4d508a62ce8109635e1d1cf29a4f') + expect(details?.entries[2].chain).toBe('ETH') + expect(details?.entries[3].address).toBe('kujira1mg9jt63eeww5ptnkw963z2sw6jzezxw0trns50') + expect(details?.entries[3].chain).toBe('KUJI') + expect(details?.entries[4].address).toBe('maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09') + expect(details?.entries[4].chain).toBe('MAYA') + expect(details?.entries[5].address).toBe('thor1gnehec7mf4uytuw3wj4uwpptvkyvzclgqap7e4') + expect(details?.entries[5].chain).toBe('THOR') + }) + + it('Should get the MAYAnames owned by an address', async () => { + const mayaNames = await mayachainAmm.getMAYANamesByOwner('maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09') + expect(mayaNames.length).toBe(1) + expect(mayaNames[0]?.name).toBe('eld') + expect(mayaNames[0]?.expire).toBe('66751601') + expect(mayaNames[0]?.owner).toBe('maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09') + expect(mayaNames[0]?.entries.length).toBe(6) + expect(mayaNames[0]?.entries[0].address).toBe('bc1qdjqcm3fsadjn9zth9wk30gy5su6hkwkhfr0re9') + expect(mayaNames[0]?.entries[0].chain).toBe('BTC') + expect(mayaNames[0]?.entries[1].address).toBe('XiKv7A7vVQmYwNUp4TjCq8ZamkjB8zZtsL') + expect(mayaNames[0]?.entries[1].chain).toBe('DASH') + expect(mayaNames[0]?.entries[2].address).toBe('0x1509b1fe69be4d508a62ce8109635e1d1cf29a4f') + expect(mayaNames[0]?.entries[2].chain).toBe('ETH') + expect(mayaNames[0]?.entries[3].address).toBe('kujira1mg9jt63eeww5ptnkw963z2sw6jzezxw0trns50') + expect(mayaNames[0]?.entries[3].chain).toBe('KUJI') + expect(mayaNames[0]?.entries[4].address).toBe('maya1gnehec7mf4uytuw3wj4uwpptvkyvzclgq2lj09') + expect(mayaNames[0]?.entries[4].chain).toBe('MAYA') + expect(mayaNames[0]?.entries[5].address).toBe('thor1gnehec7mf4uytuw3wj4uwpptvkyvzclgqap7e4') + expect(mayaNames[0]?.entries[5].chain).toBe('THOR') + }) }) diff --git a/packages/xchain-mayachain-amm/src/mayachain-amm.ts b/packages/xchain-mayachain-amm/src/mayachain-amm.ts index c01ad2889..b00bc631d 100644 --- a/packages/xchain-mayachain-amm/src/mayachain-amm.ts +++ b/packages/xchain-mayachain-amm/src/mayachain-amm.ts @@ -8,9 +8,9 @@ import { AssetETH, Client as EthClient, defaultEthParams } from '@xchainjs/xchai import { MAX_APPROVAL, abi } from '@xchainjs/xchain-evm' import { Client as KujiraClient, defaultKujiParams } from '@xchainjs/xchain-kujira' import { Client as MayaClient, MAYAChain } from '@xchainjs/xchain-mayachain' -import { MayachainQuery, QuoteSwap, QuoteSwapParams } from '@xchainjs/xchain-mayachain-query' +import { MAYANameDetails, MayachainQuery, QuoteSwap, QuoteSwapParams } from '@xchainjs/xchain-mayachain-query' import { Client as ThorClient } from '@xchainjs/xchain-thorchain' -import { Asset, CryptoAmount, baseAmount, eqAsset, getContractAddressFromAsset } from '@xchainjs/xchain-util' +import { Address, Asset, CryptoAmount, baseAmount, eqAsset, getContractAddressFromAsset } from '@xchainjs/xchain-util' import { Wallet } from '@xchainjs/xchain-wallet' import { ethers } from 'ethers' @@ -235,6 +235,24 @@ export class MayachainAMM { return errors } + /** + * Get MAYAname details + * @param {string} MAYAName + * @returns {MAYANameDetails | undefined} MAYANames details or undefined it is does not exist + */ + public async getMAYANameDetails(MAYAName: string): Promise { + return this.mayachainQuery.getMAYANameDetails(MAYAName) + } + + /** + * Get the MAYANames owned by an address + * @param {Address} owner - Thorchain address + * @returns {MAYANameDetails[]} List of MAYANames owned by the address + */ + public async getMAYANamesByOwner(owner: Address): Promise { + return this.mayachainQuery.getMAYANamesByOwner(owner) + } + /** * Check if a name is a valid MAYAName * @param {string} name MAYAName to check diff --git a/packages/xchain-mayachain-query/__e2e__/mayachain-estimateSwap.e2e.ts b/packages/xchain-mayachain-query/__e2e__/mayachain-estimateSwap.e2e.ts index 3adaca32c..a8b774b6b 100644 --- a/packages/xchain-mayachain-query/__e2e__/mayachain-estimateSwap.e2e.ts +++ b/packages/xchain-mayachain-query/__e2e__/mayachain-estimateSwap.e2e.ts @@ -91,4 +91,21 @@ describe('Estimate swap e2e tests', () => { const estimate = await mayachainQuery.quoteSwap(swapParams) printQuoteSwap(estimate) }) + + it('Get MAYANames by owner', async () => { + const mayaNames = await mayachainQuery.getMAYANamesByOwner('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + mayaNames.forEach((mayaName) => { + console.log({ + name: mayaName.name, + owner: mayaName.owner, + expire: mayaName.expire, + entries: mayaName.entries.map((entry) => { + return { + address: entry.address, + chain: entry.chain, + } + }), + }) + }) + }) }) diff --git a/packages/xchain-mayachain-query/__mocks__/midgard-api.ts b/packages/xchain-mayachain-query/__mocks__/midgard-api.ts index 33aedf839..086824e6c 100644 --- a/packages/xchain-mayachain-query/__mocks__/midgard-api.ts +++ b/packages/xchain-mayachain-query/__mocks__/midgard-api.ts @@ -8,5 +8,13 @@ export default { const resp = require(`./responses/midgard/actions.json`) return [200, resp] }) + mock.onGet(/\/v2\/mayaname\/lookup\/eld/).reply(function () { + const resp = require(`./responses/midgard/mayaname.json`) + return [200, resp] + }) + mock.onGet(/\/v2\/mayaname\/rlookup\/maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn/).reply(function () { + const resp = require(`./responses/midgard/owner.json`) + return [200, resp] + }) }, } diff --git a/packages/xchain-mayachain-query/__mocks__/responses/midgard/mayaname.json b/packages/xchain-mayachain-query/__mocks__/responses/midgard/mayaname.json new file mode 100644 index 000000000..824800034 --- /dev/null +++ b/packages/xchain-mayachain-query/__mocks__/responses/midgard/mayaname.json @@ -0,0 +1,30 @@ +{ + "entries": [ + { + "address": "bc1qvqxs558vgquwkchw64erd5hfpxfj5kmn7lyklz", + "chain": "BTC" + }, + { + "address": "XgYRN3TLoYaodB5Y6AMZuYhjv8fKKG5tgh", + "chain": "DASH" + }, + { + "address": "0x7316da75796f74e83b71c72ed6f138dd3b6b4957", + "chain": "ETH" + }, + { + "address": "kujira1x8z69wuczjk42l22c3u6qzzd5vdeqdyhwkv84v", + "chain": "KUJI" + }, + { + "address": "maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn", + "chain": "MAYA" + }, + { + "address": "thor13x0f2r0jltfplmxe40cc67hhca27np34e495yr", + "chain": "THOR" + } + ], + "expire": "66754201", + "owner": "maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn" +} \ No newline at end of file diff --git a/packages/xchain-mayachain-query/__mocks__/responses/midgard/owner.json b/packages/xchain-mayachain-query/__mocks__/responses/midgard/owner.json new file mode 100644 index 000000000..d4b52cc5f --- /dev/null +++ b/packages/xchain-mayachain-query/__mocks__/responses/midgard/owner.json @@ -0,0 +1,3 @@ +[ + "eld" +] \ No newline at end of file diff --git a/packages/xchain-mayachain-query/__tests__/mayachain-query.test.ts b/packages/xchain-mayachain-query/__tests__/mayachain-query.test.ts index 6d5635e3f..5e68bb0cc 100644 --- a/packages/xchain-mayachain-query/__tests__/mayachain-query.test.ts +++ b/packages/xchain-mayachain-query/__tests__/mayachain-query.test.ts @@ -158,4 +158,46 @@ describe('Mayachain-query tests', () => { }, }) }) + + it('Should get MAYAName details', async () => { + const details = await mayachainQuery.getMAYANameDetails('eld') + expect(details).toBeTruthy() + expect(details?.name).toBe('eld') + expect(details?.expire).toBe('66754201') + expect(details?.owner).toBe('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + expect(details?.entries.length).toBe(6) + expect(details?.entries[0].address).toBe('bc1qvqxs558vgquwkchw64erd5hfpxfj5kmn7lyklz') + expect(details?.entries[0].chain).toBe('BTC') + expect(details?.entries[1].address).toBe('XgYRN3TLoYaodB5Y6AMZuYhjv8fKKG5tgh') + expect(details?.entries[1].chain).toBe('DASH') + expect(details?.entries[2].address).toBe('0x7316da75796f74e83b71c72ed6f138dd3b6b4957') + expect(details?.entries[2].chain).toBe('ETH') + expect(details?.entries[3].address).toBe('kujira1x8z69wuczjk42l22c3u6qzzd5vdeqdyhwkv84v') + expect(details?.entries[3].chain).toBe('KUJI') + expect(details?.entries[4].address).toBe('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + expect(details?.entries[4].chain).toBe('MAYA') + expect(details?.entries[5].address).toBe('thor13x0f2r0jltfplmxe40cc67hhca27np34e495yr') + expect(details?.entries[5].chain).toBe('THOR') + }) + + it('Should get the MAYAnames owned by an address', async () => { + const mayaNames = await mayachainQuery.getMAYANamesByOwner('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + expect(mayaNames.length).toBe(1) + expect(mayaNames[0]?.name).toBe('eld') + expect(mayaNames[0]?.expire).toBe('66754201') + expect(mayaNames[0]?.owner).toBe('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + expect(mayaNames[0]?.entries.length).toBe(6) + expect(mayaNames[0]?.entries[0].address).toBe('bc1qvqxs558vgquwkchw64erd5hfpxfj5kmn7lyklz') + expect(mayaNames[0]?.entries[0].chain).toBe('BTC') + expect(mayaNames[0]?.entries[1].address).toBe('XgYRN3TLoYaodB5Y6AMZuYhjv8fKKG5tgh') + expect(mayaNames[0]?.entries[1].chain).toBe('DASH') + expect(mayaNames[0]?.entries[2].address).toBe('0x7316da75796f74e83b71c72ed6f138dd3b6b4957') + expect(mayaNames[0]?.entries[2].chain).toBe('ETH') + expect(mayaNames[0]?.entries[3].address).toBe('kujira1x8z69wuczjk42l22c3u6qzzd5vdeqdyhwkv84v') + expect(mayaNames[0]?.entries[3].chain).toBe('KUJI') + expect(mayaNames[0]?.entries[4].address).toBe('maya13x0f2r0jltfplmxe40cc67hhca27np34ezmcjn') + expect(mayaNames[0]?.entries[4].chain).toBe('MAYA') + expect(mayaNames[0]?.entries[5].address).toBe('thor13x0f2r0jltfplmxe40cc67hhca27np34e495yr') + expect(mayaNames[0]?.entries[5].chain).toBe('THOR') + }) }) diff --git a/packages/xchain-mayachain-query/src/mayachain-query.ts b/packages/xchain-mayachain-query/src/mayachain-query.ts index ba52f60b5..08b860176 100644 --- a/packages/xchain-mayachain-query/src/mayachain-query.ts +++ b/packages/xchain-mayachain-query/src/mayachain-query.ts @@ -1,8 +1,8 @@ import { Network } from '@xchainjs/xchain-client' import { PoolDetail, Transaction } from '@xchainjs/xchain-mayamidgard' -import { MAYANameDetails } from '@xchainjs/xchain-mayamidgard-query' import { QuoteSwapResponse } from '@xchainjs/xchain-mayanode' import { + Address, Asset, CryptoAmount, assetFromStringEx, @@ -13,7 +13,7 @@ import { } from '@xchainjs/xchain-util' import { MayachainCache } from './mayachain-cache' -import { InboundDetail, QuoteSwap, QuoteSwapParams, SwapHistoryParams, SwapsHistory } from './types' +import { InboundDetail, MAYANameDetails, QuoteSwap, QuoteSwapParams, SwapHistoryParams, SwapsHistory } from './types' import { ArbAsset, ArbChain, @@ -193,7 +193,10 @@ export class MayachainQuery { * @returns {MAYANameDetails | undefined} MAYANames details or undefined it is does not exist */ public async getMAYANameDetails(MAYAName: string): Promise { - return this.mayachainCache.midgardQuery.getMAYANameDetails(MAYAName) + const details = await this.mayachainCache.midgardQuery.getMAYANameDetails(MAYAName) + if (!details) return undefined + + return { ...details, name: MAYAName } } /** @@ -285,4 +288,20 @@ export class MayachainQuery { }), } } + + /** + * Get the MAYANames owned by an address + * @param {Address} owner - Thorchain address + * @returns {MAYANameDetails[]} List of MAYANames owned by the address + */ + public async getMAYANamesByOwner(owner: Address): Promise { + const mayaNames = await this.mayachainCache.midgardQuery.getMAYANameReverseLookup(owner) + + if (!mayaNames || mayaNames.length === 0) return [] + + const tasks = mayaNames.map((mayaName) => this.getMAYANameDetails(mayaName)) + + const mayaNamesDetails = await Promise.all(tasks) + return mayaNamesDetails.filter((mayaNameDetails) => mayaNameDetails !== undefined) as MAYANameDetails[] + } } diff --git a/packages/xchain-mayachain-query/src/types.ts b/packages/xchain-mayachain-query/src/types.ts index 49a76dc06..36cbd94d9 100644 --- a/packages/xchain-mayachain-query/src/types.ts +++ b/packages/xchain-mayachain-query/src/types.ts @@ -1,7 +1,10 @@ import { TxHash } from '@xchainjs/xchain-client' +import { MAYANameDetails as BaseMAYANameDetails } from '@xchainjs/xchain-mayamidgard-query' import { Address, Asset, Chain, CryptoAmount } from '@xchainjs/xchain-util' import { BigNumber } from 'bignumber.js' +export type MAYANameDetails = BaseMAYANameDetails & { name: string } + /** * Represents fees associated with a swap. */