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

E2E: ERC721 Contract Interaction #599

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class ContractResources {
public static final String INLINE_TEST_BYTECODE_PATH = bytecodePath("InlineTest");
public static final String INVALID_BYTECODE_PATH = bytecodePath("CorruptOne");
public static final String VALID_BYTECODE_PATH = HapiSpecSetup.getDefaultInstance().defaultContractPath();
public static final String ERC721_BYTECODE_PATH = bytecodePath("ERC721");
public static final String VERBOSE_DEPOSIT_BYTECODE_PATH = bytecodePath("VerboseDeposit");
public static final String GROW_ARRAY_BYTECODE_PATH = bytecodePath("GrowArray");
public static final String BIG_ARRAY_BYTECODE_PATH = bytecodePath("BigArray");
Expand Down Expand Up @@ -71,6 +72,18 @@ public class ContractResources {

public static final String BENCHMARK_GET_COUNTER = "{ \"inputs\": [], \"name\": \"counter\", \"outputs\": [ { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" } ], \"stateMutability\": \"view\", \"type\": \"function\" }";

public static final String ERC721_MINT_ABI = "{ \"inputs\": [ { \"internalType\": \"address\"," +
" \"name\": \"player\", \"type\": \"address\" }, { \"internalType\": \"uint256\", \"name\": \"tokenid\", \"type\": \"uint256\" } ]," +
" \"name\": \"mint\", \"outputs\": [ { \"internalType\": \"uint256\", " +
"\"name\": \"\", \"type\": \"uint256\" } ], " +
"\"stateMutability\": \"nonpayable\", \"type\": \"function\" }";
public static final String ERC721_APPROVE_ABI = "{ \"inputs\": [ { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" }, " +
"{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" } ], \"name\": \"approve\", \"outputs\": [], " +
"\"stateMutability\": \"nonpayable\", \"type\": \"function\" }";
public static final String ERC721_TRANSFER_FROM_ABI = "{ \"inputs\": [ { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" }, " +
"{ \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" }, " +
"{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" } ], " +
"\"name\": \"transferFrom\", \"outputs\": [], \"stateMutability\": \"nonpayable\", \"type\": \"function\" }";
public static final String CREATE_CHILD_ABI = "{\"constant\":false," +
"\"inputs\":[],\"name\":\"create\"," +
"\"outputs\":[]," +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.contractCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.cryptoCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.fileCreate;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.CONTRACT_EXECUTION_EXCEPTION;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.CONTRACT_REVERT_EXECUTED;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.ERROR_DECODING_BYTESTRING;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_GAS;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.hedera.services.bdd.suites.contract.openzeppelin;
georgiyazovaliiski marked this conversation as resolved.
Show resolved Hide resolved

/*-
* ‌
* Hedera Services Test Clients
* ​
* Copyright (C) 2018 - 2021 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 com.google.protobuf.ByteString;
import com.hedera.services.bdd.spec.HapiApiSpec;
import com.hedera.services.bdd.spec.queries.QueryVerbs;
import com.hedera.services.bdd.suites.HapiApiSuite;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import static com.hedera.services.bdd.spec.HapiApiSpec.defaultHapiSpec;
import static com.hedera.services.bdd.spec.infrastructure.meta.ContractResources.ERC721_APPROVE_ABI;
import static com.hedera.services.bdd.spec.infrastructure.meta.ContractResources.ERC721_BYTECODE_PATH;
import static com.hedera.services.bdd.spec.infrastructure.meta.ContractResources.ERC721_MINT_ABI;
import static com.hedera.services.bdd.spec.infrastructure.meta.ContractResources.ERC721_TRANSFER_FROM_ABI;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.contractCall;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.contractCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.cryptoCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.fileCreate;
import static com.hedera.services.bdd.spec.utilops.CustomSpecAssert.allRunFor;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.updateLargeFile;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.withOpContext;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.SUCCESS;

public class ERC721ContractInteractions extends HapiApiSuite {
private static final Logger log = LogManager.getLogger(ERC721ContractInteractions.class);

public static void main(String... args) {
new ERC721ContractInteractions().runSuiteSync();
}

@Override
protected Logger getResultsLogger() {
return log;
}

@Override
protected List<HapiApiSpec> getSpecsInSuite() {
return List.of(
callsERC721ContractInteractions()
);
}

private HapiApiSpec callsERC721ContractInteractions() {
final var PAYER = "tx_payer";
final var CONTRACT_CREATOR = "contractCreator";
final var NFT_SENDER = "sender";
final var CONTRACT_FILE_NAME = "ERC721ContractFile";
final var NFT_ID = 1;

final var CREATE_TX = "create";
final var MINT_TX = "mint";
final var APPROVE_TX = "approve";
final var TRANSFER_FROM_TX = "transferFrom";

return defaultHapiSpec("CallsERC721ContractInteractions")
.given(
cryptoCreate(PAYER).balance(ONE_HUNDRED_HBARS),
cryptoCreate(CONTRACT_CREATOR),
cryptoCreate(NFT_SENDER),
QueryVerbs.getAccountBalance(PAYER).logged(),
fileCreate(CONTRACT_FILE_NAME).payingWith(PAYER),
updateLargeFile(PAYER, CONTRACT_FILE_NAME, extractByteCode(ERC721_BYTECODE_PATH))
).when(
QueryVerbs.getAccountBalance(PAYER).logged(),
contractCreate("testContract")
.payingWith(CONTRACT_CREATOR)
.bytecode(CONTRACT_FILE_NAME)
.hasKnownStatus(SUCCESS)
.via(CREATE_TX)
).then(
QueryVerbs.getAccountInfo(CONTRACT_CREATOR).savingSnapshot(CONTRACT_CREATOR),
QueryVerbs.getAccountInfo(NFT_SENDER).savingSnapshot(NFT_SENDER),

withOpContext((spec, log) -> {
final var contractCreatorId = spec.registry().getAccountInfo(CONTRACT_CREATOR).getContractAccountID();
final var nftSenderId = spec.registry().getAccountInfo(NFT_SENDER).getContractAccountID();

final var mintParams = new Object[]{nftSenderId, NFT_ID};
final var approveParams = new Object[]{contractCreatorId, NFT_ID};
final var transferFromParams = new Object[]{nftSenderId, contractCreatorId, NFT_ID};

final var mint = contractCall("testContract",
ERC721_MINT_ABI, mintParams).payingWith(CONTRACT_CREATOR).via(MINT_TX);
allRunFor(spec, mint);

final var approve = contractCall("testContract",
ERC721_APPROVE_ABI, approveParams).payingWith(NFT_SENDER).via(APPROVE_TX);
allRunFor(spec, approve);

final var transferFrom = contractCall("testContract",
ERC721_TRANSFER_FROM_ABI, transferFromParams).payingWith(CONTRACT_CREATOR).via(TRANSFER_FROM_TX);
allRunFor(spec, transferFrom);
}),
QueryVerbs.getTxnRecord(CREATE_TX).logged(),
QueryVerbs.getTxnRecord(MINT_TX).logged(),
QueryVerbs.getTxnRecord(APPROVE_TX).logged(),
QueryVerbs.getTxnRecord(TRANSFER_FROM_TX).logged()
);
}

private ByteString extractByteCode(String path) {
try {
var bytes = Files.readAllBytes(Path.of(path));
return ByteString.copyFrom(bytes);
} catch (IOException e) {
e.printStackTrace();
return ByteString.EMPTY;
}
}
}