Converting DAI to xDAI with sbt-ethereum

In the prior post, we configured our sbt-ethereum installation to work with the xDAI chain, and created an account which, for that chain, we gave the alias testing-xDAI.

With our new account, we were able to interact with a contract to read, but we could not actually transact on the xDAI chain, because we didn’t have that chain’s “ether” (i.e. xDAI) with which to pay for gas.

Here we convert mainnet-Ethereum DAI to xDAI using the DAI-to-xDAI bridge. It was not difficult, but it was expensive, because it required three now-very-pricey mainnet transaction. (I made a mistake, so ended up paying to cover four mainnet transaction. Ultimately, to get 10 xDAI, worth $10, I paid about $35. If I had not screwed up and required an extra transaction, it would have been $28. The $18 difference between the $10 value of the xDAI I purchased and what I had to pay to get them represented fixed transaction costs. I could have gotten $1000 worth of xDAI for about $1018 which would have been less terrible in terms of transaction costs as a percentage of exchange. But I don’t want to convert $1000 to xDAI.

[Note: I badly overstated the costs here when I first published this; I accidentally counted some balances that were retained or transferred as costs. Sorry!]

Hopefully, however absurd the 180% transaction cost, it will prove worth it, as we’ll be able to do a lot of playing on the xDAI chain, building application that transact with real value, at a much much lower transaction cost there.

1. Purchase DAI

I purchased 20 DAI on Coinbase Pro, for $20.05.

2. Withdraw DAI to our testing-xDAI account

I withdrew 10 DAI to 0x72a8a15ECa1f824ADE35cdEB2148223402f23448, the account we set up in the previous post. Coinbase charged me a network fee of 8.24 DAI for the withdrawal.

3. Set up our testing-xDAI account on mainnet

An address, and the private key that signs transactions for it, are the same across all Ethereum chains and chain IDs. But sbt-ethereum scopes address aliases to individual chains. In the previous post, we set up the alias testing-xDAI on the xDAI chain, chain ID 100. We’ll also give it the same alias on mainnet, since we mean to use the DAI -> xDAI bridge from mainnet.

It’s a good idea when starting an sbt-ethereum session to type eth, to get a quick look at your current environment.

> eth
[info] The session is now active on chain with ID 1, with node URL 'https://ethjsonrpc.mchange.com/'.
[info] The current session sender is '0x465E79b940Bc2157E4259fF6B2D92f454497F1e4' (with aliases ['default-sender','testing0'] on chain with ID 1).
[info] The current default gas price according to your node is 199 gwei. (THIS MAY CHANGE AT ANY TIME.)

Cool. We are currently on the mainnet chain, with Chain ID 1. Let’s set up the alias to our new address. The task we’ll use is ethAddressAliasSet.

> ethAddressAliasSet testing-xDAI 0x72a8a15ECa1f824ADE35cdEB2148223402f23448
[info] Alias 'testing-xDAI' now points to address '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (for chain with ID 1).
[info] Refreshing caches.
[success] Total time: 0 s, completed Feb 20, 2021, 4:54:57 AM

4. Set up an alias for mainnet DAI

We’re also going to want to work with the mainnet ERC-20 token DAI. The smart contract that defined DAI tokens is at address 0x6B175474E89094C44Da98b954EedeAC495271d0F. We’ll want to set an alias for that too, so it is convenient to work with that token.

> ethAddressAliasSet DAI 0x6b175474e89094c44da98b954eedeac495271d0f
[info] Alias 'DAI' now points to address '0x6B175474E89094C44Da98b954EedeAC495271d0F' (for chain with ID 1).
[info] Refreshing caches.
[success] Total time: 0 s, completed Feb 20, 2021, 4:52:59 AM

Now we can very naturally get a quick summary of information about that ERC-20, using erc20Summary.

> erc20Summary DAI
[info] ERC20 Summary, token contract at '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1):
[info]   Self-Reported Name:   Dai Stablecoin
[info]   Self-Reported Symbol: DAI
[info]   Decimals:             18
[info]   Total Supply:         2305642358.809281038834982748 tokens (2305642358809281038834982748 atoms)
[success] Total time: 0 s, completed Feb 20, 2021, 4:53:06 AM

5. Switch to our testing-xDAI account and check our DAI balance

Our current session sender (see Step 3) above is not the testing-xDAI address we’d like to work with. Let’s temporarily change that using ethAddressSenderOverride.

ethAddressSenderOverride testing-xDAI
[info] Sender override set to '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (on chain with ID 1, aliases ['testing-xDAI'])).
[success] Total time: 0 s, completed Feb 20, 2021, 5:19:12 AM

Now let’s check tha account balance in DAI, using erc20Balance.

> erc20Balance DAI
[info] For ERC20 Token Contract '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1), with 18 decimals...
[info]   For Address '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['testing-xDAI'] on chain with ID 1))...
[info]     Balance: 10 tokens (which corresponds to 10000000000000000000 atoms)
[success] Total time: 1 s, completed Feb 20, 2021, 5:19:23 AM

Hooray! The 10 DAI we expensively withdrew from Coinbase have arrived.

Note: To get the DAI balance of our address, we could have just run erc20Balance DAI testing-xDAI, without overriding the default session sender.

6. Define an alias for the DAI-to-xDAI bridge

We will want to send our DAI to a smart contract, the DAI-to-xDAI bridge. Its address is 0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016, but as always, we prefer to work with human-friendly address aliases rather than long, easy to mess-up, hex strings. So let’s define an alias for that contract.

sbt:eth-command-line> ethAddressAliasSet DaiToXDaiTokenBridge 0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016
[info] Alias 'DaiToXDaiTokenBridge' now points to address '0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016' (for chain with ID 1).
[info] Refreshing caches.
[success] Total time: 0 s

7. Prepare to send ETH to testing-xDAI to cover transaction costs

We will want to send our DAI to the DAI-to-xDAI bridge, from our testing-xDAI account. But before we can do that, we’ll need to send some ETH to testing-xDAI to cover the transaction cost of that operation.

First we’ll need to figure out how much ETH to send. So we do a dry run (which we’ll abort before actually signing a transaction) and see how much sending DAI to the smart contract would cost. We’ll abort this dry run before signing the transaction (which couldn’t succeed, since our session sender, testing-xDAI, currently has no ETH to pay for gas). The task we’ll do a dry run of is erc20Transfer.

Note: The first time around I omitted to check this, and ended up sending too little ETH. That’s the nmistake I made that forced me to absorb ~$10 in oopsie transaction costs.

> erc20Transfer DAI DaiToXDaiTokenBridge 10
[warn] For the ERC20 token with contract address '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1)...
[warn]   you would transfer 10 tokens, which (with 18 decimals) translates to 10000000000000000000 atoms.
[warn] The transfer would be 
[warn]   From: '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['testing-xDAI'] on chain with ID 1)
[warn]   To:   '0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016' (with aliases ['DaiToXDaiTokenBridge'] on chain with ID 1)
[warn] You are calling the 'transfer' function on the contract at '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1).
[warn] THIS FUNCTION COULD DO ANYTHING. 
[warn] Make sure that you trust that the token contract does only what you intend, and carefully verify the transaction cost before approving the ultimate transaction.
Continue? [y/n] y

==> T R A N S A C T I O N   S I G N A T U R E   R E Q U E S T
==>
==> The transaction would be a message with...
==>   To:    0x6B175474E89094C44Da98b954EedeAC495271d0F (with aliases ['DAI'] on chain with ID 1)
==>   From:  0x72a8a15ECa1f824ADE35cdEB2148223402f23448 (with aliases ['testing-xDAI'] on chain with ID 1)
==>   Data:  0xa9059cbb0000000000000000000000004aa42145aa6ebf72e164c9bbc74fbd37880450160000000000000000000000000000000000000000000000008ac7230489e80000
==>   Value: 0 ether
==>
==> !!! Any ABI is associated with the destination address is currently unknown, so we cannot decode the message data as a method call !!!
==>
==> The nonce of the transaction would be 0.
==>
==> $$$ The transaction you have requested could use up to 44407 units of gas.
==> $$$ You would pay 143 gwei for each unit of gas, for a maximum cost of 0.006350201 ether.
==> $$$ This is worth 12.66 USD (according to Coinbase at 2:14 PM).

Would you like to sign this transaction? [y/n] n

[error] stack trace is suppressed; run last Compile / erc20Transfer for the full output
[error] (Compile / erc20Transfer) com.mchange.sc.v1.consuela.ethereum.jsonrpc.Invoker$TransactionDisapprovedException: Transaction aborted. [Disapproved: payload.size -> 68, nonce -> 0, gasPrice -> 143000000000, gasLimit -> 44407, value -> 0, proposedSigner -> 0x72a8a15ECa1f824ADE35cdEB2148223402f23448, chainId -> Some(EthChainId( 1, "mainnet" ))]
[error] Total time: 547 s (09:07), completed Feb 20, 2021, 2:23:25 PM
sbt:eth-command-line> ethTransactionEtherSend testing-xDAI 0.007 ether
[error] stack trace is suppressed; run last Compile / ethTransactionEtherSend for the full output
[error] (Compile / ethTransactionEtherSend) com.mchange.sc.v2.jsonrpc.package$JsonrpcException: err: insufficient funds for transfer (supplied gas 6244935) [code=-32000]: No further information
[error] Total time: 0 s, completed Feb 20, 2021, 2:25:58 PM

It looks like testing-xDAI need about 0.007 ETH (“0.006350201 ether”) to cover the cost of sending DAI.

Gas prices, and so the cost in ETH of transactions, change all the time! If you are following along, don’t assume the transaction cost will be about 0.007 ETH for you right now. Do your own dry run, and see what it costs!

7. Send some ETH to testing-xDAI to cover transaction costs

First, we’ll switch our session sender to an account that has some ETH, using ethAddressSenderOverride again.

> ethAddressSenderOverride testing0
[info] Sender override set to '0x465E79b940Bc2157E4259fF6B2D92f454497F1e4' (on chain with ID 1, aliases ['default-sender','testing0'])).
[success] Total time: 0 s, completed Feb 20, 2021, 6:14:39 AM

Then we’ll need to send 0.007 ETH from this address (which will be implicit, because it is our current session sender) to testing-xDAI. The task we’ll use is ethTransactionEtherSend.

> ethTransactionEtherSend testing-xDAI 0.007 ether

==> T R A N S A C T I O N   S I G N A T U R E   R E Q U E S T
==>
==> The transaction would be a message with...
==>   To:    0x72a8a15ECa1f824ADE35cdEB2148223402f23448 (with aliases ['testing-xDAI'] on chain with ID 1)
==>   From:  0x465E79b940Bc2157E4259fF6B2D92f454497F1e4 (with aliases ['default-sender','testing0'] on chain with ID 1)
==>   Data:  None
==>   Value: 0.007 ether/ Compile / ethTransactionEtherSend 0s
==>
==> The nonce of the transaction would be 562.
==>
==> $$$ The transaction you have requested could use up to 25200 units of gas.
==> $$$ You would pay 160 gwei for each unit of gas, for a maximum cost of 0.004032 ether.
==> $$$ This is worth 8.01 USD (according to Coinbase at 2:26 PM).
==> $$$ You would also send 0.007 ether (13.91 USD), for a maximum total cost of 0.011032 ether (21.92 USD).

Would you like to sign this transaction? [y/n] y

[info] Unlocking address '0x465E79b940Bc2157E4259fF6B2D92f454497F1e4' (with aliases ['default-sender','testing0'] on chain with ID 1).
Enter passphrase or hex private key for address '0x465E79b940Bc2157E4259fF6B2D92f454497F1e4': *******************
[info] Sending 7000000000000000 wei to address '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' in transaction with hash '0x1d8370e6fa6a1c4fc5bc209662b512fa922e22acdf951ee11dd88f245129d58d'.
[info] Waiting for the transaction to be mined (will wait up to 5 minutes).
[info] Transaction Receipt:
[info]        Transaction Hash:    0x1d8370e6fa6a1c4fc5bc209662b512fa922e22acdf951ee11dd88f245129d58d
[info]        Transaction Index:   145
[info]        Transaction Status:  SUCCEEDED
[info]        Block Hash:          0xca4be8c3bea39e1fcd880dc95fb6a207c2986d7b508413eed408c127aee2b037
[info]        Block Number:        11895720
[info]        From:                0x465E79b940Bc2157E4259fF6B2D92f454497F1e4
[info]        To:                  0x72a8a15ECa1f824ADE35cdEB2148223402f23448
[info]        Cumulative Gas Used: 12153193
[info]        Gas Used:            21000
[info]        Contract Address:    None
[info]        Logs:                None
[info]        Events:              None
[info] Ether sent.
[success] Total time: 296 s (04:56), completed Feb 20, 2021, 2:31:22 PM

All right!

8. Send 10 DAI to the DAI-to-xDAI bridge

We just send ETH from an address called testing0 to testing-xDAI. Now we’ll want to send from testing-xDAI, so we’ll need to change our current session sender. Again we’ll use ethAddressSenderOverride.

> ethAddressSenderOverride testing-xDAI
[info] Sender override set to '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (on chain with ID 1, aliases ['testing-xDAI'])).
[success] Total time: 0 s, completed Feb 20, 2021, 2:31:40 PM

Now we can actually do what we did only as a dry run before, use erc20Transfer to transfer 10 DAI to the DAI-to-xDAI bridge.

> erc20Transfer DAI DaiToXDaiTokenBridge 10
[warn] For the ERC20 token with contract address '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1)...
[warn]   you would transfer 10 tokens, which (with 18 decimals) translates to 10000000000000000000 atoms.
[warn] The transfer would be 
[warn]   From: '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['testing-xDAI'] on chain with ID 1)
[warn]   To:   '0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016' (with aliases ['DaiToXDaiTokenBridge'] on chain with ID 1)
[warn] You are calling the 'transfer' function on the contract at '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1).
[warn] THIS FUNCTION COULD DO ANYTHING. 
[warn] Make sure that you trust that the token contract does only what you intend, and carefully verify the transaction cost before approving the ultimate transaction.
Continue? [y/n] y

==> T R A N S A C T I O N   S I G N A T U R E   R E Q U E S T
==>
==> The transaction would be a message with...
==>   To:    0x6B175474E89094C44Da98b954EedeAC495271d0F (with aliases ['DAI'] on chain with ID 1)
==>   From:  0x72a8a15ECa1f824ADE35cdEB2148223402f23448 (with aliases ['testing-xDAI'] on chain with ID 1)
==>   Data:  0xa9059cbb0000000000000000000000004aa42145aa6ebf72e164c9bbc74fbd37880450160000000000000000000000000000000000000000000000008ac7230489e80000
==>   Value: 0 ether
==>
==> !!! Any ABI is associated with the destination address is currently unknown, so we cannot decode the message data as a method call !!!
==>
==> The nonce of the transaction would be 0.
==>
==> $$$ The transaction you have requested could use up to 44407 units of gas.
==> $$$ You would pay 120 gwei for each unit of gas, for a maximum cost of 0.00532884 ether.
==> $$$ This is worth 10.46 USD (according to Coinbase at 4:31 PM).

Would you like to sign this transaction? [y/n] y

[info] Unlocking address '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['testing-xDAI'] on chain with ID 1).
Enter passphrase or hex private key for address '0x72a8a15ECa1f824ADE35cdEB2148223402f23448': *******************
[info] ERC20 Transfer, Token Contract '0x6B175474E89094C44Da98b954EedeAC495271d0F' (with aliases ['DAI'] on chain with ID 1):
[info]   --> Sent 10 tokens (10000000000000000000 atoms)
[info]   -->   from '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['testing-xDAI'] on chain with ID 1)
[info]   -->   to '0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016' (with aliases ['DaiToXDaiTokenBridge'] on chain with ID 1)
[info] Waiting for the transaction to be mined (will wait up to 5 minutes).
[info] Transaction Receipt:
[info]        Transaction Hash:    0x201557273da97acc2b91a95856d54c38c8e66d107d8e7e7c88bd7a5819e03ee3
[info]        Transaction Index:   113
[info]        Transaction Status:  SUCCEEDED
[info]        Block Hash:          0x9b41dff12505a3603785089d6e7159c752204f251b65856a583e202122a9fdaf
[info]        Block Number:        11896288
[info]        From:                0x72a8a15ECa1f824ADE35cdEB2148223402f23448
[info]        To:                  0x6B175474E89094C44Da98b954EedeAC495271d0F
[info]        Cumulative Gas Used: 6540390
[info]        Gas Used:            22006
[info]        Contract Address:    None
[info]        Logs:                0 => EthLogEntry [source=0x6B175474E89094C44Da98b954EedeAC495271d0F] (
[info]                                    topics=[
[info]                                      0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef,
[info]                                      0x00000000000000000000000072a8a15eca1f824ade35cdeb2148223402f23448,
[info]                                      0x0000000000000000000000004aa42145aa6ebf72e164c9bbc74fbd3788045016
[info]                                    ],
[info]                                    data=0000000000000000000000000000000000000000000000008ac7230489e80000
[info]                                  )
[info]        Events:              0 => Transfer [source=0x6B175474E89094C44Da98b954EedeAC495271d0F] (
[info]                                    from (of type address): 0x72a8a15ECa1f824ADE35cdEB2148223402f23448,
[info]                                    to (of type address): 0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016,
[info]                                    tokens (of type uint256): 10000000000000000000
[info]                                  )
[success] Total time: 195 s (03:15), completed Feb 20, 2021, 4:34:43 PM

Looks good!

9. Verify receipt of xDAI as “ether” on the xDAI chain

After sending our DAI, I took a break, so I’m not sure how long it took the xDAI to be credited. But by the time I checked, it was. Let’s see how to check.

xDAI is the “ether” of the xDAI chain, with Chain ID 100. So all we need to do is switch to that chain, and check our balance.

First, we switch our session to the xDAI chain with ethNodeChainIdOverride.

> ethNodeChainIdOverride 100
[info] The chain ID has been overridden to 100.
[info] The session is now active on chain with ID 100, with node URL 'https://rpc.xdaichain.com/'.
[info] The current session sender is '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['default-sender','testing-xDAI'] on chain with ID 100).
[info] The current default gas price according to your node is 1 gwei. (THIS MAY CHANGE AT ANY TIME.)
[info] Refreshing caches.
[success] Total time: 0 s, completed Feb 20, 2021, 8:12:24 PM

Let’s “look around”, check out our current sbt-ethereum session environment, using eth.

> eth
[info] The session is now active on chain with ID 100, with node URL 'https://rpc.xdaichain.com/'.
[info] The current session sender is '0x72a8a15ECa1f824ADE35cdEB2148223402f23448' (with aliases ['default-sender','testing-xDAI'] on chain with ID 100).
[info] The current default gas price according to your node is 1 gwei. (THIS MAY CHANGE AT ANY TIME.)
[success] Total time: 0 s, completed Feb 20, 2021, 8:12:29 PM

In the previous post, we had set our default sender for Chain ID 100 to testing-xDAI. So when to that Chain ID, the xDAI chain, our “identity” is already that address. So we can just check the “ether” balance (remember, xDAI chain “ether” is exactly xDAI) of our current sender address. The task we’ll use is ethAddressBalance.

> ethAddressBalance
10 ether (as of the latest incorporated block, address 0x72a8a15ECa1f824ADE35cdEB2148223402f23448)
(The USD value of this is unknown, no exchange value is currently available for chain with ID 100 from Coinbase.)
[success] Total time: 0 s, completed Feb 20, 2021, 8:12:40 PM

As expected and desired, we have 10 “ether” on the xDAI chain, meaning 10 xDAI.

We could also have specified our address when looking up the balance, rather than relying upon the current session sender.

> ethAddressBalance testing-xDAI
10 ether (as of the latest incorporated block, address 0x72a8a15ECa1f824ADE35cdEB2148223402f23448)
(The USD value of this is unknown, no exchange value is currently available for chain with ID 100 from Coinbase.)
[success] Total time: 0 s, completed Feb 20, 2021, 8:12:54 PM

Unsurprisingly, we get the same “answer”.

We know have 10 xDAI on the xDAI chain, which we can use in further experiments to transact upon this chain. Hooray!