Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion FACTORY_VERSION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
| Version | Contract name | Address | Network |
| ------- | -------------- | ----------- | ------- |
|---------| -------------- | ----------- | ------- |
| 2.1.7 | FactoryAddress | 0.0.6431833 | Testnet |
| 2.1.6 | FactoryAddress | 0.0.6431833 | Testnet |
| 2.1.5 | FactoryAddress | 0.0.6349500 | Testnet |
| 2.1.0 | FactoryAddress | 0.0.6176922 | Testnet |
Expand Down
1 change: 1 addition & 0 deletions RESOLVER_VERSION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
| Version | Contract name | Address | Network |
|---------| -------------- | ----------- | ------- |
| 2.1.7 | ResolverAddress | 0.0.6431794 | Testnet |
| 2.1.6 | ResolverAddress | 0.0.6431794 | Testnet |
| 2.1.5 | ResolverAddress | 0.0.6349477 | Testnet |
| 2.0.0 | ResolverAddress | 0.0.6095328 | Testnet |
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-backend",
"version": "2.1.6",
"version":"2.1.7",
"description": "",
"author": "",
"license": "Apache-2.0",
Expand Down
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-cli",
"version": "2.1.6",
"version":"2.1.7",
"description": "CLI for Hedera Stablecoin",
"main": "./build/src/index.js",
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-contracts",
"version": "2.1.6",
"version":"2.1.7",
"description": "",
"main": "./build/typechain-types/index.js",
"module": "./build/typechain-types/index.js",
Expand Down
25 changes: 10 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hedera-stable-coin",
"version": "2.1.6",
"version":"2.1.7",
"private": true,
"description": "Stablecoin studio",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-sdk",
"version": "2.1.6",
"version":"2.1.7",
"description": "stablecoin studio SDK",
"main": "./build/cjs/src/index.js",
"module": "./build/esm/src/index.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import BaseError, {ErrorCode} from "../../../../../core/error/BaseError";


export class StableCoinMaxAutoAssociationReached extends BaseError {
constructor(targetId: unknown, maxAssociations: number) {
super(
ErrorCode.OperationNotAllowed,
`The account ${targetId} has reached the maximum auto-association limit of ${maxAssociations} tokens. ` +
`To proceed, either: (1) increase the account's max_automatic_token_associations limit, or (2) manually associate the token to the account.`,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,30 @@
*/

import CheckNums from '../../../../../../core/checks/numbers/CheckNums.js';
import { ICommandHandler } from '../../../../../../core/command/CommandHandler.js';
import { CommandHandler } from '../../../../../../core/decorator/CommandHandlerDecorator.js';
import { lazyInject } from '../../../../../../core/decorator/LazyInjectDecorator.js';
import {ICommandHandler} from '../../../../../../core/command/CommandHandler.js';
import {CommandHandler} from '../../../../../../core/decorator/CommandHandlerDecorator.js';
import {lazyInject} from '../../../../../../core/decorator/LazyInjectDecorator.js';
import BigDecimal from '../../../../../../domain/context/shared/BigDecimal.js';
import { StableCoinNotAssociated } from '../../error/StableCoinNotAssociated.js';
import {StableCoinNotAssociated} from '../../error/StableCoinNotAssociated.js';
import AccountService from '../../../../../service/AccountService.js';
import StableCoinService from '../../../../../service/StableCoinService.js';
import TransactionService from '../../../../../service/TransactionService.js';
import { DecimalsOverRange } from '../../error/DecimalsOverRange.js';
import { OperationNotAllowed } from '../../error/OperationNotAllowed.js';
import { CashInCommand, CashInCommandResponse } from './CashInCommand.js';
import { GetAccountTokenRelationshipQuery } from '../../../../query/account/tokenRelationship/GetAccountTokenRelationshipQuery.js';
import {DecimalsOverRange} from '../../error/DecimalsOverRange.js';
import {OperationNotAllowed} from '../../error/OperationNotAllowed.js';
import {CashInCommand, CashInCommandResponse} from './CashInCommand.js';
import {
FreezeStatus,
KycStatus,
} from '../../../../../../port/out/mirror/response/AccountTokenRelationViewModel.js';
import { RPCQueryAdapter } from '../../../../../../port/out/rpc/RPCQueryAdapter.js';
import { AccountFreeze } from '../../error/AccountFreeze.js';
import { AccountNotKyc } from '../../error/AccountNotKyc.js';
import { GetReserveAmountQuery } from '../../../../query/stablecoin/getReserveAmount/GetReserveAmountQuery.js';
import { RESERVE_DECIMALS } from '../../../../../../domain/context/reserve/Reserve.js';
import { MirrorNodeAdapter } from '../../../../../../port/out/mirror/MirrorNodeAdapter.js';
import { TokenSupplyType } from '@hashgraph/sdk';
GetAccountTokenRelationshipQuery
} from '../../../../query/account/tokenRelationship/GetAccountTokenRelationshipQuery.js';
import {FreezeStatus, KycStatus,} from '../../../../../../port/out/mirror/response/AccountTokenRelationViewModel.js';
import {RPCQueryAdapter} from '../../../../../../port/out/rpc/RPCQueryAdapter.js';
import {AccountFreeze} from '../../error/AccountFreeze.js';
import {AccountNotKyc} from '../../error/AccountNotKyc.js';
import {GetReserveAmountQuery} from '../../../../query/stablecoin/getReserveAmount/GetReserveAmountQuery.js';
import {RESERVE_DECIMALS} from '../../../../../../domain/context/reserve/Reserve.js';
import {MirrorNodeAdapter} from '../../../../../../port/out/mirror/MirrorNodeAdapter.js';
import {TokenSupplyType} from '@hashgraph/sdk';
import {GetAccountAutoAssociationQuery} from "../../../../query/account/autoAssociation/GetAccountAutoAssociationQuery";
import {StableCoinMaxAutoAssociationReached} from "../../error/StableCoinMaxAutoAssociationReached";

const MAX_SUPPLY = 9_223_372_036_854_775_807n;

Expand All @@ -64,26 +65,51 @@ export class CashInCommandHandler implements ICommandHandler<CashInCommand> {
const { amount, targetId, tokenId, startDate } = command;
const handler = this.transactionService.getHandler();
const account = this.accountService.getCurrentAccount();

const tokenRelationship = (
await this.stableCoinService.queryBus.execute(
new GetAccountTokenRelationshipQuery(targetId, tokenId),
)
).payload;

if (!tokenRelationship) {
throw new StableCoinNotAssociated(
targetId.toString(),
tokenId.toString(),
);
}
if (tokenRelationship.freezeStatus === FreezeStatus.FROZEN) {
throw new AccountFreeze(targetId.toString());
}
const autoAssociationInfo = (
await this.stableCoinService.queryBus.execute(
new GetAccountAutoAssociationQuery(targetId)
)
).payload;

if (!autoAssociationInfo) {
throw new StableCoinNotAssociated(targetId.toString(), tokenId.toString());
}

const max = Number(autoAssociationInfo.maxAutoAssociations ?? 0);
const remaining = Number(autoAssociationInfo.remainingAutoAssociations ?? 0);

if (max === 0) {
throw new StableCoinNotAssociated(targetId.toString(), tokenId.toString());
}

if (tokenRelationship.kycStatus === KycStatus.REVOKED) {
throw new AccountNotKyc(targetId.toString());
const isUnlimited = max === -1 || remaining === -1;

if (!isUnlimited && remaining <= 0) {
throw new StableCoinMaxAutoAssociationReached(
targetId.toString(),
max
);
}

} else {
if (tokenRelationship.freezeStatus === FreezeStatus.FROZEN) {
throw new AccountFreeze(targetId.toString());
}

if (tokenRelationship.kycStatus === KycStatus.REVOKED) {
throw new AccountNotKyc(targetId.toString());
}
}


const capabilities = await this.stableCoinService.getCapabilities(
account,
tokenId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import {
TransfersCommand,
TransfersCommandResponse,
} from './TransfersCommand.js';
import {GetAccountAutoAssociationQuery} from "../../../../query/account/autoAssociation/GetAccountAutoAssociationQuery";
import {StableCoinMaxAutoAssociationReached} from "../../error/StableCoinMaxAutoAssociationReached";

@CommandHandler(TransfersCommand)
export class TransfersCommandHandler
Expand Down Expand Up @@ -81,16 +83,40 @@ export class TransfersCommandHandler
).payload;

if (!tokenRelationship) {
errors.push(
new StableCoinNotAssociated(
targetsIds[i].toString(),
tokenId.toString(),
),
);
} else if (tokenRelationship.freezeStatus === FreezeStatus.FROZEN) {
errors.push(new AccountFreeze(targetsIds[i].toString()));
} else if (tokenRelationship.kycStatus === KycStatus.REVOKED) {
errors.push(new AccountNotKyc(targetsIds[i].toString()));
const autoAssociationInfo = (
await this.stableCoinService.queryBus.execute(
new GetAccountAutoAssociationQuery(targetId)
)
).payload;

if (!autoAssociationInfo) {
throw new StableCoinNotAssociated(targetId.toString(), tokenId.toString());
}

const max = Number(autoAssociationInfo.maxAutoAssociations ?? 0);
const remaining = Number(autoAssociationInfo.remainingAutoAssociations ?? 0);

if (max === 0) {
throw new StableCoinNotAssociated(targetId.toString(), tokenId.toString());
}

const isUnlimited = max === -1 || remaining === -1;

if (!isUnlimited && remaining <= 0) {
throw new StableCoinMaxAutoAssociationReached(
targetId.toString(),
max
);
}

} else {
if (tokenRelationship.freezeStatus === FreezeStatus.FROZEN) {
throw new AccountFreeze(targetId.toString());
}

if (tokenRelationship.kycStatus === KycStatus.REVOKED) {
throw new AccountNotKyc(targetId.toString());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
*
* Hedera Stablecoin SDK
*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import { QueryResponse } from "../../../../../core/query/QueryResponse.js";
import { Query } from "../../../../../core/query/Query.js";
import { HederaId } from "../../../../../domain/context/shared/HederaId.js";
import { AccountAutoAssociationViewModel } from "../../../../../port/out/mirror/response/AccountAutoAssociationViewModel.js";

export class GetAccountAutoAssociationQueryResponse implements QueryResponse {
constructor(public readonly payload?: AccountAutoAssociationViewModel) {}
}

export class GetAccountAutoAssociationQuery
extends Query<GetAccountAutoAssociationQueryResponse> {
constructor(public readonly targetId: HederaId) {
super();
}
}

Loading