aeternity/aepp-sdk-js

In smart contracts, AENS delegated signature problem

Closed this issue · 5 comments

This is used in historical contracts for example

AENS.transfer(owner, Contract.address, name, signature = sig)

In this case, how should JS-SDK 13.3.2 use the get signature file call?

this is my code:

image

image

image

@davidyuk should know !

AENS.transfer still works, but signature format changed since Ceres.

As far as we all in Ceres the best to use signDelegation method of Account or AeSdk.

The error you have is because aepp-calldata expects to get signature as hex string or Buffer, but sdk encodes it as sg_. So, you need to decode signature before passing to calldata. Related issue: aeternity/aepp-calldata-js#240

Here is example of changing name owner via delegation signature in Ceres using the sdk@13.3.2

import {
  Node, AeSdk, MemoryAccount, CompilerHttp, DelegationTag, packDelegation, decode,
} from '@aeternity/aepp-sdk';

const [owner, recipient] = [MemoryAccount.generate(), MemoryAccount.generate()];
console.log('Owner address', owner.address);
console.log('Recipient address', recipient.address);

const aeSdk = new AeSdk({
  accounts: [owner],
  nodes: [{ name: 'testnet', instance: new Node('https://testnet.aeternity.io') }],
  onCompiler: new CompilerHttp('https://v7.compiler.aepps.com'),
});

await fetch(`https://faucet.aepps.com/account/${owner.address}`, { method: 'POST' });

const name = `test-name-${Date.now()}.chain`;
await aeSdk.aensClaim(name, 0);
console.log('Claimed name', name);
console.log('Name owner', (await aeSdk.aensQuery(name)).owner);

const contractSourceCode = `
contract DelegateTest =
  stateful entrypoint transfer(
    owner: address, new_owner: address, name: string, sign: signature): unit =
    AENS.transfer(owner, new_owner, name, signature = sign)
`;
const contract = await aeSdk.initializeContract({ sourceCode: contractSourceCode });
const contractAddress = (await contract.$deploy([])).address;
console.log('Contract deployed at', contractAddress);

const delegation = packDelegation({
  tag: DelegationTag.AensName, accountAddress: aeSdk.address, contractAddress, nameId: name,
});
const delegationSignature = decode(await aeSdk.signDelegation(delegation));
await contract.transfer(owner.address, recipient.address, name, delegationSignature);
console.log('Name transferred');

console.log('Name owner', (await aeSdk.aensQuery(name)).owner);

I tried to use the method you provided to call, but still failed

Is there something wrong? I did not find it....

image

image

image

A private key exposed in the above message, ensure that you don't have much funds there!

I figured out the issue. Contracts deployed in Iris are executed in FATE v2, so it expects an old signature format. The problem is that we have security concerns about that format, and I would like to drop its support in future SDK versions. Is it feasible to migrate your contracts to FATE v3?

Meanwhile, you can provide consensusProtocolVersion: ConsensusProtocolVersion.Iris option to generate an old signature in Ceres using AeSdk::signNameDelegationToContract. See the below reproduction.

The code I've used to test it
import {
  Node, AeSdk, MemoryAccount, CompilerHttp, ConsensusProtocolVersion, decode,
} from '@aeternity/aepp-sdk';

const [owner, recipient] = [
  new MemoryAccount('9ebd7beda0c79af72a42ece3821a56eff16359b6df376cf049aee995565f022f840c974b97164776454ba119d84edc4d6058a8dec92b6edc578ab2d30b4c4200'),
  MemoryAccount.generate(),
];
console.log('Owner address', owner.address);
console.log('Recipient address', recipient.address);

const aeSdk = new AeSdk({
  accounts: [owner],
  nodes: [{ name: 'testnet', instance: new Node('http://localhost:3013') }],
  onCompiler: new CompilerHttp('https://v7.compiler.aepps.com'),
});

const contractSourceCode = `
contract DelegateTest =
  stateful entrypoint transfer(
    owner: address, new_owner: address, name: string, sign: signature): unit =
    AENS.transfer(owner, new_owner, name, signature = sign)
`;
const contract = await aeSdk.initializeContract({ sourceCode: contractSourceCode });
const contractAddress = (await contract.$deploy([])).address;
console.log('Contract deployed at', contractAddress);
console.log('Height', await aeSdk.getHeight());
console.log('Consensus', ConsensusProtocolVersion[(await aeSdk.api.getNodeInfo()).consensusProtocolVersion]);

const name = `test-name-${Date.now()}.chain`;
const nameObj = await aeSdk.aensPreclaim(name);
await nameObj.claim();
console.log('Claimed name', name);
console.log('Name owner', (await aeSdk.aensQuery(name)).owner);

console.log('Height', await aeSdk.getHeight());
console.log('Consensus', ConsensusProtocolVersion[(await aeSdk.api.getNodeInfo()).consensusProtocolVersion]);
const delegationSignature = await aeSdk.signNameDelegationToContract(
  contractAddress,
  name,
  { consensusProtocolVersion: ConsensusProtocolVersion.Iris },
);
console.log('delegationSignature', delegationSignature);
const delegationSignatureAsHex = decode(delegationSignature);
await contract.transfer(owner.address, recipient.address, name, delegationSignatureAsHex);
console.log('Name transferred');

console.log('Name owner', (await aeSdk.aensQuery(name)).owner);
dev_mode:
  auto_emit_microblocks: true

chain:
  persist: false
  hard_forks:
    "1": 0
    "5": 1
    "6": 2
  genesis_accounts:
    ak_21A27UVVt3hDkBE5J7rhhqnH5YNb4Y1dqo4PnSybrH85pnWo7E: 10000000000000000000000

So, the contract deployed in Iris and called in Ceres.

@davidyuk Thank you for your answer. I will upgrade the contract to FATE V3. Then there will be no problem