Aerenity - bring USDT and other stablecoins to AE

Aerenity is the bridge for stablecoins(USDT, USDC) from ethereum to aeternity.
It uses HTLC (hash time locked contract) to do atomic swap between blockchains. I think aeternity should have stablecoins in the network because this is blood of the DEFI.

Project implementation consists of several stages.

  1. MVP, participating in hackathon. Done. 2nd Place thank you for all people who believed in the project.
  2. Want to change a little bit flow for getting USDT on aeternity. And fully run it on the goerli testnet + ae testnet. And allow community to test it and get feedback,
  3. Run on mainnet
  4. Add more stablecoins
  5. Build some DEFI features, like lend/borrow

Right now you can check prototype on Will update you about project news.

cool! AE needs stable coins too much


it’s very cool to see you continuing to build on the project! can’t wait to see how it evolves and looking forward to test it extensively on testnet(s) :slight_smile:


Fantastic, we’ve been waiting for this day for a long time.

1 Like

Hey @FerumFlex, did you think about submitting your stablecoin prototype to the Lumos hackathon as well? I think it might fit well into the DeFi category.

good proposition, let me think about this)

1 Like

Hi guys
Recent days I heavily worked on the project, mostly research and understand how and what to do.
There are several starting points. AE unfortunately does not have USDT token minted on platform. We need to create it, but we can not just mint 1b(or more) tokens because they will cost anything. My plan is to lock USDT tokens on eth contract and mint same amount on AE. I see two ways how to implement this

  1. Better way, but right now more complex(maybe even undoable). Make those contracts that everyone can call, but in this case to mint USDT tokens on AE you need some proof that exact amount of USDT tokens was locked on ETH contract. I tried to learn zero knowledge proof, and I am investigateing this part. Sometimes it seems that this is not doable. Maybe I figure out how to do this…

  2. More centralized way. We need some bot(or oracle) that will move data about locking money from ETH to AE. We should trust this oracle, he should not cheat. I think I can build such Oracle and give management to AE team.

How do you think guys? Specially want to hear opinion of @marco.chain ))) But anybody are also welcome their thoughts)


@FerumFlex you might also wanna review this discussion we had before here on the forum about stable coins, just as additional input: Stable coins on AE? - #7 by vlad.chain

this here might be a good read: Bridging the Multichain Universe with Zero Knowledge Proofs | by Ingonyama | Oct, 2022 | Medium

actually I am not sure if we’re ready for ZKP implementations already. the chain generally provides capabilities for ZKP but when exploring the ZKP bounty (which we probably have to take down anyway due to the recent Tornado Cash news :sweat_smile: ), @VitalJeevanjot identified some missing capabilities which @hanssv.chain meanwhile already provided in the node implementation. I am not really into this topic, but those missing capabilities won’t be publicly usable until the upcoming Ceres hardfork is active on testnet & mainnet. not sure if this is also a limitation for your usecase.

generally I think ZKPs provide a lot of possibilities where some are probably even completely unexplored right now. but it’s also a very complex topic :smiley:

@FerumFlex maybe you can provide some diagrams which better visualize your considered approaches. it’s easier to discuss concrete proposals than written text only. also you’d have to think about the whole process and probably you’d identify some obstacles or wrong assumptions when thinking more deeply about it.

for the centralized way there is the problem that some party (or multiple parties according to the setup) is/are in control of releasing the funds. also you’d need to consider the bridge in both directions. I am not sure if we could find an entity or multiple entities providing such service :thinking:

I quickly thought about just “burning” (e.g. sending to zero address on Ethereum) USDT/USDC (or whatever) and just minting them on æternity then. this would probably be the easiest solution with no way back, but the stablecoin wouldn’t be “official” anymore and most likely not be supported by Tether, Circle, …

but to provide sth. like we’d “just” need to be able to check a specific tx on Ethereum really happened and verify that in a Sophia contract.

recently I had some conversation about if we could verify pricefeed oracle txs that e.g. happened on Ethereum. it would definitely be interesting to explore the following question in general:

  • “how to verify on-chain txs on Ethereum in a Sophia contract on æternity”?

just some thoughts on that topic from my side :slight_smile:


I think for solution with oracle something like this

1 Like

ZKP are Completely Doable on aeternity and its already done and pushed by me with snark js implementation and zokretes circuits as well.

The only thing here applies if those circuits utilizes ZKP friendly hash function which in this case considered Poseidon hash (to be release in ceres and hopefully callable through smart contracts) and that is only if you wish to perform these hash functions a lot many times, like in Merkle tree.

1 Like

Not to mention we cannot expect much from centralized exchanges in this case.

what are the following steps steps as they seem to be between user and AE contract?

  • is swap registrered and has confirmations >= n?
  • Yes is registered!

generally the flow is quite clear to me, but I am still not sure what’s the best approach :thinking:

how would somebody now be able to burn and unlock on ETH contract?

Hi guys, I am working on the project. But have a lot of problems, mostly because do not have good examples on how I can do it on Sophia. Most of them I solved…

Right now got another issue. SO I want to sign some message using oracle private key, and verify it on smartcontracts. On ethereium it works perfect.

how I generate signature

async function getSignature(web3, account, swapId) {
  let message = swapId;
  let hash = await web3.eth.personal.sign(message, account);
  return hash;

How I verify it on ethereum side

function parseSignature(bytes memory _signature)
    returns (
        bytes32 r,
        bytes32 s,
        uint8 v
    assembly {
        r := mload(add(_signature, 32))
        s := mload(add(_signature, 64))
        v := and(mload(add(_signature, 65)), 0xff)

    if (v < 27) v += 27;
    if (v != 27 && v != 28) revert SignatureInvalidV();

function sign(bytes32 swapId, bytes memory signature) external {
    (bytes32 r, bytes32 s, uint8 v) = parseSignature(signature);

    address signer = ecrecover(getUnsignedMsg(swapId), v, r, s);
    if (signer != oracle) {
        revert SignatureInvalidV();
    swaps[swapId].signature = signature;
    emit SwapSigned(swapId, signature);

function getUnsignedMsg(bytes32 data) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", data));

It works like a charm. Trying to calidate it on ae side.

  entrypoint get_unsigned_msg(data: hash) : hash =
    // 19457468657265756d205369676e6564204d6573736167653a0a3332 - is hash of the "\x19Ethereum Signed Message:\n32"
    Crypto.sha3(Bytes.concat(#19457468657265756d205369676e6564204d6573736167653a0a3332, data))

require(Crypto.ecverify_secp256k1(get_unsigned_msg(swapId),, signature), "Signature is not valid")

and it fails.
What I tried. I generate hash on ethereum using

let hash = await web3.eth.accounts.hashMessage(swapId);

and using get_unsigned_msg(swapId) and the are the same.

In Sophia’s tests I found this code:

contract BitcoinAuth =
  record state = { nonce : int, owner : bytes(20) }

  entrypoint init(owner' : bytes(20)) = { nonce = 1, owner = owner' }

  stateful entrypoint authorize(n : int, s : bytes(65)) : bool =
    require(n >= state.nonce, "Nonce too low")
    require(n =< state.nonce, "Nonce too high")
    put(state{ nonce = n + 1 })
      None          => abort("Not in Auth context")
      Some(tx_hash) => Crypto.ecverify_secp256k1(to_sign(tx_hash, n), state.owner, s)

  entrypoint to_sign(h : hash, n : int) : hash =
    Crypto.blake2b((h, n))

But why hash is generated using blake2b? SHould be sha3?

So my main question. Does anybody have worked example how I can sign message using web3 and verify it on ae side?


Never mind, was able to verify transaction. reason why it did not work. eth provides signature in format r,s,v. Ae waits for signature in format v,s,r.

Probably need to add new example.


hahaha, I also struggled with this in the past. didn’t we make that somehow clearer in the docs already? :thinking: cc @hanssv.chain

After @marco.chain’s struggles it was rather clearly documented I think. Should be in StdLib documentation somewhere… Yes here: Crypto.secp256k1_verify


Hi again, I am finishing my implementation. WIth a little bit different approach, so right now it has this flow:

  1. User sends usdt token to Eth gate contract. And this is htlc contract, if nothing happens he can return his money.
  2. Oracle in the background checks new fund of the gate contract and adds signature to the blockchain.
  3. After signature was got, user can use this signature to mint tokens on AE side.
1 Like

agree, some examples also will be helpful

@marco.chain it seems I broke it)