반응형
Web3j는 이더리움 블록체인과 상호작용하기 위한 자바 라이브러리입니다. 이러한 기술을 결합하여 이더리움 스마트 컨트랙트와 통신하는 방법을 소스로 보여드리겠습니다.
여기에서는 Infura API apiKey 및 smart contract wrapper java 파일이 준비되어 있어야 합니다.
1. Infura API apiKey는 아래 사이트에서 가입 후 얻으실 수 있습니다.
2. smart contract wrapper 파일은 솔리디티의 ABI파일을 java로 변환한 파일입니다.
여기에서는 예제로 만들어놓은 NFT 솔리디티를 java로 변환하여 진행하였습니다.
전체 소스는 맨 아래 깃허브 주소를 남겨놓았으며 변환된 wrapper 파일은 아래 경로에서 확인하실 수 있습니다.
예제로 만들어놓은 NFT 스마트컨트랙트 주소는 아래와 같습니다.
0x16a7d4f76197d5b77048189a4e31ae86f58a5eaa
3. 아래는 소스 내용입니다.
pom.xml
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.9.6</version>
</dependency>
application.yml 파일
metamask:
WALLET_ADDRESS: "" # 지갑 주소
CONTRACT_ADDRESS: "0x16a7d4f76197d5b77048189a4e31ae86f58a5eaa" # 통신할 스마트컨트랙트 주소
PRIVATE_KEY: "" # 지갑 private key
infura:
API_URL: "https://goerli.infura.io/v3/[apiKey]" # infura goerli api url 정보
Web3jConfig.java 파일
@Configuration
public class Web3jConfig {
@Value("${infura.API_URL}")
private String INFURA_API_URL;
@Value("${metamask.PRIVATE_KEY}")
private String PRIVATE_KEY;
@Value("${metamask.CONTRACT_ADDRESS}")
private String CONTRACT_ADDRESS;
@Bean
public Web3j web3j() {
return Web3j.build(new HttpService(INFURA_API_URL));
}
@Bean
public Credentials credentials() {
BigInteger privateKeyInBT = new BigInteger(PRIVATE_KEY, 16);
return Credentials.create(ECKeyPair.create(privateKeyInBT));
}
@Bean
public NFT nft() {
BigInteger gasPrice = Contract.GAS_PRICE;
BigInteger gasLimit = Contract.GAS_LIMIT;
StaticGasProvider gasProvider = new StaticGasProvider(gasPrice, gasLimit);
return NFT.load(CONTRACT_ADDRESS, web3j(), credentials(), gasProvider);
}
}
Web3jService.java 파일
@Slf4j
@RequiredArgsConstructor
@Service("web3jService")
public class Web3jService {
private final Web3j web3j;
private final NFT nft;
@Value("${metamask.WALLET_ADDRESS}")
private String WALLET_ADDRESS;
@Value("${metamask.CONTRACT_ADDRESS}")
private String CONTRACT_ADDRESS;
// 현재 블록 번호
public EthBlockNumber getBlockNumber() throws ExecutionException, InterruptedException {
return web3j.ethBlockNumber().sendAsync().get();
}
// 지정된 주소의 계정
public EthAccounts getEthAccounts() throws ExecutionException, InterruptedException {
return web3j.ethAccounts().sendAsync().get();
}
// 계좌 거래 건수
public EthGetTransactionCount getTransactionCount() throws ExecutionException, InterruptedException {
EthGetTransactionCount result = new EthGetTransactionCount();
result = web3j.ethGetTransactionCount(WALLET_ADDRESS,
DefaultBlockParameter.valueOf("latest"))
.sendAsync()
.get();
return result;
}
// 계정 잔액 조회
public EthGetBalance getEthBalance() throws ExecutionException, InterruptedException {
return web3j.ethGetBalance(WALLET_ADDRESS,
DefaultBlockParameter.valueOf("latest"))
.sendAsync()
.get();
}
// 스마트컨트랙트명 가져오기
public String getContractName() throws Exception {
return nft.name().send();
}
// nft 발행 건수
public BigInteger currentCount() throws Exception {
return nft.balanceOf(WALLET_ADDRESS).send();
}
// nft 발행
public TransactionReceipt nftCreate() throws Exception {
return nft.create(WALLET_ADDRESS, "ipfs://QmNZLXLk8nWG4PMdcCWAGpgW12hAhiV375YeFpaCLisfBi")
.sendAsync()
.get();
}
// nft 거래가 발생할 경우 subscribe에 등록한 함수가 실행됨
public void transferEventFlowable() throws Exception {
web3j.ethLogFlowable(getEthFilter())
.subscribe(logData -> {
log.info("logData : {}", logData);
String data = logData.getData();
log.info("data : {}", data);
String address = logData.getAddress();
log.info("address : {}", address);
});
Thread.sleep(10000000);
}
// 이더리움 블록체인에서 발생하는 이벤트를 필터링하는데 사용(여기에서는 Transfer(거래)만 허용)
private EthFilter getEthFilter() throws Exception {
EthBlockNumber blockNumber = getBlockNumber();
EthFilter ethFilter = new EthFilter(DefaultBlockParameter.valueOf(blockNumber.getBlockNumber()), DefaultBlockParameterName.LATEST, CONTRACT_ADDRESS);
Event event = new Event("Transfer",
Arrays.asList(
new TypeReference<Address>(true) {
// from
},
new TypeReference<Address>(true) {
},
new TypeReference<Uint256>(false) {
// amount
}
));
String topicData = EventEncoder.encode(event);
ethFilter.addSingleTopic(topicData);
ethFilter.addNullTopic();// filter: event type (topic[0])
//ethFilter.addOptionalTopics("0x"+ TypeEncoder.encode(new Address("")));
return ethFilter;
}
}
Web3jServiceTest.java Junit 테스트 파일 입니다.
@Slf4j
@SpringBootTest
class Web3jServiceTest {
@Resource(name = "web3jService")
private Web3jService web3jService;
@Test
public void getBlockNumber() throws ExecutionException, InterruptedException {
EthBlockNumber ethBlockNumber = web3jService.getBlockNumber();
long id = ethBlockNumber.getId();
BigInteger blockNumber = ethBlockNumber.getBlockNumber();
log.info("id : {}", id);
log.info("blockNumber : {}", blockNumber);
}
@Test
public void getEthAccounts() throws ExecutionException, InterruptedException {
EthAccounts ethAccounts = web3jService.getEthAccounts();
List<String> accounts = ethAccounts.getAccounts();
log.info("accounts : {}", accounts);
}
@Test
public void getTransactionCount() throws ExecutionException, InterruptedException {
EthGetTransactionCount ethGetTransactionCount = web3jService.getTransactionCount();
BigInteger transactionCount = ethGetTransactionCount.getTransactionCount();
log.info("transactionCount : {}", transactionCount);
}
@Test
public void getEthBalance() throws ExecutionException, InterruptedException {
EthGetBalance ethGetBalance = web3jService.getEthBalance();
BigInteger balance = ethGetBalance.getBalance();
log.info("balance : {}", balance);
}
@Test
public void getContractName() throws Exception {
String contractName = web3jService.getContractName();
log.info("contractName : {}", contractName);
}
@Test
public void currentCount() throws Exception {
BigInteger currentCount = web3jService.currentCount();
log.info("currentCount : {}", currentCount);
}
@Test
public void nftCreate() throws Exception {
log.info("start time : {}", LocalDateTime.now());
TransactionReceipt transactionReceipt = web3jService.nftCreate();
log.info("transactionReceipt : {}", transactionReceipt);
log.info("end time : {}", LocalDateTime.now());
}
@Test
public void transferEventFlowable() throws Exception {
web3jService.transferEventFlowable();
}
}
전체 소스는 아래 깃 허브에 있습니다.
https://github.com/shan0325/blockchain/tree/master/back-web3j-ex01
반응형