diff --git a/hedera-node/hedera-app/src/xtest/java/contract/DeleteXTest.java b/hedera-node/hedera-app/src/xtest/java/contract/DeleteXTest.java index 0426b1001b51..a2d2c7f78c50 100644 --- a/hedera-node/hedera-app/src/xtest/java/contract/DeleteXTest.java +++ b/hedera-node/hedera-app/src/xtest/java/contract/DeleteXTest.java @@ -16,10 +16,21 @@ package contract; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; import static com.hedera.hapi.node.base.ResponseCodeEnum.TOKEN_IS_IMMUTABLE; import static com.hedera.hapi.node.base.ResponseCodeEnum.TOKEN_WAS_DELETED; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asHeadlongAddress; +import static contract.AssociationsXTestConstants.A_TOKEN_ADDRESS; +import static contract.AssociationsXTestConstants.A_TOKEN_ID; +import static contract.AssociationsXTestConstants.B_TOKEN_ADDRESS; +import static contract.AssociationsXTestConstants.B_TOKEN_ID; +import static contract.AssociationsXTestConstants.C_TOKEN_ADDRESS; +import static contract.AssociationsXTestConstants.C_TOKEN_ID; +import static contract.AssociationsXTestConstants.D_TOKEN_ADDRESS; +import static contract.AssociationsXTestConstants.D_TOKEN_ID; +import static contract.HtsErc721TransferXTestConstants.UNAUTHORIZED_SPENDER_ID; +import static contract.XTestConstants.AN_ED25519_KEY; import static contract.XTestConstants.ERC20_TOKEN_ADDRESS; import static contract.XTestConstants.ERC20_TOKEN_ID; import static contract.XTestConstants.ERC721_TOKEN_ADDRESS; @@ -50,6 +61,20 @@ import java.util.Map; import org.apache.tuweni.bytes.Bytes; +/** + * Exercises delete on a fungible and non-fungible token via the following steps relative to an {@code OWNER} account: + *
    + *
  1. Deletes {@code ERC20_TOKEN} via DELETE operation
  2. + *
  3. Deletes {@code ERC721_TOKEN} via DELETE operation
  4. + *
  5. Freezes a deleted {@code ERC20_TOKEN}. This should fail with TOKEN_WAS_DELETED
  6. + *
  7. Freezes a deleted {@code ERC721_TOKEN}. This should fail with TOKEN_WAS_DELETED
  8. + *
  9. Deletes {@code ERC20_TOKEN} without admin key. This should fail with TOKEN_IS_IMMUTABLE
  10. + *
  11. Deletes {@code ERC721_TOKEN} without admin key. This should fail with TOKEN_IS_IMMUTABLE
  12. + *
  13. Deletes {@code ERC20_TOKEN} with wrong admin key. This should fail with INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE
  14. + *
  15. Deletes {@code ERC721_TOKEN} with wrong admin key. This should fail with INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE
  16. + *
  17. Deletes token with invalid token address via DELETE operation. This should fail with INVALID_TOKEN_ID
  18. + *
+ */ public class DeleteXTest extends AbstractContractXTest { @Override protected void doScenarioOperations() { @@ -61,6 +86,14 @@ protected void doScenarioOperations() { .array()), assertSuccess()); + // Successfully delete token + runHtsCallAndExpectOnSuccess( + SENDER_BESU_ADDRESS, + Bytes.wrap(DeleteTranslator.DELETE_TOKEN + .encodeCallWithArgs(ERC721_TOKEN_ADDRESS) + .array()), + assertSuccess()); + // Try to freeze deleted token runHtsCallAndExpectOnSuccess( SENDER_BESU_ADDRESS, @@ -70,15 +103,55 @@ protected void doScenarioOperations() { output -> assertEquals( Bytes.wrap(ReturnTypes.encodedRc(TOKEN_WAS_DELETED).array()), output)); + // Try to freeze deleted token + runHtsCallAndExpectOnSuccess( + SENDER_BESU_ADDRESS, + Bytes.wrap(FreezeUnfreezeTranslator.FREEZE + .encodeCallWithArgs(ERC721_TOKEN_ADDRESS, asHeadlongAddress(SENDER_ADDRESS.toByteArray())) + .array()), + output -> assertEquals( + Bytes.wrap(ReturnTypes.encodedRc(TOKEN_WAS_DELETED).array()), output)); + // Fail if token has no admin key runHtsCallAndExpectOnSuccess( SENDER_BESU_ADDRESS, Bytes.wrap(DeleteTranslator.DELETE_TOKEN - .encodeCallWithArgs(ERC721_TOKEN_ADDRESS) + .encodeCallWithArgs(A_TOKEN_ADDRESS) + .array()), + output -> assertEquals( + Bytes.wrap(ReturnTypes.encodedRc(TOKEN_IS_IMMUTABLE).array()), output)); + + // Fail if token has no admin key + runHtsCallAndExpectOnSuccess( + SENDER_BESU_ADDRESS, + Bytes.wrap(DeleteTranslator.DELETE_TOKEN + .encodeCallWithArgs(B_TOKEN_ADDRESS) .array()), output -> assertEquals( Bytes.wrap(ReturnTypes.encodedRc(TOKEN_IS_IMMUTABLE).array()), output)); + // Fail if token has wrong admin key + runHtsCallAndExpectOnSuccess( + SENDER_BESU_ADDRESS, + Bytes.wrap(DeleteTranslator.DELETE_TOKEN + .encodeCallWithArgs(C_TOKEN_ADDRESS) + .array()), + output -> assertEquals( + Bytes.wrap(ReturnTypes.encodedRc(INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE) + .array()), + output)); + + // Fail if token has wrong admin key + runHtsCallAndExpectOnSuccess( + SENDER_BESU_ADDRESS, + Bytes.wrap(DeleteTranslator.DELETE_TOKEN + .encodeCallWithArgs(D_TOKEN_ADDRESS) + .array()), + output -> assertEquals( + Bytes.wrap(ReturnTypes.encodedRc(INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE) + .array()), + output)); + // should fail when token has invalid address runHtsCallAndExpectOnSuccess( SENDER_BESU_ADDRESS, @@ -122,8 +195,40 @@ protected Map initialTokens() { Token.newBuilder() .tokenId(ERC721_TOKEN_ID) .treasuryAccountId(SENDER_ID) + .tokenType(TokenType.NON_FUNGIBLE_UNIQUE) + .adminKey(SENDER_CONTRACT_ID_KEY) + .freezeKey(SENDER_CONTRACT_ID_KEY) + .build()); + tokens.put( + A_TOKEN_ID, + Token.newBuilder() + .tokenId(A_TOKEN_ID) + .treasuryAccountId(SENDER_ID) .tokenType(TokenType.FUNGIBLE_COMMON) .build()); + tokens.put( + B_TOKEN_ID, + Token.newBuilder() + .tokenId(B_TOKEN_ID) + .treasuryAccountId(SENDER_ID) + .tokenType(TokenType.NON_FUNGIBLE_UNIQUE) + .build()); + tokens.put( + C_TOKEN_ID, + Token.newBuilder() + .tokenId(C_TOKEN_ID) + .treasuryAccountId(UNAUTHORIZED_SPENDER_ID) + .tokenType(TokenType.FUNGIBLE_COMMON) + .adminKey(AN_ED25519_KEY) + .build()); + tokens.put( + D_TOKEN_ID, + Token.newBuilder() + .tokenId(D_TOKEN_ID) + .treasuryAccountId(UNAUTHORIZED_SPENDER_ID) + .tokenType(TokenType.NON_FUNGIBLE_UNIQUE) + .adminKey(AN_ED25519_KEY) + .build()); return tokens; }