Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge master #1085

Merged
merged 12 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/cardano-services-client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.17.3](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

**Note:** Version bump only for package @cardano-sdk/cardano-services-client

## [0.17.2](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

**Note:** Version bump only for package @cardano-sdk/cardano-services-client
Expand Down
2 changes: 1 addition & 1 deletion packages/cardano-services-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cardano-sdk/cardano-services-client",
"version": "0.17.2",
"version": "0.17.3",
"description": "Cardano Services Client",
"engines": {
"node": ">=16.20.2"
Expand Down
4 changes: 4 additions & 0 deletions packages/cardano-services/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.25.4](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

**Note:** Version bump only for package @cardano-sdk/cardano-services

## [0.25.3](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

**Note:** Version bump only for package @cardano-sdk/cardano-services
Expand Down
2 changes: 1 addition & 1 deletion packages/cardano-services/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cardano-sdk/cardano-services",
"version": "0.25.3",
"version": "0.25.4",
"description": "Cardano GraphQL Services",
"engines": {
"node": ">=16.20.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export class ChainHistoryBuilder {
public async queryTransactionInputsByIds(ids: string[], collateral = false): Promise<TxInput[]> {
this.#logger.debug(`About to find inputs (collateral: ${collateral}) for transactions with ids:`, ids);
const result: QueryResult<TxInputModel> = await this.#db.query({
name: `tx_${collateral ? 'collateral' : 'inputs'}_by_tx_ids`,
name: `tx_${collateral ? 'collateral_' : ''}inputs_by_tx_ids`,
text: collateral ? Queries.findTxCollateralsByIds : Queries.findTxInputsByIds,
values: [ids]
});
Expand All @@ -217,11 +217,11 @@ export class ChainHistoryBuilder {
return mapTxOutTokenMap(result.rows);
}

public async queryTransactionOutputsByIds(ids: string[]): Promise<TxOutput[]> {
this.#logger.debug('About to find outputs for transactions with ids:', ids);
public async queryTransactionOutputsByIds(ids: string[], collateral = false): Promise<TxOutput[]> {
this.#logger.debug(`About to find outputs (collateral: ${collateral}) for transactions with ids:`, ids);
const result: QueryResult<TxOutputModel> = await this.#db.query({
name: 'tx_outputs_by_tx_ids',
text: Queries.findTxOutputsByIds,
name: `tx_${collateral ? 'collateral_' : ''}outputs_by_tx_ids`,
text: collateral ? Queries.findCollateralOutputsByTxIds : Queries.findTxOutputsByIds,
values: [ids]
});
if (result.rows.length === 0) return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export class DbSyncChainHistoryProvider extends DbSyncProvider() implements Chai
metadata,
collaterals,
certificates,
collateralOutputs,
votingProcedures,
proposalProcedures
] = await Promise.all([
Expand All @@ -128,6 +129,7 @@ export class DbSyncChainHistoryProvider extends DbSyncProvider() implements Chai
this.#metadataService.queryTxMetadataByRecordIds(ids),
this.#builder.queryTransactionInputsByIds(ids, true),
this.#builder.queryCertificatesByIds(ids),
this.#builder.queryTransactionOutputsByIds(ids, true),
this.#builder.queryVotingProceduresByIds(ids),
this.#builder.queryProposalProceduresByIds(ids)
]);
Expand All @@ -137,12 +139,16 @@ export class DbSyncChainHistoryProvider extends DbSyncProvider() implements Chai
const txInputs = orderBy(inputs.filter((input) => input.txInputId === txId).map(mapTxIn), ['index']);
const txCollaterals = orderBy(collaterals.filter((col) => col.txInputId === txId).map(mapTxIn), ['index']);
const txOutputs = orderBy(outputs.filter((output) => output.txId === txId).map(mapTxOut), ['index']);
const txCollateralOutputs = orderBy(collateralOutputs.filter((output) => output.txId === txId).map(mapTxOut), [
'index'
]);
const inputSource: Cardano.InputSource = tx.valid_contract
? Cardano.InputSource.inputs
: Cardano.InputSource.collaterals;

return mapTxAlonzo(tx, {
certificates: certificates.get(txId),
collateralOutputs: txCollateralOutputs,
collaterals: txCollaterals,
inputSource,
inputs: txInputs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ interface TxAlonzoData {
metadata?: Cardano.TxMetadata;
collaterals?: Cardano.HydratedTxIn[];
certificates?: Cardano.Certificate[];
collateralOutputs?: Cardano.TxOut[];
proposalProcedures?: Cardano.ProposalProcedure[];
votingProcedures?: Cardano.VotingProcedures;
}
Expand All @@ -374,6 +375,7 @@ export const mapTxAlonzo = (
{
certificates,
collaterals,
collateralOutputs = [],
inputSource,
inputs,
metadata,
Expand All @@ -398,6 +400,7 @@ export const mapTxAlonzo = (
},
body: {
certificates,
collateralReturn: collateralOutputs.length > 0 ? collateralOutputs[0] : undefined,
collaterals,
fee: BigInt(txModel.fee),
inputs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ const selectTxInput = (collateral?: boolean) => `
JOIN tx AS source_tx
ON tx_out.tx_id = source_tx.id`;

const selectTxOutput = `
const selectTxOutput = (collateral = false) => `
SELECT
tx_out.id AS id,
tx_out.address AS address,
tx_out."index" AS "index",
tx_out.value AS coin_value,
tx_out.data_hash AS datum,
tx.hash AS tx_id
FROM tx_out
FROM ${collateral ? 'collateral_tx_out' : 'tx_out'} AS tx_out
JOIN tx ON tx_out.tx_id = tx.id`;

export const findTxInputsByIds = `
Expand All @@ -45,18 +45,23 @@ export const findTxInputsByAddresses = `
ORDER BY tx_in.id ASC`;

export const findTxOutputsByIds = `
${selectTxOutput}
${selectTxOutput()}
WHERE tx.id = ANY($1)
ORDER BY tx_out.id ASC`;

export const findTxOutputsByAddresses = `
${selectTxOutput}
${selectTxOutput()}
JOIN block ON tx.block_id = block.id
WHERE tx_out.address = ANY($1)
AND block.block_no >= $2
AND block.block_no <= $3
ORDER BY tx_out.id ASC`;

export const findCollateralOutputsByTxIds = `
${selectTxOutput(true)}
WHERE tx.id = ANY($1)
ORDER BY tx_out.id ASC`;

export const findTip = `
SELECT
block_no,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,17 @@ describe('ChainHistoryHttpService', () => {
expect(tx.body.collaterals?.length).toEqual(1);
});

// TODO LW-9182 REMOVE SKIP
it.skip('has collateral outputs', async () => {
const response = await provider.transactionsByHashes({
ids: await fixtureBuilder.getTxHashes(1, { with: [TxWith.CollateralOutput] })
});
const tx: Cardano.HydratedTx = response[0];
expect(response.length).toEqual(1);

expect(tx.body.collateralReturn).toMatchShapeOf(DataMocks.Tx.collateralReturn);
});

it('has certificates', async () => {
const response = await provider.transactionsByHashes({
ids: await fixtureBuilder.getTxHashes(2, { with: [TxWith.DelegationCertificate] })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('ChainHistoryBuilder', () => {
const result = await builder.queryTransactionOutputsByIds(ids);
expect(result.length).toBeGreaterThanOrEqual(2);
expect(result[0]).toMatchShapeOf(DataMocks.Tx.txOut);
checkLoggedTxIds('About to find outputs for transactions with ids', true);
checkLoggedTxIds('About to find outputs \\(collateral: false\\) for transactions with ids', true);
});
test('query transaction outputs with empty array', async () => {
const result = await builder.queryTransactionOutputsByIds([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ describe('chain history mappers', () => {
test('map TxModel to Cardano.HydratedTx with extra data', () => {
const result = mappers.mapTxAlonzo(txModel, {
certificates,
collateralOutputs: [txOutput],
collaterals: inputs,
inputSource,
inputs,
Expand All @@ -389,7 +390,14 @@ describe('chain history mappers', () => {
expect(result).toEqual<Cardano.HydratedTx>({
...expected,
auxiliaryData: { blob: metadata },
body: { ...expected.body, certificates, collaterals: inputs, mint: assets, withdrawals },
body: {
...expected.body,
certificates,
collateralReturn: txOutput,
collaterals: inputs,
mint: assets,
withdrawals
},
witness: { ...expected.witness, redeemers }
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export enum TxWith {
Mint = 'mint',
MultiAsset = 'multiAsset',
Redeemer = 'redeemer',
Withdrawal = 'withdrawal'
Withdrawal = 'withdrawal',
CollateralOutput = 'collateralOutput'
}

export type AddressesInBlockRange = {
Expand Down Expand Up @@ -120,6 +121,7 @@ export class ChainHistoryFixtureBuilder {
if (options.with.includes(TxWith.DelegationCertificate)) query += Queries.latestTxHashesWithDelegationCerts;
if (options.with.includes(TxWith.MirCertificate)) query += Queries.latestTxHashesWithMirCerts;
if (options.with.includes(TxWith.Withdrawal)) query += Queries.latestTxHashesWithWithdrawal;
if (options.with.includes(TxWith.CollateralOutput)) query += Queries.latestTxHashesWithCollateralOutput;

query += Queries.endLatestTxHashes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export const latestTxHashesWithMirCerts = `
export const latestTxHashesWithWithdrawal = `
JOIN withdrawal ON withdrawal.tx_id = tx.id`;

export const latestTxHashesWithCollateralOutput = `
JOIN collateral_tx_out ON collateral_tx_out.tx_id = tx.id`;

export const endLatestTxHashes = `
GROUP BY tx.id
ORDER BY tx.id DESC
Expand Down Expand Up @@ -101,6 +104,7 @@ const Queries = {
latestTxHashes,
latestTxHashesWithAuxiliaryData,
latestTxHashesWithCollateral,
latestTxHashesWithCollateralOutput,
latestTxHashesWithDelegationCerts,
latestTxHashesWithMint,
latestTxHashesWithMirCerts,
Expand Down
7 changes: 7 additions & 0 deletions packages/cardano-services/test/data-mocks/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ export const collateralInputs = [
}
];

export const collateralReturn: Cardano.TxOut = {
address: Cardano.PaymentAddress('addr_test1wqnp362vmvr8jtc946d3a3utqgclfdl5y9d3kn849e359hst7hkqk'),
value: {
coins: 3_681_817_479_100_950n
}
};

export const withValidityInterval: Cardano.HydratedTx = merge(withAssets, {
body: {
validityInterval: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.27.0](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

### ⚠ BREAKING CHANGES

* **core:** tokenTransferInspector now takes an extra parameter AssetProvider
- txSummaryInspector now takes an extra parameter AssetProvider
- tokenTransferInspector now return AssetInfo rather than AssettId
- txSummaryInspector now return AssetInfo rather than AssettId

### Features

* **core:** tokenTransferInspector and txSummaryInspector now return AssetInfo rather than AssettId ([219623f](https://github.com/input-output-hk/cardano-js-sdk/commit/219623fa1218c5f5e4c4cffffd43af7db04951f1))

## [0.26.0](https://github.com/input-output-hk/cardano-js-sdk/compare/@cardano-sdk/[email protected]...@cardano-sdk/[email protected]) (2024-02-02)

### ⚠ BREAKING CHANGES
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cardano-sdk/core",
"version": "0.26.0",
"version": "0.27.0",
"description": "Core types and libraries for Cardano",
"engines": {
"node": ">=16.20.2"
Expand Down
60 changes: 56 additions & 4 deletions packages/core/src/util/tokenTransferInspector.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import * as Cardano from '../Cardano';
import { AssetInfo } from '../Asset';
import { AssetProvider } from '../Provider';
import { Inspector, resolveInputs } from './txInspector';
import { coalesceValueQuantities } from './coalesceValueQuantities';
import { subtractValueQuantities } from './subtractValueQuantities';
import uniq from 'lodash/uniq';

export type AssetInfoWithAmount = { amount: Cardano.Lovelace; assetInfo: AssetInfo };

export type TokenTransferValue = {
assets: Map<Cardano.AssetId, AssetInfoWithAmount>;
coins: Cardano.Lovelace;
};

export type TokenTransferInspection = {
fromAddress: Map<Cardano.PaymentAddress, Cardano.Value>;
toAddress: Map<Cardano.PaymentAddress, Cardano.Value>;
fromAddress: Map<Cardano.PaymentAddress, TokenTransferValue>;
toAddress: Map<Cardano.PaymentAddress, TokenTransferValue>;
};

/** Arguments for the token transfer inspector. */
export interface TokenTransferInspectorArgs {
/** The input resolver. */
inputResolver: Cardano.InputResolver;

/** The asset provider to resolve AssetInfo for assets in the fromAddress field. */
fromAddressAssetProvider: AssetProvider;

/** The asset provider to resolve AssetInfo for assets in the toAddress field. */
toAddressAssetProvider: AssetProvider;
}

export type TokenTransferInspector = (args: TokenTransferInspectorArgs) => Inspector<TokenTransferInspection>;
Expand Down Expand Up @@ -99,9 +116,41 @@ const removeZeroBalanceEntries = (addressMap: Map<Cardano.PaymentAddress, Cardan
}
};

const toTokenTransferValue = async (
assetProvider: AssetProvider,
addressMap: Map<Cardano.PaymentAddress, Cardano.Value>
): Promise<Map<Cardano.PaymentAddress, TokenTransferValue>> => {
const tokenTransferValue = new Map<Cardano.PaymentAddress, TokenTransferValue>();

for (const [address, value] of addressMap.entries()) {
const coins = value.coins;
const assetIds = uniq(value.assets && value.assets.size > 0 ? [...value.assets.keys()] : []);
const assetInfos = new Map<Cardano.AssetId, AssetInfoWithAmount>();

if (assetIds.length > 0) {
const assets = await assetProvider.getAssets({
assetIds,
extraData: { nftMetadata: true, tokenMetadata: true }
});

for (const asset of assets) {
const amount = value.assets?.get(asset.assetId) ?? 0n;
assetInfos.set(asset.assetId, { amount, assetInfo: asset });
}
}

tokenTransferValue.set(address, {
assets: assetInfos,
coins
});
}

return tokenTransferValue;
};

/** Inspect a transaction and return a map of addresses and their balances. */
export const tokenTransferInspector: TokenTransferInspector =
({ inputResolver }) =>
({ inputResolver, fromAddressAssetProvider, toAddressAssetProvider }) =>
async (tx) => {
const { resolvedInputs } = await resolveInputs(tx.body.inputs, inputResolver);

Expand All @@ -118,5 +167,8 @@ export const tokenTransferInspector: TokenTransferInspector =
removeZeroBalanceEntries(fromAddress);
removeZeroBalanceEntries(toAddress);

return { fromAddress, toAddress };
return {
fromAddress: await toTokenTransferValue(fromAddressAssetProvider, fromAddress),
toAddress: await toTokenTransferValue(toAddressAssetProvider, toAddress)
};
};
Loading