[KAS SDK] KAS API와 통합된 지갑, KASWallet

Tech at Klaytn
Klaytn
Published in
60 min readDec 23, 2020

전체 포스팅 목록은 여기에서 확인하세요.

KAS SDK v1.0.2 에서는 KAS Wallet API와 통합된 지갑인 KASWallet을 소개합니다. KASWallet은 기존 Caver에서 제공되던 편리한 기능들이 KAS Wallet API에 저장되어 있는 Klaytn 계정과 함께 사용되기 위하여 제공되는 기능입니다.

이 포스팅에서는 KASWallet의 정의와 사용 방법을 설명합니다.

1. KASWallet 이란

KASWallet이란 기존 Caver의 `caver.wallet`에서 제공되던 in-memory wallet인 KeyringContainer에 상응하는 기능을 KAS Wallet API를 사용하여 동작하도록 구현된 지갑입니다.

Caver의 `caver.contract`, `caver.kct.kip7` 그리고 `caver.kct.kip17`은 `caver.wallet`을 사용하여 내부적으로 생성한 트랜잭션에 서명하고 네트워크에 전송하도록 동작합니다. 그렇기 때문에 이전 KAS SDK에서는 KAS Wallet API에 저장된 Klaytn 계정과 함께 `caver.contract`, `caver.kct.kip7` 혹은 `caver.kct.kip17`에서 제공되는 기능들을 사용하는데에 한계가 있었습니다.

KAS SDK v1.0.2부터는 KASWallet을 `caver.wallet`을 통하여 제공함으로써 KAS Wallet API에 저장된 Klaytn 계정을 사용하여 컨트랙트를 쉽게 배포하거나 실행할 수 있게 되었습니다. 또한 Caver에서 제공하는 트랜잭션을 KAS Wallet API에 저장된 Klaytn 계정을 사용하여 서명할 수 있습니다.

2. KASWallet 구조

위는 KASWallet을 설명하기 위한 다이어그램입니다.

`KeyringContainer`와 `KASWallet`은 각각 `IWallet` 인터페이스를 구현하고, `Caver`는 `wallet` 멤버변수에 `KeyringContainer`의 인스턴스를, `CaverExtKAS`는 `KASWallet`의 인스턴스를 `wallet` 변수에 정의하고 있습니다.

또한 `wallet` 멤버 변수에 대한 getter인 `getWallet`을 `Caver`와 `CaverExtKAS` 모두 `IWallet`을 리턴하도록 구현해야 합니다. 그래서 `Contract`, `KIP7` 그리고 `KIP17`에서는 getWallet`을 통해 `IWallet` 인터페이스를 구현한 클래스인 `KeyringContainer` 혹은 `KASWallet` 인스턴스를 리턴받아 동작하도록 구현되었습니다. Contract, KIP7 그리고 KIP17이 동작하는 데에 필요한 함수는 모두 IWallet에 정의되어 있습니다.

3. KAS Wallet API의 Klaytn 계정과 함께 caver.contract 사용하기

KAS SDK의 `caver.wallet`은 KASWallet이기 때문에 KAS SDK의 `caver.contract`를 사용하면 KAS Wallet API 에 저장되어 있는 Klaytn 계정을 사용하여 손쉽게 Klaytn에 컨트랙트를 배포하거나 실행할 수 있습니다. KAS Wallet API의 Klaytn 계정을 사용하여 `caver.contract`를 사용하는 방법은 기존 Caver의 `caver.contract`를 사용하는 방법과 동일합니다.

여기서는 간단하게 배포하고 실행하는 방법을 설명합니다. 여기서 스마트 컨트랙트를 배포하고 실행할 때 사용되는 Klaytn 계정은 KAS Wallet API에서 관리되고 있는 계정이며, 이 Klaytn 계정은 트랜잭션을 전송하기 위한 충분한 KLAY를 소유하고 있어야 합니다.

3.1. caver-js-ext-kas

caver-js-ext-kas의 `caver.contract`를 사용하는 방법은 caver-js의 `caver.contract`를 사용하는 방법과 동일합니다.

3.1.1. 스마트 컨트랙트 배포

caver-js-ext-kas를 사용하여 스마트 컨트랙트를 배포하는 방법에 대해서 아래에 설명합니다.

const contract = new caver.contract(abi)

먼저 `caver.contract`를 사용하여 Contract 인스턴스를 생성합니다.

const deployed = await contract.deploy({ data: byteCode }).send({ from: '0x{the address of a Klaytn account in KAS Wallet API}', gas: 10000000 })

그 이후 contract 인스턴스의 `deploy` 메소드를 호출합니다. `deploy`는 트랜잭션을 네트워크로 전송하는 `send` 함수가 정의된 오브젝트를 리턴합니다.

결과로 리턴 받은 오브젝트의 `send` 함수를 호출해야 실제로 네트워크로 트랜잭션이 전송되게 됩니다. 예제에서는 `send`함수를 호출할 때 넘겨주는 파라미터 오브젝트에 `from`과 `gas`를 정의해 주고 있는데, 이 때 from 주소는 KAS Wallet API에 저장되어 있는 Klaytn 계정의 주소이어야 합니다.

위의 코드를 실행하면 내부적으로 SmartContractDeploy 트랜잭션을 생성하고 KAS Wallet API에 저장되어 있는 `from`의 계정으로 트랜잭션에 서명한 후 네트워크에 전송합니다. 배포의 결과로는 배포된 컨트랙트의 정보를 포함하고 있는 Contract 인스턴스가 리턴됩니다.

3.1.2. 스마트 컨트랙트 실행

caver-js-ext-kas를 사용하여 Klaytn에 배포된 스마트 컨트랙트를 실행하는 방법은 아래와 같습니다.

const contractAddress = '0x5D3Cd9eB73f00BbECB949DCE08BB26019FcB599f'
const contract = new caver.contract(abi, contractAddress)

배포할 때와 동일하게 스마트 컨트랙트를 실행하기 위하여 먼저 contract 인스턴스를 생성합니다. 생성자에 전달하는 파라미터로는 스마트 컨트랙트의 ABI와 배포된 컨트랙트의 주소를 넘겨줍니다.

const receipt = await contract.methods.set('key', 'value').send({ from: '0x{the address of a Klaytn account in KAS Wallet API}', gas: 5000000 })

생성된 contract는 `methods`를 통해 스마트 컨트랙트에 정의되어 있는 함수를 사용할 수 있습니다. 그 이후 `contract.methods`로 컨트랙트에 정의된 함수를 사용할 수 있습니다. 좀 전과 마찬가지로 각 함수를 호출하면 실제 네트워크에 트랜잭션을 전송하는 `send` 함수가 정의된 오브젝트가 리턴이 됩니다.

리턴 받은 오브젝트에 정의된 `send`를 호출하여 스마트 컨트랙트를 실행합니다. `send`에 전달되는 오브젝트 파라미터에는 `from`과 `gas`가 정의되어 있으며, `from`은 KAS Wallet API에 저장된 Klaytn 계정의 주소이어야 합니다.

위의 코드를 실행하면 내부적으로 SmartContractExecution 트랜잭션을 생성하고 KAS Wallet API에 저장되어 있는 `from`의 계정으로 트랜잭션에 서명한 후 네트워크에 전송합니다. 컨트랙트 실행의 결과로는 트랜잭션 receipt이 리턴됩니다.

3.2. caver-java-ext-kas

3.2.1. 스마트 컨트랙트 배포

caver-java-ext-kas를 사용하여 스마트 컨트랙트를 배포하는 방법에 대해서 아래에 설명합니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");
Contract contract = new Contract(caver, ABI);

먼저 `Contract`인스턴스를 생성합니다.

SendOptions sendOptions = new SendOptions("0x{the address of a Klaytn account in KAS Wallet API}", BigInteger.valueOf(10000000));
Contract deployed = contract.deploy(sendOptions, BINARY);

그 이후 contract 인스턴스의 `deploy` 메소드를 호출합니다. `deploy`의 파라미터로는 트랜잭션 전송에 필요한 SendOptions, 스마트 컨트랙트의 바이트코드, 그리고 마지막으로 스마트 컨트랙트의 생성자 파라미터를 차례대로 넘겨줍니다. 위 코드는 배포하고자 하는 스마트 컨트랙트의 생성자에서 받는 파라미터가 없으므로 sendOptions와 BINARY만 파라미터로 전달합니다.

위 예제에서는 `SendOptions`에 `from`과 `gas`를 정의해 주고 있는데, 이 때 from 주소는 KAS Wallet API에 저장되어 있는 Klaytn 계정의 주소이어야 합니다.

위의 코드를 실행하면 내부적으로 SmartContractDeploy 트랜잭션을 생성하고 KAS Wallet API에 저장되어 있는 `from`의 계정으로 트랜잭션에 서명한 후 네트워크에 전송합니다. 배포의 결과로는 배포된 컨트랙트의 정보를 포함하고 있는 Contract 인스턴스가 리턴됩니다.

3.2.2. 스마트 컨트랙트 실행

caver-java-ext-kas를 사용하여 Klaytn에 배포된 스마트 컨트랙트를 실행하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");
String address = "Your contract address";
Contract contract = new Contract(caver, ABI, address);

배포할 때와 동일하게 스마트 컨트랙트를 실행하기 위하여 먼저 contract 인스턴스를 생성합니다.

SendOptions sendOptions = new SendOptions("0x{the address of a Klaytn account in KAS Wallet API}", BigInteger.valueOf(5000000));
TransactionReceipt.TransactionReceiptData receiptData
= contract.send(sendOptions,"set", "key", "value");

생성된 contract에는 스마트 컨트랙트를 실행하는 `send` 함수가 정의되어 있습니다. `send` 함수를 호출할 때 첫 번째 파라미터로는 트랜잭션을 실행할 때 필요한 SendOptions, 실행하고자 하는 스마트 컨트랙트 함수의 이름, 그리고 마지막으로 스마트 컨트랙트 함수의 파라미터를 차례대로 넘겨줍니다.

위의 코드를 실행하면 내부적으로 SmartContractExecution 트랜잭션을 생성하고 KAS Wallet API에 저장되어 있는 `from`의 계정으로 트랜잭션에 서명한 후 네트워크에 전송합니다. 컨트랙트 실행의 결과로는 트랜잭션 receipt이 리턴됩니다.

4. KAS Wallet API의 Klaytn 계정과 함께 caver.kct 사용하기

KAS Wallet API에 저장되어 있는 Klaytn 계정을 사용하여 `caver.kct`를 사용하는 방법은 기존 Caver의 `caver.kct`를 사용하는 방법과 동일합니다.

여기서는 간단하게 KIP-7 토큰 컨트랙트와 KIP-17 토큰 컨트랙트를 배포하고 실행하는 방법을 설명합니다. 여기서 토큰 컨트랙트를 배포하고 실행할 때 사용되는 Klaytn 계정은 KAS Wallet API에서 관리되고 있는 계정이며, 이 Klaytn 계정은 트랜잭션을 전송하기 위한 충분한 KLAY를 소유하고 있어야 합니다.

4.1. caver-js-ext-kas

caver-js-ext-kas의 `caver.kct.kip7`을 사용하는 방법은 caver-js의 `caver.kct.kip7`을 사용하는 방법과 동일합니다.

4.1.1. KIP-7 토큰 컨트랙트 배포

caver-js-ext-kas를 사용하여 KIP-7 토큰 컨트랙트를 배포하는 방법은 아래와 같습니다.

const deployed = await caver.kct.kip7.deploy({
name: 'Jasmine',
symbol: 'JAS',
decimals: 18,
initialSupply: '100000000000000000000'
}, '0x{the address of a Klaytn account in KAS Wallet API}')

KIP7에서 제공되는 static 함수인 `caver.kct.kip7.deploy`를 사용하여 KIP-7 토큰 컨트랙트를 배포합니다. 파라미터로는 배포하고자 하는 토큰 컨트랙트의 정보, 그리고 배포할 때 사용할 Klaytn 계정의 주소를 넘겨줍니다. 위의 예제에서 배포할 때 사용할 Klaytn 계정의 주소는 KAS Wallet API에 저장되어 있는 계정의 주소이어야 합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-7 토큰 컨트랙트가 배포되며, 배포의 결과로 배포된 KIP-7 컨트랙트의 정보가 담긴 KIP7 인스턴스가 리턴됩니다.

4.1.2. KIP-7 토큰 컨트랙트 실행

caver-js-ext-kas를 사용하여 Klaytn에 배포된 KIP-7 토큰 컨트랙트를 실행하는 방법은 아래와 같습니다.

const contractAddress = '0x42c3809EeED7c5C497067fE4092D1c354D3a01Cb'
const kip7 = new caver.kct.kip7(contractAddress)

먼저 배포된 KIP-7 컨트랙트 주소를 생성자 파라미터로 전달하여 KIP7 인스턴스를 생성합니다.

const receipt = await kip7.transfer('0x{address in hex}', 1, { from: '0x{the address of a Klaytn account in KAS Wallet API}' })

그리고 생성된 KIP7 인스턴스의 메소드를 호출하면 됩니다. 예제에서는 `kip7.transfer` 함수를 호출하는데 파라미터로는 실제 KIP-7 토큰 컨트랙트 transfer 함수의 파라미터를 차례대로 전달하고 마지막으로 파라미터로는 트랜잭션 전송에 필요한 정보들이 정의된 오브젝트를 전달합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-7 토큰 컨트랙트가 실행되며, 실행의 결과로 트랜잭션 receipt이 리턴됩니다.

4.1.3. KIP-17 토큰 컨트랙트 배포

caver-js-ext-kas를 사용하여 KIP-17 토큰 컨트랙트를 배포하거나 실행하는 코드는 KIP-7과 비슷합니다. KIP-17 토큰 컨트랙트를 배포하는 방법은 아래와 같습니다.

const deployed = await caver.kct.kip17.deploy({
name: 'Jasmine',
symbol: 'JAS',
}, '0x{the address of a Klaytn account in KAS Wallet API}')

KIP17에서 제공되는 static 함수인 `caver.kct.kip17.deploy`를 사용하여 KIP-17 토큰 컨트랙트를 배포합니다. 파라미터로는 배포하고자 하는 토큰 컨트랙트의 정보, 그리고 배포할 때 사용할 Klaytn 계정의 주소를 넘겨줍니다. 위의 예제에서 배포할 때 사용할 Klaytn 계정의 주소는 KAS Wallet API에 저장되어 있는 계정의 주소이어야 합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-17 토큰 컨트랙트가 배포되며, 배포의 결과로 배포된 KIP-17 컨트랙트의 정보가 담긴 KIP17 인스턴스가 리턴됩니다.

4.1.4. KIP-17 토큰 컨트랙트 실행

caver-js-ext-kas를 사용하여 Klaytn에 배포된 KIP-17 토큰 컨트랙트를 실행하는 방법은 아래와 같습니다.

const contractAddress = '0xAD719B194457D0641B410Ce75C4D22442533A781'
const kip17 = new caver.kct.kip17(contractAddress)

먼저 배포된 KIP-17 컨트랙트 주소를 생성자 파라미터로 전달하여 KIP17 인스턴스를 생성합니다.

const receipt = await kip17.mintWithTokenURI('0x{address i hex}', tokenId, tokenURI, { from: '0x{the address of a Klaytn account in KAS Wallet API}' })

그리고 생성된 KIP17 인스턴스의 메소드를 호출하면 됩니다. 예제에서는 `kip17.mintWithTokenURI` 함수를 호출하는데 파라미터로는 실제 KIP-17 토큰 컨트랙트 mintWithTokenURI 함수의 파라미터를 차례대로 전달하고 마지막으로 파라미터로는 트랜잭션 전송에 필요한 정보들이 정의된 오브젝트를 전달합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-17 토큰 컨트랙트가 실행되며, 마찬가지로 실행의 결과로 트랜잭션 receipt이 리턴됩니다.

4.2. caver-java-ext-kas

4.2.1. KIP-7 토큰 컨트랙트 배포

caver-java-ext-kas를 사용하여 KIP-7 토큰 컨트랙트를 배포하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");
String deployer = "0x{address in hex}";
int decimals = 18;
BigInteger initialSupply = BigInteger.valueOf(100).multiply(BigInteger.TEN.pow(decimals)); // 100 * 10¹⁸
KIP7 kip7 = KIP7.deploy(caver, deployer, "Jasmine", "JAS", decimals, initialSupply);

KIP7에서 제공되는 static 함수인 `deploy`를 사용하여 KIP-7 토큰 컨트랙트를 배포합니다. 파라미터로는 CaverExtKAS instance와 배포할 때 사용할 Klaytn 계정의 주소, 그리고 배포하고자 하는 토큰 컨트랙트의 정보를 넘겨줍니다. 위의 예제에서 배포할 때 사용할 Klaytn 계정의 주소는 KAS Wallet API에 저장되어 있는 계정의 주소이어야 합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-7 토큰 컨트랙트가 배포되며, 배포의 결과로 배포된 KIP-7 컨트랙트의 정보가 담긴 KIP7 인스턴스가 리턴됩니다.

4.2.2. KIP-7 토큰 컨트랙트 실행

caver-java-ext-kas를 사용하여 Klaytn에 배포된 KIP-7 토큰 컨트랙트를 실행하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");String address = "0x42c3809EeED7c5C497067fE4092D1c354D3a01Cb";
KIP7 kip7 = new KIP7(caver, address);

먼저 배포된 CaverExtKAS instance와, KIP-7 컨트랙트 주소를 생성자 파라미터로 전달하여 KIP7 인스턴스를 생성합니다.

SendOptions sendOptions = new SendOptions(baseAccount);
String toAccount = "0x{to address}";
BigInteger transferAmount = BigInteger.TEN.multiply(BigInteger.TEN.pow(18)); // 10 * 10¹⁸
TransactionReceipt.TransactionReceiptData receiptData = kip7.transfer(toAccount, transferAmount, sendOptions);

그리고 생성된 KIP7 인스턴스의 메소드를 호출하면 됩니다. 예제에서는 `kip7.transfer` 함수를 호출하는데 파라미터로는 실제 KIP-7 토큰 컨트랙트 transfer 함수의 파라미터를 차례대로 전달하고 마지막으로 파라미터로는 트랜잭션 전송에 필요한 정보들이 정의된 오브젝트를 전달합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-7 토큰 컨트랙트가 실행되며, 실행의 결과로 트랜잭션 receipt이 리턴됩니다.

4.2.3. KIP-17 토큰 컨트랙트 배포

caver-java-ext-kas를 사용하여 KIP-17 토큰 컨트랙트를 배포하거나 실행하는 코드는 KIP-7과 비슷합니다. KIP-17 토큰 컨트랙트를 배포하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");String deployer = "0x{address in hex}";KIP17 kip17 = KIP17.deploy(caver, deployer, "Jasmine", "JAS");

KIP17에서 제공되는 static 함수인 `deploy`를 사용하여 KIP-17 토큰 컨트랙트를 배포합니다. 파라미터로는 CaverExtKAS instance와 배포할 때 사용할 Klaytn 계정의 주소, 그리고 배포하고자 하는 토큰 컨트랙트의 정보를 넘겨줍니다. 위의 예제에서 배포할 때 사용할 Klaytn 계정의 주소는 KAS Wallet API에 저장되어 있는 계정의 주소이어야 합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-17 토큰 컨트랙트가 배포되며, 배포의 결과로 배포된 KIP-17 컨트랙트의 정보가 담긴 KIP17 인스턴스가 리턴됩니다.

4.2.4. KIP-17 토큰 컨트랙트 실행

caver-java-ext-kas를 사용하여 Klaytn에 배포된 KIP-17 토큰 컨트랙트를 실행하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");String contractAddress = "'0xAD719B194457D0641B410Ce75C4D22442533A781'";
KIP17 kip17 = new KIP17(caver, contractAddress);

먼저 배포된 CaverExtKAS instance와 KIP-17 컨트랙트 주소를 생성자 파라미터로 전달하여 KIP17 인스턴스를 생성합니다.

String from = "0x{from address}";
String to = "0x{to address}";
String tokenURI = "tokenURI";
SendOptions sendOptions = new SendOptions(from);
TransactionReceipt.TransactionReceiptData receiptData = kip17.mintWithTokenURI(to, BigInteger.ZERO, tokenURI, sendOptions);

그리고 생성된 KIP17 인스턴스의 메소드를 호출하면 됩니다. 예제에서는 `kip17.mintWithTokenURI` 함수를 호출하는데 파라미터로는 실제 KIP-17 토큰 컨트랙트 mintWithTokenURI 함수의 파라미터를 차례대로 전달하고 마지막으로 파라미터로는 트랜잭션 전송에 필요한 정보들이 정의된 오브젝트를 전달합니다.

위의 코드가 실행되면 KAS Wallet API에 저장되어 있는 계정을 사용하여 KIP-17 토큰 컨트랙트가 실행되며, 마찬가지로 실행의 결과로 트랜잭션 receipt이 리턴됩니다.

5. KAS SDK 에서 KeyringContainer 사용하기

KAS SDK에서는 기존 caver의 `caver.wallet`에서 제공되던 in-memory wallet인 `KeyringContainer`을 대신하여 KAS Wallet API를 사용하는 `KASWallet`이 제공됩니다. 그래서 KAS SDK에서 in-memory wallet인 `KeyringContainer`를 사용하고 싶으면 따로 인스턴스화를 해서 사용해야 합니다.

또한 caver-js-ext-kas와 caver-java-ext-kas 모두 `caver.contract`와 `caver.kct`에서 컨트랙트를 배포하거나 실행할 때 사용하는 지갑을 지정할 수 있는 `setWallet` 함수가 제공됩니다. 이를 통하여 KAS SDK를 사용할 때 인스턴스 별로 컨트랙트를 배포하거나 실행할 때 사용될 지갑을 유연하게 지정하여 사용할 수 있습니다.

5.1. caver-js-ext-kas

아래는 caver-js-ext-kas를 사용하여 `KeyringContainer` 인스턴스를 생성하는 방법입니다.

const keyringContainer = new caver.keyringContainer()

위의 방식으로 생성된 keyringContainer를 `caver.contract`, `caver.kct.kip7` 그리고 `caver.kct.kip17`에서 사용하는 방법은 아래와 같습니다.

const contract = new caver.contract(abi, contractAddress)
contract.setWallet(keyringContainer)
const kip7 = new caver.kct.kip7(contractAddress)
kip7.setWallet(keyringContainer)
const kip7 = new caver.kct.kip17(contractAddress)
kip7.setWallet(keyringContainer)

위와 같이 Contract 인스턴스의 setWallet 메소드를 호출하면 contract에서 사용하는 IWallet을 지정할 수 있습니다. 이는 KIP7과 KIP17 모두 동일하게 동작합니다.

KIP7과 KIP17에서 제공되는 static 메소드인 deploy함수의 경우에는 마지막 파라미터에 추가적으로 IWallet을 넘겨줌으로써 배포에 사용되는 지갑을 지정할 수 있습니다. 아래는 deploy 함수의 마지막 파라미터에 keyringContainer를 넘겨주는 코드입니다.

const kip7 = await caver.kct.kip7.deploy({…}, deployer, keyringContainer)const kip17 = await caver.kct.kip17.deploy({…}, deployer, keyringContainer)

위의 코드가 실행되면 SmartContractDeploy 트랜잭션을 서명할 때 keyringContainer 내부에 저장되어 있는 keyring을 사용합니다.

5.2. caver-java-ext-kas

아래는 caver-java-ext-kas를 사용하여 `KeyringContainer` 인스턴스를 생성하는 방법입니다.

KeyringContainer keyringContainer = new KeyringContainer();

위의 방식으로 생성된 keyringContainer를 `caver.contract`, `caver.kct.kip7` 그리고 `caver.kct.kip17`에서 사용하는 방법은 아래와 같습니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");KeyringContainer keyringContainer = new KeyringContainer();
Contract contract = new Contract(caver, abi, contractAddress);
contract.setWallet(keyringContainer);
KIP7 kip7 = new KIP7(caver, contractAddress);
kip7.setWallet(keyringContainer);
KIP17 kip17 = new KIP17(caver, contractAddress);
kip17.setWallet(keyringContainer);

위와 같이 Contract 인스턴스의 setWallet 메소드를 호출하면 contract에서 사용하는 IWallet을 지정할 수 있습니다. 이는 KIP7와 KIP17 모두 동일하게 동작합니다.

KIP7과 KIP17에서 제공되는 static 메소드인 deploy함수의 경우에는 마지막 파라미터에 추가적으로 IWallet을 넘겨줌으로써 배포에 사용되는 지갑을 지정할 수 있습니다. 아래는 deploy 함수의 마지막 파라미터에 keyringContainer를 넘겨주는 코드입니다.

CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, "your_access_key", "your_secret_access_key");KeyringContainer keyringContainer = new KeyringContainer();KIP7 kip7 = KIP7.deploy(caver, "0x{address in hex}", "Jasmine", "JAS", decimals, initialValue, keyringContainer);KIP17 kip17 = KIP17.deploy(caver, "0x{address in hex}", "Jasmine", "JAS", keyringContainer);

위의 코드가 실행되면 SmartContractDeploy 트랜잭션을 서명할 때 keyringContainer 내부에 저장되어 있는 keyring을 사용합니다.

6. Example code

아래 예제는 caver-js-ext-kas를 사용하여 Key, Value형태로 데이터를 읽고, 저장하는 smart contract를 배포 및 실행해보는 코드입니다.

// js : KAS Wallet API with `caver.contract`
const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS()
caver.initKASAPI(chainId, accessKeyId, secretAccessKey)const abi = [
{
constant: true,
inputs: [{ name: 'key', type: 'string' }],
name: 'get',
outputs: [{ name: '', type: 'string' }],
payable: false,
stateMutability: 'view',
type: 'function',
},
{
constant: false,
inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }],
name: 'set',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
},
]
const byteCode = '0x608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f460048036036020811015610ㅇ05157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029'const contract = new caver.contract(abi)const deployed = await contract.deploy({ data: byteCode }).send({ from: '0x{the address of a Klaytn account in KAS Wallet API}', gas: 10000000 })console.log(`Deployed contract address: ${deployed.options.address}`)

아래 예제는 caver-js-ext-kas를 사용하여 KIP7을 배포 및 실행해보는 예제 코드입니다.

// js : KAS Wallet API with `caver.kct.kip7`
const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS()
caver.initKASAPI(chainId, accessKeyId, secretAccessKey)const deployed = await caver.kct.kip7.deploy({
name: 'Jasmine',
symbol: 'JAS',
decimals: 18,
initialSupply: '100000000000000000000'
}, '0x{the address of a Klaytn account in KAS Wallet API}')
console.log(`Deployed contract address: ${deployed.options.address}`)
const contractAddress = deployed.options.address
const kip7 = new caver.kct.kip7(contractAddress)
const receipt = await kip7.transfer('0x{address in hex}', 1, { from: '0x{the address of a Klaytn account in KAS Wallet API}' })
console.log(receipt)

아래 예제는 caver-js-ext-kas를 사용하여 KIP17을 배포 및 실행해보는 예제 코드입니다.

// js : KAS Wallet API account with `caver.kct.kip17`
const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS()
caver.initKASAPI(chainId, accessKeyId, secretAccessKey)const deployed = await caver.kct.kip17.deploy({
name: 'Jasmine',
symbol: 'JAS',
}, '0x{the address of a Klaytn account in KAS Wallet API}')
console.log(`Deployed contract address: ${deployed.options.address}`)
const contractAddress = deployed.options.address
const kip17 = new caver.kct.kip17(contractAddress)
const receipt = await kip17.mintWithTokenURI('0x{address i hex}', tokenId, tokenURI, { from: '0x{the address of a Klaytn account in KAS Wallet API}' })
console.log(receipt)

아래 예제는 caver-js-ext-kas에서 KeyringContainer를 통해 KIP7 / 17을 배포 및 실행해보는 예제 코드입니다.

// js : Use KeyringContainer with KAS SDK
const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS()
caver.initKASAPI(chainId, accessKeyId, secretAccessKey)const keyringContainer = new caver.keyringContainer()const keyring = keyringContainer.keyring.createFromPrivateKey('0x{private key}')
keyringContainer.add(keyring)
// Use keyringContainer with caver.contract
const contract = new caver.contract(abi, '0x{contract address}')
contract.setWallet(keyringContainer)
const receipt = await contract.methods.set('key', 'value').send({ from: keyring.address, gas: 5000000 })
// Use keyringContainer with caver.kct.kip7
const deployed = await caver.kct.kip7.deploy({
name: 'Jasmine',
symbol: 'JAS',
decimals: 18,
initialSupply: '100000000000000000000'
}, keyring.address, keyringContainer)
const kip7Address = deployed.options.address
const kip7 = new caver.kct.kip7(kip7Address)
kip7.setWallet(keyringContainer)
const receiptWithTransfer = await kip7.transfer('0x{address in hex}', 1, { from: keyring.address })
console.log(receiptWithTransfer)
// Use keyringContainer with caver.kct.kip17
const deployed = await caver.kct.kip17.deploy({
name: 'Jasmine',
symbol: 'JAS',
}, keyring.address, keyringContainer)
const kip17Address = deployed.options.address
const kip17 = new caver.kct.kip17(kip17Address)
kip17.setWallet(keyringContainer)
const receiptWithMinting = await kip17.mintWithTokenURI('0x{address i hex}', tokenId, tokenURI, { from: keyring.address })
console.log(receiptWithMinting)

아래 예제는 caver-java-ext-kas를 사용하여 Key, Value형태로 데이터를 읽고, 저장하는 smart contract를 배포 및 실행해보는 코드입니다.

import com.klaytn.caver.contract.Contract;
import com.klaytn.caver.contract.SendOptions;
import com.klaytn.caver.methods.response.TransactionReceipt;
import com.klaytn.caver.utils.ChainId;
import org.web3j.abi.datatypes.Type;
import org.web3j.protocol.exceptions.TransactionException;
import xyz.groundx.caver_ext_kas.CaverExtKAS;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.util.List;
public class SampleContract {
static final String BINARY = "608060405234801561001057600080fd5b5061051f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a723058203ffebc792829e0434ecc495da1b53d24399cd7fff506a4fd03589861843e14990029";
static final String ABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]";
public static void main(String[] args) throws NoSuchMethodException, TransactionException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
String accessKey = "your access key";
String secretAccessKey = "your secret access key";
CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, accessKey, secretAccessKey);
//The deployer account must be created through the KAS Wallet API.
//The deployer must have enough KLAY to deploy the contract
String deployer = "0x{address}";
//Deploy contract
BigInteger gas = BigInteger.valueOf(10000000);
SendOptions deploySendOptions = new SendOptions(deployer, gas);
Contract sampleContract = new Contract(caver, ABI);
sampleContract.deploy(deploySendOptions, BINARY);
System.out.println("Deployed contract address: " + sampleContract.getContractAddress());
//Connect already deployed contract
Contract deployedContract = new Contract(caver, ABI, sampleContract.getContractAddress());

//Execute smart contract's "set" function
SendOptions sendOptions = new SendOptions(deployer, BigInteger.valueOf(5000000));
TransactionReceipt.TransactionReceiptData receiptData = deployedContract.send(sendOptions, "set", "key", "value");
System.out.println(receiptData.getTransactionHash());
//Execute smart contract's "get" function
List<Type> result = deployedContract.call("get", "key");
System.out.println((String)result.get(0).getValue());
}
}

아래 예제는 caver-java-ext-kas를 통해 KIP7을 배포 및 실행해보는 예제입니다.

import com.klaytn.caver.contract.SendOptions;
import com.klaytn.caver.kct.kip7.KIP7;
import com.klaytn.caver.methods.response.TransactionReceipt;
import com.klaytn.caver.utils.ChainId;
import org.web3j.protocol.exceptions.TransactionException;
import xyz.groundx.caver_ext_kas.CaverExtKAS;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
public class SampleKIP7 {
public static void main(String[] args) throws NoSuchMethodException, TransactionException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
String accessKey = "your access key";
String secretAccessKey = "your secret access key";
CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, accessKey, secretAccessKey);
//The deployer account must be created through the KAS Wallet API.
//The deployer must have enough KLAY to deploy the contract
String deployer = "0x{address}";

//deploy contract
BigInteger initialSupply = BigInteger.TEN.multiply(BigInteger.TEN.pow(18)); // 10 * 10¹⁸
KIP7 kip7 = KIP7.deploy(caver, deployer, "Jasmine", "JAS", 18, initialSupply);
System.out.println(kip7.getContractAddress());
//Connect already deployed contract
KIP7 deployedKIP7 = new KIP7(caver, kip7.getContractAddress());
//Execute KIP7’s transfer function.
String from = deployer;
String to = "0x{to address}";
SendOptions sendOptions = new SendOptions(from);
BigInteger transferAmount = BigInteger.ONE.multiply(BigInteger.TEN.pow(18));
TransactionReceipt.TransactionReceiptData receiptData = deployedKIP7.transfer(to, transferAmount, sendOptions);
System.out.println(receiptData.getTransactionHash());
}
}

아래 예제는 caver-java-ext-kas를 사용해 KIP-17를 배포 및 실행해보는 샘플 코드입니다.

import com.klaytn.caver.contract.SendOptions;
import com.klaytn.caver.kct.kip17.KIP17;
import com.klaytn.caver.methods.response.TransactionReceipt;
import com.klaytn.caver.utils.ChainId;
import org.junit.Ignore;
import org.web3j.protocol.exceptions.TransactionException;
import xyz.groundx.caver_ext_kas.CaverExtKAS;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
public class SampleKIP17 {public static void main(String[] args) throws NoSuchMethodException, IOException, InstantiationException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, TransactionException {
String accessKey = "your access key";
String secretAccessKey = "your secret access key";
CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, accessKey, secretAccessKey);
//The deployer account must be created through the KAS Wallet API.
//The deployer must have enough KLAY to deploy the contract
String deployer = "0x{address}";
//deploy contract
KIP17 kip17 = KIP17.deploy(caver, deployer, "Jasmine", "JAS");
System.out.println(kip17.getContractAddress());
//Connect already deployed contract
KIP17 deployedKip17 = new KIP17(caver, kip17.getContractAddress());
//Execute KIP7’s transfer function.
String from = deployer;
String to = "0x{to address}";
String tokenURI = "tokenURI";
SendOptions sendOptions = new SendOptions(from);
TransactionReceipt.TransactionReceiptData receiptData = deployedKip17.mintWithTokenURI(to, BigInteger.ZERO, tokenURI, sendOptions);
System.out.println(receiptData.getTransactionHash());
}
}

아래 예제는 caver-java-ext-kas에서 KeyringContainer를 통해 KIP7 / 17을 배포 및 실행해보는 예제 코드입니다.

import com.klaytn.caver.contract.SendOptions;
import com.klaytn.caver.kct.kip17.KIP17;
import com.klaytn.caver.kct.kip7.KIP7;
import com.klaytn.caver.methods.response.TransactionReceipt;
import com.klaytn.caver.utils.ChainId;
import com.klaytn.caver.wallet.KeyringContainer;
import com.klaytn.caver.wallet.keyring.KeyringFactory;
import com.klaytn.caver.wallet.keyring.SingleKeyring;
import org.junit.Ignore;
import org.web3j.protocol.exceptions.TransactionException;
import xyz.groundx.caver_ext_kas.CaverExtKAS;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
public class SampleKeyringContainer {

public static void main(String[] args) throws NoSuchMethodException, IOException, InstantiationException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, TransactionException {
String accessKey = "your access key";
String secretAccessKey = "your secret access key";
CaverExtKAS caver = new CaverExtKAS(ChainId.BAOBAB_TESTNET, accessKey, secretAccessKey);
KeyringContainer container = new KeyringContainer();//deployer must have KLAY to deploy and execute smart contract.
String deployerPrivateKey = "0x{private key}";
SingleKeyring deployerKeyring = (SingleKeyring)container.add(KeyringFactory.createFromPrivateKey(deployerPrivateKey));
String deployerAddr = deployerKeyring.getAddress();
String toAddress = "0x{address}";
//KIP7
BigInteger initialSupply = BigInteger.TEN.multiply(BigInteger.TEN.pow(18)); // 10 * 10¹⁸
KIP7 kip7 = KIP7.deploy(caver, deployerAddr, "Jasmine", "JAS", 18, initialSupply, container);
KIP7 deployedKIP7 = new KIP7(caver, kip7.getContractAddress());
BigInteger transferAmount = BigInteger.ONE.multiply(BigInteger.TEN.pow(18));
SendOptions transferSendOptions = new SendOptions(deployerAddr);
TransactionReceipt.TransactionReceiptData receiptData_transfer = deployedKIP7.transfer(toAddress, transferAmount, transferSendOptions);//KIP17
KIP17 kip17 = KIP17.deploy(caver, deployerKeyring.getAddress(), "Jasmine", "JAS", container);
KIP17 deployedKIP17 = new KIP17(caver, kip7.getContractAddress());
SendOptions mintSendOptions = new SendOptions(deployerAddr);
TransactionReceipt.TransactionReceiptData receiptData_mint = deployedKIP17.mintWithTokenURI(toAddress, BigInteger.ZERO, "tokenURI", mintSendOptions);
}
}

--

--