fixed readme

This commit is contained in:
spacemandev 2022-06-29 23:56:33 -05:00
parent f57f4f92b0
commit e02bde2cc5
4 changed files with 142 additions and 7 deletions

View File

@ -15,11 +15,8 @@ Simply run `npm run guardiand` and wait while the Wormhole Guardian builds a doc
## Test Scripts
After you have Guardiand running, you can run the basic test with `npm run test`. This will:
- Deploy a simple Messenger contract (found in chains/evm/src/Messenger.sol) to each EVM chain
- Register each contract with the other chain
- Send a message from each contract
- Fetch the VAA from the Guardian
- Submit the VAA to each contract
- Print out the Message
- Deploy a Treasury contract
- Attest the TKN ERC20 token from Chain0 (ETH) to Chain1 (BSC)
- Mint 100 TKN tokens to the Treasury on ETH
- Approve & Transfer 50 TKN tokens from the treasury on ETH to the Treasury on BSC.
If everything goes correctly, you should get a printout with the Hello World messages on each chain.

View File

@ -0,0 +1,57 @@
# EVM: Attesting a Token
Attesting a token from EVM is fairly simple, and usually done via the Portal UI since it's a step that only needs to happen once per Token.
If for whatever reason you need to do it programmatically, you can also do it using the JS SDK:
The first step is to create an AttestMeta VAA. We do this by calling `attestFromEth()` function from the JS SDK and passing in the Token Bridge address, a Ethers signer object, and the address of the Token we want to attest:
```js
const networkTokenAttestation = await attestFromEth(
network.tokenBridgeAddress, // Token Bridge Address
signer, //Private Key to sign and pay for TX + RPC Endpoint
network.testToken //Token Address
);
```
Anyone can attest any token on the network.
To complete the Attestation, we grab the VAA that the `attestFromEth()` function generates by getting the Emitter address of the Token Bridge and the Sequence from the logs of the transaction receipt. We then fetch against a guardian REST endpoint. It could take a couple seconds (up to 30s!) for the guardian to see and sign the VAA, so it's a good idea to poll the guardian every couple seconds until the VAA is found.
```js
const emitterAddr = getEmitterAddressEth(network.tokenBridgeAddress);
const seq = parseSequenceFromLogEth(networkTokenAttestation, network.bridgeAddress);
const vaaURL = `${config.wormhole.restAddress}/v1/signed_vaa/${network.wormholeChainId}/${emitterAddr}/${seq}`;
console.log("Searching for: ", vaaURL);
let vaaBytes = await (await fetch(vaaURL)).json();
while(!vaaBytes.vaaBytes){
console.log("VAA not found, retrying in 5s!");
await new Promise((r) => setTimeout(r, 5000)); //Timeout to let Guardiand pick up log and have VAA ready
vaaBytes = await (await fetch(vaaURL)).json();
}
```
Next, we submit the VAA onto the target chain to create a wrapped version of the Token by calling `createWrapped()`. On an EVM chain, this will deploy a Portal Wrapped Token contract who's mint authority is the Portal Token Bridge on that chain. Sometimes this transaction throws an unpredicatable gas price error, so it's a good idea to set a high gas limit.
After the wrapped token is created, you can get the new wrapped token address by calling the `wrappedAsset()` function of the TokenBridge.
```js
await targetTokenBridge.createWrapped(Buffer.from(vaaBytes.vaaBytes, "base64"), {
gasLimit: 2000000
});
await new Promise((r) => setTimeout(r, 5000)); //Time out to let block propogate
const wrappedTokenAddress = await targetTokenBridge.wrappedAsset(
network.wormholeChainId,
Buffer.from(
tryNativeToHexString(network.testToken, "ethereum"),
"hex"
)
);
console.log("Wrapped token created at: ", wrappedTokenAddress);
```

View File

@ -0,0 +1,80 @@
# EVM: Transferring a Token
WARNING: To be able to successfully transfer a token from Chain A to Chain B, make sure you [attest](./attestingToken.md) it first. Otherwise the Token may be transferred, but you won't be able to claim it til it's attested.
One big gotcha new EVM developers usually run into when working with ERC20 tokens is that because EVM uses unsigned integers, there's no concept of decimals. Therefore, tokens usually have up to 18 zeros behind them to denote up to 18 decimal places. Wormhole normalizes this to *eight* zeros, with transfer amounts rounded down to the nearest 8the decimal.
To wrap the Token Bridge functions in your contract, you can use the Token Bridge interfaces provided under [`projects/evm-tokenbridge/chains/evm/src/Wormhole`](https://github.com/certusone/xdapp-book/tree/main/projects/evm-tokenbridge/chains/evm/src/Wormhole) folder of the xDapp Book repository.
```solidity
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
import "./Wormhole/ITokenBridge.sol";
import "./Wormhole/PortalWrappedToken.sol";
contract Treasury {
address private token_bridge_address = address(0x0290FB167208Af455bB137780163b7B7a9a10C16);
ITokenBridge token_bridge = ITokenBridge(token_bridge_address);
address private TKN_address = address(0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A);
ERC20PresetMinterPauser TKN = ERC20PresetMinterPauser(TKN_address);
uint32 nonce = 0;
function bridgeToken(uint256 amt, uint16 receipientChainId, bytes32 recipient) public returns (uint64 sequence) {
nonce += 1;
return token_bridge.transferTokens(TKN_address, amt, receipientChainId, recipient, 0, nonce);
}
function approveTokenBridge(uint256 amt) public returns (bool) {
return TKN.approve(token_bridge_address, amt);
}
}
```
To transfer a token, first we have to *approve* the Token Bridge to be able to spend that Token on our behalf (so it can transfer tokens form our contract to tself). Make sure the `bridgeAmt` properly takes into account decimals for the ERC20 token.
```js
// Here we are approving and transfering 50 tokens. The ERC20 token we are transfering has 18 decimal places.
const bridgeAmt = ethers.utils.parseUnits("50", "18");
await treasury.approveTokenBridge(bridgeAmt, {
gasLimit: 2000000,
});
```
Then we simply call `transfer` to create the transfer VAA and fetch it from the guardians when it's ready. Note that the target receipient is a Wormhole normalized hex address left-padded to 32 bytes.
```js
const targetRecepient = Buffer.from(tryNativeToHexString(targetDeployment.deployedAddress, "ethereum"), 'hex');
const tx = await (await treasury.bridgeToken(
bridgeAmt,
targetNetwork.wormholeChainId,
targetRecepient
)).wait();
const emitterAddr = getEmitterAddressEth(network.tokenBridgeAddress);
const seq = parseSequenceFromLogEth(tx, network.bridgeAddress);
const vaaURL = `${config.wormhole.restAddress}/v1/signed_vaa/${network.wormholeChainId}/${emitterAddr}/${seq}`;
let vaaBytes = await (await fetch(vaaURL)).json();
while(!vaaBytes.vaaBytes){
console.log("VAA not found, retrying in 5s!");
await new Promise((r) => setTimeout(r, 5000)); //Timeout to let Guardiand pick up log and have VAA ready
vaaBytes = await (await fetch(vaaURL)).json();
}
```
After we've fetched the VAA, we can call the `completeTransfer()` function on the target chain if it's an EVM.
```js
const completeTransferTx = await targetTokenBridge.completeTransfer(Buffer.from(vaaBytes.vaaBytes, "base64"));
```

View File

@ -0,0 +1 @@
# EVM: Transfer with Payload