Skip to content

aurora-is-near/chain-signatures-signer

Repository files navigation

Chain Signatures Signer

Solidity Contract to Support NEAR Chain Signatures on AURORA.

What is the main thing this contract does?

This contract opens you the doors to:

  • to create a runtime environment on networks without smart contracts, like Bitcoin, Ripple by using Solidity smart contracts deployed to AURORA
  • use Chain Signatures from AURORA directly, using Solidity

This repo uses Foundry. Please install it to deploy/verify your own contract if needed.

Right now we have two such signers deployed:

You can use these or deploy your own one.

The ABI is inside signer_abi.json file. Just use it. Or extract it via Explorer.

How it works?

The contract works by using the XCC to communicate with NEAR via its subaccount. You can read more about it in the XCC Docs.

Deploying and verifying

First of all, you will need to put $PRIVATE_KEY into your .env file and install Foundry.

After that you can just execute, if on Mainnet:

forge create --rpc-url https://mainnet.aurora.dev ChainSignaturesSigner --legacy --private-key $PRIVATE_KEY --libraries 'lib/xcc/AuroraSdk.sol:AuroraSdk:0x05ADbA73a00b70D2e35BE8F0b44e8Ca6891d925C' --constructor-args v1.signer 0xC42C30aC6Cc15faC9bD938618BcaA1a1FaE8501d

And if on Testnet:

forge create --rpc-url https://testnet.aurora.dev ChainSignaturesSigner --legacy --private-key $PRIVATE_KEY --libraries 'lib/xcc/AuroraSdk.sol:AuroraSdk:0xa1c283ed4CD8Ddc8694c209B18Fb40f7B3929361' --constructor-args v1.signer-prod.testnet 0x4861825E75ab14553E5aF711EbbE6873d369d146       

To verify contract use:

forge verify-contract --rpc-url https://mainnet.aurora.dev 
<YOUR_CONTRACT_ADDRESS_HERE> ChainSignaturesSigner --verifier blockscout --verifier-url https://explorer.mainnet.aurora.dev/api --libraries 'lib/xcc/AuroraSdk.sol:AuroraSdk:0x05ADbA73a00b70D2e35BE8F0b44e8Ca6891d925C' --guess-constructor-args

For the verification on Testnet, just change the rpc, the explorer endpoint, and AuroraSdk library address. Take them from the create command above.

Initializing the contract

To start using your freshly deployed contract, you will need to initialize it by calling init function. To do this:

  • Verify the contract
  • Approve the wNEAR for the CS Signer (2 wNEAR is needed to init, but I advice you to approve more – to make the sign calls in the future, I was using 3 wNEAR).
  • Go to the Explorer and call init method.

If you forgot smth, you will see crazy gas estimates in your wallet. Usually it is happening because you haven't approved wNEAR for the contract address.

Only the deployer of the contract can call the init method.

The method itself looks like that:

    function init() public onlyRole(OWNER_ROLE) {
        // Make a cross-contract call to trigger sub-account creation.
        bytes memory data = abi.encodePacked('{\"greeting\":\"Hello from Signer!\"}');
        PromiseCreateArgs memory initCall = near.call("hello.near-examples.testnet", "set_greeting", data, 0, SET_GREETING_NEAR_GAS);
        initCall.transact();
    }

It call the simplest possible contract on NEAR to bootstrap itself and initialize the XCC subaccount.

Signing the payload

It is done via sign function call and recieving the response in the signCallback transaction.

To call sign you will need to provide:

  • payload - the data to be signed
  • version - key_version from chain signatures, check NEAR docs. At the moment, it is just 0.
  • attachedNear - the amount of wNEAR to attach to the NEAR call. Usually 1yoctoNEAR is enough, so you should just enter 1.

The code for the sign method looks like this:

    function sign(string memory payload, uint256 version, uint128 attachedNear) public {
        bytes memory _data = hexStringToBytes(payload);
        require(_data.length == 32, "Payload must be 32 bytes");

        // path is fixed here to make sure only msg.sender can use the derived 
        // address via chain signature's of the xcc sub-account
        string memory path = addressToString(msg.sender);
        bytes memory data = createData(_data, path, version);

        PromiseCreateArgs memory callSign = near.call(signer, "sign", data, attachedNear,  SIGN_NEAR_GAS);
        PromiseCreateArgs memory callback = near.auroraCall(address(this), abi.encodeWithSelector(this.signCallback.selector), 0, SIGN_CALLBACK_NEAR_GAS);

        callSign.then(callback).transact();
    }

The main moments in it to focus onto are:

  • Ownership Preservation: The derivation path is equal to addressToString(msg.sender); which ensures that only the EOA or contract who is msg.sender can operate the derived account on other networks.
  • Callback is optional: you can remove it and index the NEAR blockchain instead for the MPC response. It will save you some gas if you don't need the signed message back into your Solidity contracts.
  • Gas for signature: SIGN_NEAR_GAS value can change in the future and be optimized. Right now it is 50TGas.

Function signCallback just propagates the MPC response back inside EVM and emits SignedEvent:

    function signCallback() public onlyRole(CALLBACK_ROLE) {
        PromiseResult memory result = AuroraSdk.promiseResult(0);

        if (result.status != PromiseResultStatus.Successful) {
            revert("SignCallback failed");
        }

        string memory output = string(result.output);
        emit SignedEvent(output);
    }

The output will contain the affine_point and scalar to reconstruct the signature. You can do it with:

Outro

That is it. Feel free to contact me in Telegram if you will need more support or have any questions – @dhilbert or on Aurora Discord (@slava).

Foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.

Foundry consists of:

  • Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
  • Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
  • Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
  • Chisel: Fast, utilitarian, and verbose solidity REPL.

Documentation

https://book.getfoundry.sh/

Usage

Build

$ forge build

Test

$ forge test

Format

$ forge fmt

Gas Snapshots

$ forge snapshot

Anvil

$ anvil

Deploy

$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>

Cast

$ cast <subcommand>

Help

$ forge --help
$ anvil --help
$ cast --help

About

Solidity Contract to Support NEAR Chain Signatures on AURORA

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published