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

feat(tokenDissociateTransaction): Implement TokenDissociateTransaction E2E tests: TCK #291

Merged
1 change: 0 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@
"arrowParens": "always",
"endOfLine": "lf"
}

Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ The tests contained in this specification will assume that a valid account and a

| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---------|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|-------------------|
| 1 | Dissociates a token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and the token is associated with <CREATED_ACCOUNT_ID>. | N |
| 2 | Dissociates a token from an account with which it is already dissociated | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_NOT_ASSOCIATED_TO_ACCOUNT response code from the network. | N |
| 3 | Dissociates a token from an account without signing with the account's private key | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an INVALID_SIGNATURE response code from the network. | N |
| 4 | Dissociates a token from an account that doesn't exist | accountId="123.456.789", tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an INVALID_ACCOUNT_ID response code from the network. | N |
| 5 | Dissociates a token from an account that is deleted | accountId=<DELETED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<DELETED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an INVALID_ACCOUNT_ID response code from the network. | N |
| 6 | Dissociates a token from an empty account | accountId="", tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an SDK internal error. | N |
| 1 | Dissociates a token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and the token is associated with <CREATED_ACCOUNT_ID>. | Y |
| 2 | Dissociates a token from an account with which it is already dissociated | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_NOT_ASSOCIATED_TO_ACCOUNT response code from the network. | Y |
| 3 | Dissociates a token from an account without signing with the account's private key | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an INVALID_SIGNATURE response code from the network. | Y |
| 4 | Dissociates a token from an account that doesn't exist | accountId="123.456.789", tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an INVALID_ACCOUNT_ID response code from the network. | Y |
| 5 | Dissociates a token from an account that is deleted | accountId=<DELETED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<DELETED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an INVALID_ACCOUNT_ID response code from the network. | Y |
| 6 | Dissociates a token from an empty account | accountId="", tokenIds=[<CREATED_TOKEN_ID>] | The token dissociation fails with an SDK internal error. | Y |

#### JSON Request Example

Expand Down Expand Up @@ -101,17 +101,17 @@ The tests contained in this specification will assume that a valid account and a

| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|-------------------|
| 1 | Dissociates no tokens from an account | accountId=<CREATED_ACCOUNT_ID>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and no disassociations are made. | N |
| 2 | Dissociates a token that doesn't exist from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=["123.456.789"], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an INVALID_TOKEN_ID response code from the network. | N |
| 3 | Dissociates a token that is deleted from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<DELETED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_WAS_DELETED response code from the network. | N |
| 4 | Dissociates a token that is empty from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[""], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an SDK internal error. | N |
| 5 | Dissociates a token twice from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>, <CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_ID_REPEATED_IN_TOKEN_LIST response code from the network. | N |
| 6 | Dissociates three valid tokens from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, <CREATED_TOKEN_ID_3>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and three disassociations are made. | N |
| 7 | Dissociates two valid tokens and an invalid token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, "123.456.789"], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an INVALID_TOKEN_ID response code from the network. | N |
| 8 | Dissociates two valid tokens and a deleted token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, <DELETED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_WAS_DELETED response code from the network. | N |
| 1 | Dissociates no tokens from an account | accountId=<CREATED_ACCOUNT_ID>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and no disassociations are made. | Y |
| 2 | Dissociates a token that doesn't exist from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=["123.456.789"], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_NOT_ASSOCIATED_TO_ACCOUNT response code from the network. | Y |
| 3 | Dissociates a token that is deleted from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<DELETED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_NOT_ASSOCIATED_TO_ACCOUNT response code from the network. | Y |
| 4 | Dissociates a token that is empty from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[""], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an SDK internal error. | Y |
| 5 | Dissociates a token twice from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>, <CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_ID_REPEATED_IN_TOKEN_LIST response code from the network. | Y |
| 6 | Dissociates three valid tokens from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, <CREATED_TOKEN_ID_3>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation succeeds and three disassociations are made. | Y |
| 7 | Dissociates two valid and associated tokens and an invalid token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, "123.456.789"], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an INVALID_TOKEN_ID response code from the network. | Y |
| 8 | Dissociates two valid and associated tokens and a deleted token from an account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID_1>, <CREATED_TOKEN_ID_2>, <DELETED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_WAS_DELETED response code from the network. | Y |
| 9 | Dissociates a token from an account while that account has a balance of the token | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TRANSACTION_REQUIRES_ZERO_TOKEN_BALANCES response code from the network. | N |
| 10 | Dissociates a token from an account while its frozen for the account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an ACCOUNT_FROZEN_FOR_TOKEN response code from the network. | N |
| 11 | Dissociates a token from an account while the token is paused | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_IS_PAUSED response code from the network. | N |
| 10 | Dissociates a token from an account while its frozen for the account | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an ACCOUNT_FROZEN_FOR_TOKEN response code from the network. | Y |
| 11 | Dissociates a token from an account while the token is paused | accountId=<CREATED_ACCOUNT_ID>, tokenIds=[<CREATED_TOKEN_ID>], commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The token dissociation fails with an TOKEN_IS_PAUSED response code from the network. | Y |

#### JSON Request Example

Expand Down
54 changes: 54 additions & 0 deletions mirrorNodeClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import axios from "axios";

class MirrorNodeClient {
constructor() {
this.mirrorNodeRestUrl = process.env.MIRROR_NODE_REST_URL;
this.NODE_TIMEOUT = process.env.NODE_TIMEOUT;
}

async getAccountData(accountId) {
const url = `${this.mirrorNodeRestUrl}/api/v1/accounts/${accountId}`;
return this.retryUntilData(url);
}

async getBalanceData() {
const url = `${this.mirrorNodeRestUrl}/api/v1/balances`;
return this.retryUntilData(url);
}

async getTokenData(tokenId) {
const url = `${this.mirrorNodeRestUrl}/api/v1/tokens/${tokenId}`;
return this.retryUntilData(url);
}

async getTokenRelationships(accountId) {
const url = `${this.mirrorNodeRestUrl}/api/v1/accounts/${accountId}/tokens`;
return this.retryUntilData(url);
}

async retryUntilData(url) {
const maxRetries = Math.floor(this.NODE_TIMEOUT / 1000); // retry once per second
let retries = 0;

while (retries < maxRetries) {
try {
const response = await axios.get(url);

if (response.data) {
return response.data;
}
} catch (error) {
// Uncomment if you want to see the error
// console.error(error);
}

// If the array is empty, delay for a second before the next try
await new Promise((resolve) => setTimeout(resolve, 1000));
retries++;
}

throw new Error("Max retries reached without data");
}
}

export default new MirrorNodeClient();
10 changes: 8 additions & 2 deletions src/services/MirrorNodeClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fetchData } from "../utils/helpers/fetch-data";
import { retryOnError } from "../utils/helpers/retry-on-error";
import { fetchData } from "@helpers/fetch-data";
import { retryOnError } from "@helpers/retry-on-error";

class MirrorNodeClient {
private mirrorNodeRestUrl: string | undefined;
Expand All @@ -25,6 +25,12 @@ class MirrorNodeClient {
const url = `${this.mirrorNodeRestUrl}/api/v1/tokens/${tokenId}`;
return retryOnError(async () => fetchData(url));
}

// TODO: Get mirror node interface with OpenAPI
async getTokenRelationships(accountId: string): Promise<any> {
const url = `${this.mirrorNodeRestUrl}/api/v1/accounts/${accountId}/tokens`;
return retryOnError(async () => fetchData(url));
}
}

export default new MirrorNodeClient();
Loading