Error: Returned error: unknown account 에러

안녕하세요,

roleBased인 owner의 주소를 DB로부터 받아서
미리 만들어 놓았던 changeOwner 컨트랙트를 caver js로 실행하려는데

async changeOwner(){
    const ownerAddress = await this.bringAndSetOwnerwallet() //이부분은 문제없음
  
    await tokenContract.methods.changeOwner(ownerAddress).send({   //여기서 문제 발생
      from: await this.owner(), 
      gas: 100000,
    })

위 부분에서
await tokenContract.methods.changeOwner(ownerAddress).send() 얘를 실행할 때
exception: Error: Returned error: unknown account 에러가 뜹니다.

bringAndSetOwnerwallet() 안에서
in memory wallet에 추가해주는 작업을 하였는데

아무리 생각해도 unknown account가 뜨는 이유를 모르겠습니다.
저 에러는 from 부분의 주소가 wallet에 들어있지 않을때 나타나는것 외에도 다른경우가 있나요?

async bringAndSetOwnerwallet(){ 

    // 디비에서 오너 주소 받아오고 지갑에 add
    const wallet = await this.klayService.getOwnerWallet()
    const ownerAddress = wallet.getAddressString()

    // // 디비에서 키 받아오기
    const ARoleTxKey = await this.klayService.getCorporateRoleKey(1, AccountKeyRole.ROLE_TRANSACTION)
    const ARoleAccountUpdateKey = await this.klayService.getCorporateRoleKey(1, AccountKeyRole.ROLE_ACCOUNTUPDATE)
    const BRoleTxKey = await this.klayService.getCorporateRoleKey(2, AccountKeyRole.ROLE_TRANSACTION)
    const BRoleAccountUpdateKey = await this.klayService.getCorporateRoleKey(2, AccountKeyRole.ROLE_ACCOUNTUPDATE)
    const keyList = [
      [ARoleTxKey, BRoleTxKey],
      [ARoleAccountUpdateKey, BRoleAccountUpdateKey],
      [ARoleTxKey, BRoleTxKey],
    ]

    this.klayService.addKeyringToWallet(ownerAddress, keyList)

    return ownerAddress
  }


addKeyringToWallet(address: string, key) {
    if (this.caver.wallet.isExisted(address)) {
      const updateKeyring = this.caver.wallet.keyring.create(address, key);
      this.caver.wallet.updateKeyring(updateKeyring);
    } else {
      this.caver.wallet.newKeyring(address, key);
    }
  }

안녕하세요.

Contract를 어떤 것을 사용햇냐에 따라서 추가해야 하는 in-memory wallet이 달라질 수 있습니다.

common architecture 이후인 caver.contract.create를 사용해서 생성된 객체라면 KeyringContainer인 caver.wallet에 keyring 객체를 add해 주시면 됩니다. (https://docs.klaytn.foundation/dapp/sdk/caver-js/api-references/caver.contract)

만약 contract 객체가 caver.klay.Contract를 사용해서 생성된 객체라면 caver.klay.accounts.wallet에 추가해야 합니다. (https://docs.klaytn.foundation/dapp/sdk/caver-js/v1.4.1/api-references/caver.klay.contract)

자세한 내용은 문서를 참고해 주시기 바랍니다.
감사합니다

똑같은 contract 객체의 다른 메서드를 사용한 함수인 takeBack의 경우
from이 owner로 똑같아도 잘 수행되는데 유독 저 changeOwner만 unknown account 가 뜹니다.

async takeBack(owner: string, target: string, amount: string) {
    //오너가 환수
    await myContract.methods.takeBack(owner, target, amount).send({
      from: await this.owner(),
      gas: 100000,
    });

    const response = {
      amount,
    };
    return response;

위 코드도 caver.wallet.newKeyring()으로 owner의 정보를 넣어주니 takeBack 스마트컨트랙이 잘 작동합니다.
이상하게 changeOwner만 계속 unknown account가 뜹니다.

const myContract = new caver.contract( tokenContract.options.jsonInterface, tokenContract.options.address, );

의심할만한 문제를 생각해보면

  1. account wallet문제 (from)
  2. caver contract문제
  3. smart contract (solidity) 자체의 문제인데,

에러 내용은 1번인데
1번은 wallet add나 create등 여러 방안으로 시도해도 안되고,
또 changeOwner빼고 다른 메서드들은 잘 작동이 됩니다.

2번도 같은 컨트랙트 객체의 다른 메서드들은 잘 작동이 되며

3번은 remix안에서 실행해봤을때 아무 문제없이 owner를 변경할 수 있었습니다.

스마트 컨트랙트 소스코드와 이를 호출하는 코드를 제공해 주시면 에러 재현을 해보고 답변드리겠습니다.

1개의 좋아요

스마트컨트랙 코드

function changeOwner(address newOwner) public onlyOwner {
        super.transferOwnership(newOwner);
    }

function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

//////호출 코드
async changeOwner(){
const ownerAddress = await this.bringAndSetOwnerwallet()

await tokenContract.methods.transferOwnership(ownerAddress).send({ 
    from: await this.owner(),
    gas: 100000,
  });

}

//롤베이스로 만들어주는 코드

async bringAndSetOwnerwallet(){ 

    // 디비에서 오너 주소 받아오고 지갑에 add
    const wallet = await this.klayService.getOwnerWallet()
    const ownerAddress = wallet.getAddressString()

    // // 디비에서 키 받아오기
    const ARoleTxKey = await this.klayService.getCorporateRoleKey(1, AccountKeyRole.ROLE_TRANSACTION)
    const ARoleAccountUpdateKey = await this.klayService.getCorporateRoleKey(1, AccountKeyRole.ROLE_ACCOUNTUPDATE)
    const BRoleTxKey = await this.klayService.getCorporateRoleKey(2, AccountKeyRole.ROLE_TRANSACTION)
    const BRoleAccountUpdateKey = await this.klayService.getCorporateRoleKey(2, AccountKeyRole.ROLE_ACCOUNTUPDATE)
    const keyList = [
      [ARoleTxKey, BRoleTxKey],
      [ARoleAccountUpdateKey, BRoleAccountUpdateKey],
      [ARoleTxKey, BRoleTxKey],
    ]

    this.klayService.addKeyringToWallet(ownerAddress, keyList)

    return ownerAddress
  }

ownerAddress는 롤베이스드로 키가 업데이트 된 상태인 건가요?
주신 코드는 외부 서비스 호출하는 부분도 포함되어 있어 재현에 사용하기가 어려운데요, 재현을 위해서는 실행이 가능한 코드가 필요합니다.
스마트 컨트랙트 소스코드도 바로 컴파일 가능한 형태로 부탁드립니다.
하고자 하시는게 롤베이스로 키가 업데이트된 계정으로 transferOwnership을 호출하면 되는건가요?

1개의 좋아요