Skip to content

Commit ad8f601

Browse files
chore: Release ATS v3.1.0 (#785)
Signed-off-by: Miguel_LZPF <miguel.carpena@io.builders> Signed-off-by: mamoralesiob <miguelangel@io.builders> Co-authored-by: mamoralesiob <miguelangel@io.builders>
1 parent e3ce27f commit ad8f601

File tree

103 files changed

+12069
-2625
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+12069
-2625
lines changed

.github/workflows/mp.publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
popd > /dev/null
104104
fi
105105
done
106-
106+
107107
# Verify successful packing
108108
if [ -z "$(ls -A dist-artifacts)" ]; then
109109
echo "::warning::No public packages were found to pack."

apps/ats/web/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @hashgraph/asset-tokenization-dapp
22

3+
## 3.1.0
4+
5+
### Patch Changes
6+
7+
- @hashgraph/asset-tokenization-sdk@3.1.0
8+
39
## 3.0.0
410

511
### Minor Changes

apps/ats/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hashgraph/asset-tokenization-dapp",
3-
"version": "3.0.0",
3+
"version": "3.1.0",
44
"license": "Apache-2.0",
55
"scripts": {
66
"build": "tsc && vite build",
Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1-
NODE_ENV=local
21
APP_ENV=local
3-
LOG_LEVEL=log
42
PORT=3000
53
POSTGRESQL_HOST=localhost
64
POSTGRESQL_PORT=5432
75
POSTGRESQL_USER=postgres
86
POSTGRESQL_PASSWORD=postgres
97
POSTGRESQL_DB=postgres
108
BATCH_SIZE=100
11-
12-
# Mainnet
13-
#BLOCKCHAIN_MIRROR_NODE_URL=https://mainnet-public.mirrornode.hedera.com
14-
#BLOCKCHAIN_CONTRACT_ID=0.0.456858
15-
# Testnet
9+
HEDERA_USDC_ADDRESS=0.0.429274
10+
ATS_NETWORK=testnet
11+
ATS_MIRROR_URL=https://testnet.mirrornode.hedera.com/api/v1/
12+
ATS_RPC_URL=https://testnet.hashio.io/api
13+
RPC_URL=https://testnet.hashio.io/api
14+
ATS_FACTORY_ADDRESS='0.0.6224505'
15+
ATS_RESOLVER_ADDRESS='0.0.6224426'
16+
#Just in case...
17+
FACTORY_ADDRESS='0.0.6224505'
18+
RESOLVER_ADDRESS='0.0.6224426'
19+
DFNS_SERVICE_ACCOUNT_AUTHORIZATION_TOKEN=
20+
DFNS_SERVICE_ACCOUNT_PRIVATE_KEY_PATH=
21+
DFNS_SERVICE_ACCOUNT_CREDENTIAL_ID=
22+
DFNS_APP_ORIGIN=
23+
DFNS_APP_ID=
24+
DFNS_BASE_URL=
25+
DFNS_WALLET_ID=
26+
DFNS_WALLET_PUBLIC_KEY=
27+
DFNS_HEDERA_ACCOUNT_ID=
1628
BLOCKCHAIN_MIRROR_NODE_URL=https://testnet.mirrornode.hedera.com
1729
BLOCKCHAIN_CONTRACT_ID=0.0.429274
1830
BLOCKCHAIN_TOKEN_DECIMALS=6
1931
BLOCKCHAIN_LISTENER_POLL_TIMEOUT=10000
20-
BLOCKCHAIN_LISTENER_START_TIMESTAMP=2025-08-26T00:00:00.000Z
32+
BLOCKCHAIN_LISTENER_START_TIMESTAMP=2025-09-24T15:25:00.000Z

apps/mass-payout/backend/src/domain/model/blockchain-listener.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
*/
204204

205205
import { CustomError } from "@domain/errors/shared/custom.error"
206+
import { ApiProperty } from "@nestjs/swagger"
206207

207208
export interface MirrorNodeLog {
208209
timestamp: string
@@ -237,9 +238,33 @@ export interface ApprovalEventData extends BlockchainEvent {
237238
export class BlockchainEventListenerError extends CustomError {}
238239

239240
export class BlockchainEventListenerConfig {
241+
@ApiProperty({
242+
description: "The id of the event listener config",
243+
example: "32264ce1-76fb-44bb-a8a2-d1a516dcf34d",
244+
})
240245
id: string
246+
247+
@ApiProperty({
248+
description: "The Hedera mirror node url",
249+
example: "https://testnet.mirrornode.hedera.com/api/v1/",
250+
})
241251
mirrorNodeUrl: string
252+
253+
@ApiProperty({
254+
description: "The payment token Hedera contract Id",
255+
example: "0.0.123456",
256+
})
242257
contractId: string
258+
259+
@ApiProperty({
260+
description: "The payment token decimals",
261+
example: "2",
262+
})
243263
tokenDecimals: number
264+
265+
@ApiProperty({
266+
description: "The blockchain listener start date",
267+
example: "2025-01-15 13:45:30",
268+
})
244269
startTimestamp: string
245270
}

apps/mass-payout/backend/src/infrastructure/rest/asset/asset.controller.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ import { ImportAssetUseCase } from "@application/use-cases/import-asset.use-case
213213
import { PauseAssetUseCase } from "@application/use-cases/pause-asset.use-case"
214214
import { UnpauseAssetUseCase } from "@application/use-cases/unpause-asset.use-case"
215215
import { Body, Get, HttpCode, HttpStatus, Param, Patch, Post, Query } from "@nestjs/common"
216+
import { ApiOperation, ApiResponse, ApiTags, ApiParam } from "@nestjs/swagger"
216217
import { DistributionResponse } from "../distribution/distribution.response"
217218
import { PageOptionsRequest } from "../page-options.request"
218219
import { PageResponse } from "../page.response"
@@ -224,6 +225,7 @@ import { GetBasicAssetInformationResponse } from "./get-basic-asset-information.
224225
import { ImportAssetRequest } from "./import-asset.request"
225226
import { GetDistributionHolderCountUseCase } from "@application/use-cases/get-distribution-holder-count.use-case"
226227

228+
@ApiTags("Assets")
227229
@RestController("assets")
228230
export class AssetController {
229231
constructor(
@@ -240,36 +242,97 @@ export class AssetController {
240242
private readonly executePayoutUseCase: ExecutePayoutUseCase,
241243
) {}
242244

245+
@ApiOperation({
246+
summary: "Import an asset so the payments to its holders are managed by the Scheduler Payment Distribution Service",
247+
})
248+
@ApiResponse({ status: 500, description: "Internal server error" })
249+
@ApiResponse({ status: 400, description: "Bad Request" })
250+
@ApiResponse({ status: 401, description: "Unauthorized" })
251+
@ApiResponse({ status: 404, description: "Not Found" })
252+
@ApiResponse({ status: 201, type: AssetResponse })
243253
@Post("import")
244254
async importAsset(@Body() request: ImportAssetRequest): Promise<AssetResponse> {
245255
const asset = await this.importAssetUseCase.execute(request.hederaTokenAddress)
246256
return AssetResponse.fromAsset(asset)
247257
}
248258

259+
@ApiOperation({ summary: "Pause the Scheduler Payment Distribution Service for a certain asset." })
260+
@ApiParam({
261+
name: "assetId",
262+
description: "The ID of the asset to pause.",
263+
example: "0.0.123456",
264+
})
265+
@ApiResponse({ status: 500, description: "Internal server error" })
266+
@ApiResponse({ status: 400, description: "Bad Request" })
267+
@ApiResponse({ status: 401, description: "Unauthorized" })
268+
@ApiResponse({ status: 404, description: "Not Found" })
269+
@ApiResponse({
270+
status: 200,
271+
description: "The asset LifeCycleCashFlow contract has been successfully paused.",
272+
})
249273
@Patch(":assetId/pause")
250274
@HttpCode(HttpStatus.OK)
251275
async pauseAsset(@Param("assetId") assetId: string): Promise<void> {
252276
await this.pauseAssetUseCase.execute(assetId)
253277
}
254278

279+
@ApiOperation({ summary: "Unpause the Scheduler Payment Distribution Service for a certain asset." })
280+
@ApiParam({
281+
name: "assetId",
282+
description: "The ID of the asset to unpause.",
283+
example: "0.0.123456",
284+
})
285+
@ApiResponse({ status: 500, description: "Internal server error" })
286+
@ApiResponse({ status: 400, description: "Bad Request" })
287+
@ApiResponse({ status: 401, description: "Unauthorized" })
288+
@ApiResponse({ status: 404, description: "Not Found" })
289+
@ApiResponse({
290+
status: 200,
291+
description: "The asset LifeCycleCashFlow contract has been successfully unpaused.",
292+
})
255293
@Patch(":assetId/unpause")
256294
@HttpCode(HttpStatus.OK)
257295
async unpauseAsset(@Param("assetId") assetId: string): Promise<void> {
258296
await this.unpauseAssetUseCase.execute(assetId)
259297
}
260298

299+
@ApiOperation({ summary: "Get the assets list managed by the Scheduler Payment Distribution Service." })
300+
@ApiResponse({ status: 500, description: "Internal server error" })
301+
@ApiResponse({ status: 400, description: "Bad Request" })
302+
@ApiResponse({ status: 401, description: "Unauthorized" })
303+
@ApiResponse({ status: 404, description: "Not Found" })
304+
@ApiResponse({ status: 200, type: PageResponse<AssetResponse> })
261305
@Get()
262306
async getAssets(@Query() pageOptions: PageOptionsRequest): Promise<PageResponse<AssetResponse>> {
263307
const result = await this.getAssetsUseCase.execute(pageOptions.toPageOptions())
264308
return PageResponse.fromPage(result, AssetResponse.fromAsset)
265309
}
266310

311+
@ApiOperation({ summary: "Get a certain asset managed by the Scheduler Payment Distribution Service." })
312+
@ApiParam({
313+
name: "assetId",
314+
description: "The ID of the asset to unpause.",
315+
example: "0.0.123456",
316+
})
317+
@ApiResponse({ status: 500, description: "Internal server error" })
318+
@ApiResponse({ status: 400, description: "Bad Request" })
319+
@ApiResponse({ status: 401, description: "Unauthorized" })
320+
@ApiResponse({ status: 404, description: "Not Found" })
321+
@ApiResponse({ status: 200, type: AssetResponse })
267322
@Get(":assetId")
268323
async getAsset(@Param("assetId") assetId: string): Promise<AssetResponse> {
269324
const asset = await this.getAssetUseCase.execute(assetId)
270325
return AssetResponse.fromAsset(asset)
271326
}
272327

328+
@ApiOperation({
329+
summary: "Get the basic information of a certain asset managed by the Scheduler Payment Distribution Service.",
330+
})
331+
@ApiResponse({ status: 500, description: "Internal server error" })
332+
@ApiResponse({ status: 400, description: "Bad Request" })
333+
@ApiResponse({ status: 401, description: "Unauthorized" })
334+
@ApiResponse({ status: 404, description: "Not Found" })
335+
@ApiResponse({ status: 200, type: GetBasicAssetInformationResponse })
273336
@Get(":hederaTokenAddress/metadata")
274337
async getBasicAssetInformation(
275338
@Param() request: GetBasicAssetInformationRequest,
@@ -284,6 +347,19 @@ export class AssetController {
284347
)
285348
}
286349

350+
@ApiOperation({
351+
summary: "Get distributions information of a certain asset managed by the Scheduler Payment Distribution Service.",
352+
})
353+
@ApiParam({
354+
name: "assetId",
355+
description: "The ID of the asset to get its distributions information.",
356+
example: "0.0.123456",
357+
})
358+
@ApiResponse({ status: 500, description: "Internal server error" })
359+
@ApiResponse({ status: 400, description: "Bad Request" })
360+
@ApiResponse({ status: 401, description: "Unauthorized" })
361+
@ApiResponse({ status: 404, description: "Not Found" })
362+
@ApiResponse({ status: 200, type: PageResponse<DistributionResponse> })
287363
@Get(":assetId/distributions")
288364
async getAssetDistributions(
289365
@Param("assetId") assetId: string,
@@ -299,6 +375,20 @@ export class AssetController {
299375
return distributions
300376
}
301377

378+
@ApiOperation({ summary: "Create a batch payout." })
379+
@ApiParam({
380+
name: "assetId",
381+
description: "The ID of the asset to create a batch payout for",
382+
example: "0.0.123456",
383+
})
384+
@ApiResponse({ status: 500, description: "Internal server error" })
385+
@ApiResponse({ status: 400, description: "Bad Request" })
386+
@ApiResponse({ status: 401, description: "Unauthorized" })
387+
@ApiResponse({ status: 404, description: "Not Found" })
388+
@ApiResponse({
389+
status: 201,
390+
description: "The asset payout has been successfully created.",
391+
})
302392
@Post(":assetId/distributions/payout")
303393
@HttpCode(HttpStatus.CREATED)
304394
async createPayout(@Param("assetId") assetId: string, @Body() request: CreatePayoutRequest): Promise<void> {
@@ -313,13 +403,35 @@ export class AssetController {
313403
})
314404
}
315405

406+
@ApiOperation({ summary: "Enable the asset synchronization." })
407+
@ApiParam({
408+
name: "assetId",
409+
description: "The ID of the asset to enable the sync.",
410+
example: "0.0.123456",
411+
})
412+
@ApiResponse({ status: 500, description: "Internal server error" })
413+
@ApiResponse({ status: 400, description: "Bad Request" })
414+
@ApiResponse({ status: 401, description: "Unauthorized" })
415+
@ApiResponse({ status: 404, description: "Not Found" })
416+
@ApiResponse({ status: 200, type: AssetResponse })
316417
@Patch(":assetId/enable-sync")
317418
@HttpCode(HttpStatus.OK)
318419
async enableAssetSync(@Param("assetId") assetId: string): Promise<AssetResponse> {
319420
const asset = await this.enableAssetSyncUseCase.execute(assetId)
320421
return AssetResponse.fromAsset(asset)
321422
}
322423

424+
@ApiOperation({ summary: "Disable the asset synchronization." })
425+
@ApiParam({
426+
name: "assetId",
427+
description: "The ID of the asset to disable the sync.",
428+
example: "0.0.123456",
429+
})
430+
@ApiResponse({ status: 500, description: "Internal server error" })
431+
@ApiResponse({ status: 400, description: "Bad Request" })
432+
@ApiResponse({ status: 401, description: "Unauthorized" })
433+
@ApiResponse({ status: 404, description: "Not Found" })
434+
@ApiResponse({ status: 200, type: AssetResponse })
323435
@Patch(":assetId/disable-sync")
324436
@HttpCode(HttpStatus.OK)
325437
async disableAssetSync(@Param("assetId") assetId: string): Promise<AssetResponse> {

apps/mass-payout/backend/src/infrastructure/rest/asset/asset.response.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,20 +203,88 @@
203203
*/
204204

205205
import { Asset } from "@domain/model/asset"
206+
import { ApiProperty } from "@nestjs/swagger"
206207

207208
export class AssetResponse {
209+
@ApiProperty({
210+
description: "The id of the asset in the service",
211+
example: "32264ce1-76fb-44bb-a8a2-d1a516dcf34d",
212+
})
208213
id: string
214+
215+
@ApiProperty({
216+
description: "The name of the asset",
217+
example: "Sella River Clean",
218+
})
209219
name: string
220+
221+
@ApiProperty({
222+
description: "The type of the asset",
223+
example: "BOND | EQUITY",
224+
})
210225
type: string
226+
227+
@ApiProperty({
228+
description: "The asset Hedera token contract Id",
229+
example: "0.0.123456",
230+
})
211231
hederaTokenAddress: string
232+
233+
@ApiProperty({
234+
description: "The EVM address of the asset Hedera token contract",
235+
example: "0x0123456789abcdef0123456789abcdef01234567",
236+
})
212237
evmTokenAddress: string
238+
239+
@ApiProperty({
240+
description: "The symbol of the asset",
241+
example: "SRC",
242+
})
213243
symbol: string
244+
245+
@ApiProperty({
246+
description: "The LifeCycleCashFlow Hedera contract Id",
247+
example: "0.0.123456",
248+
required: false,
249+
})
214250
lifeCycleCashFlowHederaAddress?: string
251+
252+
@ApiProperty({
253+
description: "The EVM address of the LifeCycleCashFlow Hedera contract",
254+
example: "0x0123456789abcdef0123456789abcdef01234567",
255+
required: false,
256+
})
215257
lifeCycleCashFlowEvmAddress?: string
258+
259+
@ApiProperty({
260+
description: "The asset maturity date",
261+
example: "2025-01-15 13:45:30",
262+
required: false,
263+
})
216264
maturityDate?: Date
265+
266+
@ApiProperty({
267+
description: "Whether the asset is paused",
268+
example: "true | false",
269+
})
217270
isPaused: boolean
271+
272+
@ApiProperty({
273+
description: "Whether the asset sync is enabled",
274+
example: "true | false",
275+
})
218276
syncEnabled: boolean
277+
278+
@ApiProperty({
279+
description: "The asset creation date in the service",
280+
example: "2025-01-15 13:45:30",
281+
})
219282
createdAt: Date
283+
284+
@ApiProperty({
285+
description: "The asset update date in the service",
286+
example: "2025-01-15 13:45:30",
287+
})
220288
updatedAt: Date
221289

222290
static fromAsset(asset: Asset): AssetResponse {

0 commit comments

Comments
 (0)