컨트랙트 실행 트랜잭션 api 오류 문의

안녕하세요,

KAS 서비스에서 컨트랙트 실행 API를 통해서 토큰 전송을 시도했는데 아래와 같은 오류 메시지가 나왔습니다.

Klaytn Wallet 사이트에서 만든 지갑 2개를 가지고 바오밥넷에서 시도했습니다.

어떤 문제인지 모르겠어서 문의 드립니다.

감사합니다.

  • 입력한 파라미터값
    “from”: “0xbd4753f39c71f20b5ae7bb8b8ad60db3b9df6269”,
    “value”: “0x0”,
    “to”: “0x06545b70b18068ccf5ee6eb5eb1f465c5dbe4f05”,
    “input”: “0xa9059cbb00000000000000000000000006545b70b18068ccf5ee6eb5eb1f465c5dbe4f0500000000000000000000000000000000000000000000000000000000000186a0”,
    “nonce”: 15,
    “gas”: 1000000,
    “submit”: true

  • 결과
    ← 400 Bad Request https://wallet-api.klaytnapi.com/v2/tx/contract/execute (259ms)
    content-type: application/json; charset=utf-8
    date: Thu, 19 Nov 2020 07:45:28 GMT
    content-length: 81
    x-envoy-upstream-service-time: 10
    server: istio-envoy
    {“code”:1065100,“message”:“failed to get an account from AMS; data don’t exist”}

안녕하세요, 클레이튼 포럼에 질문을 올려주셔서 감사드립니다.

아래 에러내용을 보면 from에 해당하는 주소(“0xbd4753f39c71f20b5ae7bb8b8ad60db3b9df6269”)가 wallet API에서 생성한 주소가 아니라서 서명을 추가할 수 없다는 에러로 보입니다.

from에 해당하는 주소가 wallet API에서 생성한 klaytn account가 맞을까요?

안녕하세요.

https://baobab.wallet.klaytn.com/ 에서 생성한 계정입니다.

안녕하세요, 거기서 생성하시면 안되고 이 API 를 통해 생성하셔야 합니다.

저도 EN 서버로 서비스중인데요. 이것을 KAS API 로 변경하려고 합니다. 그럼 기존에 생성된 Klaytn account는 사용할 수 없고, 새로 계정을 생성하여야만 하는 건가요? 기존 계정을 KAS에 등록하는 방법은 없나요?

안녕하세요,

기존 계정을 KAS Wallet으로 migration하는 기능은 현재 출시 준비중에 있으며, 1월 중에 출시될 예정입니다. 출시 후에 관련 내용 안내드릴 수 있도록 하겠습니다.

감사합니다.

cc @_Luffy

2월인데요. 아직 migration 기능이 출시되었다는 공지가 나오지 않네요. 언제쯤 출시가 될까요?

1개의 좋아요

@albizz 안녕하십니까. 정식 기능 공지는 현재 준비중이고요.
마이그레이션 API 는 현재 개발되어 있는데, 튜토리얼이 아직 작성되지 않아서, 아래와 같이 가이드 드립니다.

  1. 키 생성 API를 통해서 N개의 키를 생성 (keyId, public key 정보를 알 수 있음)
  2. 로컬에서 마이그레이션 하고자 하는 address 를 (1) 에서 받은 public key 로 업데이트 하기 위한 Fee delegation account update transaction 을 만들어서 서명 (RLP 를 얻음)
  3. address, keyId, RLP 를 계정 등록 API 를 통해서 등록

크게는 위의 3가지 단계로 이루어집니다.

caver-js-ext-kas 에서 SDK 사용법을 확인하실 수 있습니다.

코드 레벨의 조금더 상세한 프로세스를 확인하고 싶으시면, SDK 의 마이그레이션 함수 내부 로직을 확인하실 수도 있습니다.

추후 튜토리얼을 통해서 조금더 쉽게 사용하실수 있도록 노력하겠습니다.

감사합니다.

1개의 좋아요

@colin.kim

안녕하세요.
caver-js-ext-kas를 이용해서


async function createWallet(){
	const account = await caver.kas.wallet.createAccount()
	console.log('account : ',account)	
}

를 해서 만들면 아래와 같은 정보가 뜨는데요.
KAS를 이용해 스마트 컨트랙에 접근하려면 아래 화면에 나오는 address를 from 에 가져다 쓰면 되는거죠?
근데 Klay가 0이라 insufficient funds of te sender for value는 그대로 아닌가요? 그렇다고 Private Key나 KeystoreFile(.json)이 만들어진것도 아니라서 KlaytnWallet.com에서 접근하여 Klay Faucet 을 할 수도 없고요
어떻게 해야될까요?

image

안녕하세요, Wallet API에는 global fee payer를 이용한 fee delegation 기능을 이용할 수 있습니다. KLAY가 없더라도 생성하신 토큰을 주고 받으실 수 있습니다. 아래 링크를 참고 부탁드립니다.

https://refs.klaytnapi.com/ko/wallet/latest#operation/FDContractExecutionTransaction

답변 감사합니다.

  1. 말씀하신대로 global fee payer를 이용하면 KAS에서 수수료를 대납하는거잖아요?
    그래서 Fee Delegated Transaction를 쓰려고 하는데 아래 코드 부분에 어떻게 넣어야될까요?
    주신 POST 부분(“http://localhost/v2/tx/fd/value”)을 어떻게 caver.kas 이런식으로 부를지 모르겠습니다.

const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS()
  1. 그러면 KlaytnWallet.com에서 KAS를 이용해 만든 Wallet을 연결하고 Run Faucet을 하려면 어떻게 해야 될까요?? 터미널에 Private Key는 나오지 않더라고요

  2. KAS로 만든 지갑 계정은 토큰이 0이니까 IDE로 만든 지갑(토큰 있음)을 갖고 Smart Contract에다가 입금을 해야 KAS로 스마트 컨트랙을 조회하거나 할 수 있다는건가요???
    그걸 어떻게 하는지 코드 예시를 좀 들어주실수 있나요. 보내주신 링크( https://refs.klaytnapi.com/ko/wallet/latest#operation/FDContractExecutionTransaction )를 봤는데요.


const contractAddress = '0xb4f5aecc5a473eed4c275df01c5d103658fb06eb' //KIP-7 Labeling
const contract = new caver.contract(abi, contractAddress)

// fee delegation or migration
async function delegateFee(){
	// from: IDE에서 만든 klaytn 계정 주소(토큰 있음)
	// to : KIP7contract 주소
	const result = await contract.methods.execute('? API를 봐도 여기를 모르겠습니다. )
}

async function getContractInfo(){
	// klaytn account address
	const receipt = await contract.methods.set('key', 'value').send({ from: '0xKIP7스마트컨트랙주소', gas: 100?????????})
	console.log('receipt: ',receipt)	
}

delegateFee()
getContractInfo()

  1. KlaytnWallet에서는 Balance 로 초기발행량이 잡히는데, KlaytnScope (baobab)에서는 왜 0 klay로 나올까요?
    contract 정보에 보이는 balance와 totalSupply는 어떻게 다른건가요?


  1. 링크도 참고 부탁드리겠습니다. Wallet API로 새로 두 계정을 만들고 두 계정간 0 KLAY를 전송하는 예제코드를 전달드립니다.
const Caver = require('caver-js')
const CaverExtKAS = require('caver-js-ext-kas')

// Configuration Part
// Set your KAS access key and secretAccessKey.
const accessKeyId = ''
const secretAccessKey = ''

// const CHAIN_ID_BAOBOB = '1001'
// const CHAIN_ID_CYPRESS = '8217'
const chainId = '1001'

const option = {
    headers: [
        { name: 'Authorization', value: 'Basic ' + Buffer.from(accessKeyId + ':' + secretAccessKey).toString('base64') },
        { name: 'x-chain-id', value: chainId },
    ]
}

const caver = new CaverExtKAS()

main()

async function main() {
    caver.initKASAPI(chainId, accessKeyId, secretAccessKey)

    var acc1 = await caver.kas.wallet.createAccount()
    var acc2 = await caver.kas.wallet.createAccount()

    var result = await caver.kas.wallet.requestFDValueTransferPaidByGlobalFeePayer({
        from: acc1.address,
        to:acc2.address,
        value:0,
        submit:true
    })
    console.log('result', result)
}
  1. Wallet API에서 생성한 계정은 private key가 암호화되어 누구도 알 수 없습니다. Baobab faucet에서 새로 계정을 만드시고 그 계정에서 Wallet API로 만든 계정으로 KLAY를 전송하시면 될 것 같습니다.

  2. 아직 대납기능을 지원하는 기능이 구현중이라서 현재는 코드가 좀 복잡하네요. caver v1.6.1에서 컨트랙트에 대납 기능이 추가되었으나 아직 KAS와 연동하는 부분은 추가 기능 구현이 필요합니다. 아래 코드를 이용해 현재 상황에서도 대납 기능을 이용할 수는 있습니다. 좀 복잡하지만요. 아래 예제 코드를 전달드립니다.

  1. KlaytnWallet에서는 DTK에 빨간 박스를 그려주셨고, scope쪽에서는 KLAY에 빨간 박스를 그려주셨네요. 질문이 명확하게 이해하진 못했으나, 설명을 좀 적어보겠습니다. scope에서도 동일한 네트워크에서 동일한 계정을 조회하시면 동일한 KLAY 잔고를 확인하실 수 있습니다. KlaytnWallet쪽에서는 0x9로 시작하는 계정의 잔고를 확인하신거니, scope에서도 0x9로 시작하는 계정의 잔고를 조회하시면 될 것 같습니다. DTK에 대해서도 마찬가지고요.

감사합니다.

1개의 좋아요

답변 감사합니다! 제가 스마트 컨트랙으로 발행한 토큰과 Balance를 착각했었네요;;

1. 그러면 (IDE로 Deploy한) 스마트 컨트랙의 토큰을 A(0x12123…) 지갑에 보내주려면 어떻게 해야될까요?
아래같이 하면 owner 지갑이 KAS로 만든게 아니라 KlaytnWallet 웹에서 만든거라 아래와 같은 에러가 뜨는것 같습니다.

해당 코드는 아래와 같습니다.
(KIP7토큰이며, caver-js-ext-kas 사용중입니다)



const CaverExtKAS = require('caver-js-ext-kas')
const caver = new CaverExtKAS('https://api.baobab.klaytn.net:8651/')

caver.initKASAPI(1001, accessKeyID, secretKey)

...


async function transferContract(){

	const smartContractAddress = 'IDE로 만든 컨트랙 주소';
	const kip7 = new caver.kct.kip7(smartContractAddress)

	const receipt = await kip7.transfer(receiver.address, 10, { from : 스마트컨트랙발행할때 연결된지갑주소}) 
	console.log('receipt: ',receipt)	
}

transferContract()

2. 지금은 baobab에서 하는거지만, A계정에 있는 100 토큰을 출금한다고 하면 어떤 API를 써야될까요?

1번은 해결한거 같습니다. keyringContainer에다가 스마트 컨트랙을 발행할 때 연결했던 계좌의 PK를 추가했더니 해당 에러는 더 이상 나타나지 않습니다.

1. keyring이 뭔가요??

2. A계정에서 B계정으로 토큰을 보내려면 어떻게 해야 될까요?
스마트 컨트랙에서 A계정으로 보내줄 땐 kip7.transfer를 아래와같이 사용했습니다.
어떤 API를 사용해야되나요?


async function kip7Transfer(){
	const keyringContainer = new caver.keyringContainer()
	const keyring = keyringContainer.keyring.createFromPrivateKey('owner지갑의 PK')
	keyringContainer.add(keyring)

	const kip7 = new caver.kct.kip7('스마트컨트랙 주소')
	kip7.setWallet(keyringContainer)
	kip7.transfer(receiver.address, 10, { from: ide_wallet.address }).then(console.log)
}

kip7Transfer()
  1. keyring은 특정 klaytn 계정의 private key 묶음을 의미합니다. 즉 한 계정이 사용하는 키들의 집합이라고 생각하시면 됩니다. 이더리움과 다르게 클레이튼은 한 계정이 여러개의 private key를 사용할 수 있습니다.

  2. caver-js-boilerplate/index.js at kipfd · kjhman21/caver-js-boilerplate · GitHub 이 부분에서 from주소를 caver.wallet에 있는 계정으로 설정하시고 해당 계정으로 서명하시면 됩니다.

    const sender = caver.wallet.keyring.createFromPrivateKey('0x{private key}')
    caver.wallet.add(sender)

    await caver.wallet.sign(sender.address, transferTx)

감사합니다.

1개의 좋아요

답변 감사합니다.

스마트 컨트랙을 발행할 때 연결된 계정을 Owner라고 한다면,
Owner ------ “100 DTK” --------> A 계정 을 구현할때는 kip7.transfer()를 이용했는데요

A 계정 ------------- 100 DTK ---------> B계정을 구현하려고 할때 사용해야될 API가 caver.transaction.feeDelegatedSmartContractExecution()라는건가요? (Klay가 아니라 자체 토큰을 보내고 싶은겁니다)
스마트 컨트랙을 발행한 계정이 아니라면 대납을 해줘야되는건가요?

그리고 말해주신대로 했는데 여전히 gas required exceeds allowance or always failing transaction 에러가 나네요.

참고해서 적은 코든데 receiver.address, ide_wallet.address에는 다 Klay가 있습니다.
혹시 contract Address에 Klay가 없어서 그런가요? 근데 contract Address에 Klay 전송은 안되더라고요


async function sendToken(){
	console.log('sending Token......')
	try{
		const c = new caver.contract(kip7JsonInterface, contractAddress)
		const transferInput = await c.methods['transfer'](receiver.address, 10).encodeABI()
		var transferTx = new caver.transaction.feeDelegatedSmartContractExecution({
			from: ide_wallet.address,
			to: contractAddress,
			input: transferInput,
			gas: 10000
		})	

		await caver.wallet.sign(ide_wallet.address, transferTx)
	} catch(err){
		console.log('err : ',err)
	}
	
}
sendToken()

A → B에도 기본적으로는 kip7.transfer()를 이용하시면 되는데, A계정이 Wallet API계정이라면 caver-js-ext-kas가 아닌 caver-js를 이용해서는 (private key가 없기 때문에) 토큰을 전송하실 수 없습니다.

추후에 KAS KIP-7 API가 나오면 좀 더 쉬운 방법이 제공될 예정인데, 아직은 제공되지 않는 기능이라서, 현재는 caver-js를 이용해 트랜잭션을 만들고 signature는 채우지 않은 상태에서 RLP를 전송하는 방법이 간단한 방법입니다.

KLAY를 보내시려면 ValueTransfer 트랜잭션이 필요합니다. 만약 자체 토큰 등 스마트 컨트랙트를 실행하고 싶으시면 Smart contract execution 트랜잭션이 필요하고요. 대납은 이 기능과는 별개로 sender가 KLAY가 없을 때 다른 계정의 KLAY를 이용해 transaction fee를 납부하려고 할 때 사용할 수 있습니다. value transfer transaction도 smart contract execution transaction도 모두 대납 기능을 이용할 수 있습니다.
Transaction type에 대한 상세 설명은 이 링크에서 확인하실 수 있습니다.

gas required exceeds allowance라는 에러가 뜨신다면 transaction object의 gas값을 좀 더 큰 값으로 설정하시길 바랍니다.

감사합니다.

1개의 좋아요

답변 감사합니다.

  1. caver-js-ext-kas를 이용중이라면, 계정을 KlaytnWallet 웹으로 만들던 KAS를 이용해 만들던 상관없이 쓸 수 있다는 말씀이신거죠?

  2. KlaytnWallet으로 만든 계정을 스마트 컨트랙 발행할 때 연결했더니, kip7.transfer()를 할 때 keyring을 꼭 해줘야되더라고요. KAS createAccount로 만든 계정이라면 keyring을 안해도 되나요? keyring은 KAS화 시키는 작업이라 생각하면 되나요? (좀전에 위에서는 caver-js-ext-kas를 쓰면 다 쓸 수 있다고 가정했는데… 그게 아닌건가요?)

  3. 두 함수의 차이가 궁금합니다.


async function createAccount(){
	const account = await caver.kas.wallet.createAccount()
	console.log('account : ',account)	
}

async function generateSingleKey(){
	const keyring = caver.wallet.keyring.generate()
	console.log('keyring : ',keyring)
}

createAccount를 하면 address와 publicKey만 나오는데 이거 PrivateKey와 klaytnWalletKey가 없어서 지갑으로 사용 불가한거 아닌가요?
image

반면 generateSingleKey()함수를 이용하면 아래와 같이 주소와 private Key가 생성되니까 이게 지갑으로 사용이 가능하고요.
image

그러다보니 createAccount()를 무슨 용도로 사용해야될지를 모르겠습니다.

4. 지갑과 계정의 차이
KlaytnWallet 웹에서도 CreateAccount를 하면 지갑과 계정이 동시에 생기잖아요?
1개의 계정에 1개의 지갑이라고 생각을 하면 되죠? 혹은 1개의 계정이 여러개의 지갑을 소유하는 거고요?
그렇다면 caver-js-ext-kas를 이용해서 caver.kas.wallet.createAccount()를 하면… 각각의 계정&지갑이 생성된다고 보면 되는건가요?

API를 쓰다보니 개념이 더 헷갈리네요…

  1. 네 상관없이 쓰실 수 있지만 사용방법은 좀 다릅니다.
    KlaytnWallet을 통해 만드신 계정은 직접 private key를 caver-js wallet으로 import해서 사용하셔야 하고요 (참고)
    KAS Wallet으로 생성한 계정을 이용하시려면 이 문서 참고 부탁드립니다. 참고로, caver-js-ext-kas는 caver-js를 wrapping하여 만든 라이브러리이기 때문에, caver-js의 기능을 모두 이용하실 수 있습니다.

  2. 음… 기본적으로, 어찌되었건 트랜잭션에 private key로 서명하는 과정이 필요합니다. KlaytnWallet에서 만든 계정은 private key를 따로 추출하여서 caver-js를 통해 서명을 직접 하셔야 합니다. KAS를 사용하신다면 서명 과정은 KAS API가 담당해서 처리를 하니, 생성된 계정의 주소와 KAS credential을 전달하면 KAS Wallet API 내부적으로 서명이 일어나게 되고요.

과정을 좀 더 세분화해서 설명을 해보겠습니다. KlaytnWallet의 예를 보면,
1- KlaytnWallet을 통해 account A 생성 (private key도 같이 생성됨)
2- 생성된 private key를 caver.wallet을 통해 import
3- tx.from=A로 트랜잭션 생성
4- signedTransaction = caver.wallet.sign(A, tx)
5- signedTransaction을 Klaytn network (Cypress)로 전송

의 과정을 통해 트랜잭션 생성, 서명, 전파가 되고, 전파된 트랜잭션이 블록에 들어가게 되면 그게 실제 블록체인에 최종 결과로 들어가게 됩니다.

KAS는 이 과정을 쉽게하고, private key 관리를 내부적으로 해 준다고 생각하시면 됩니다. KAS를 쓰게되면 절차가 아래와 같이 바뀌게 됩니다.
1- KAS Wallet API를 통해 account B create (private key는 KAS 내부에 저장됨)
2- tx.from=B로 트랜잭션 생성
3- KAS Wallet API를 통해 트랜잭션 서명 및 전송 (submit = true일 경우 바로 Cypress로 전송됨)

KAS를 사용할 경우에는 보안을 위해 KAS 내부에서 생성한 private key만을 사용할 수 있기 때문에, createAccount()로만 클레이튼 계정을 생성할 수 있습니다.

  1. 계정과 지갑이라는 용어가 명확히 정의되지 않아 생기는 문제 같습니다. 지갑은 여러개의 계정을 관리하고 트랜잭션에 원하는 계정의 서명을 추가하는 역할을 포함한다고 생각하시면 됩니다. 계정은 단순히 Klaytn에서 관리되는 KLAY balance를 가진 하나의 자료구조라고 생각하시면 되고요. 위에 말씀하신 것을 바탕으로 보자면 지갑이라는 용어는 빼셔도 될 것 같습니다.

감사합니다.