Fix builds (#12)

This commit is contained in:
Karl 2022-04-26 10:26:44 -05:00 committed by GitHub
parent ff64856758
commit b2f09b6add
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 335 additions and 318 deletions

View File

@ -1,49 +1,50 @@
-include Makefile.help
.PHONY: dependencies test clean all
.PHONY: clean all ethereum terra tilt-deploy tilt-test
all: build
.PHONY: build
## Build all Smart Contracts
build: ethereum terra
.PHONY: ethereum
ethereum: ethereum/build
ethereum/build:
cd ethereum && make build
.PHONY: terra
terra: terra/artifacts/checksum.txt
terra/artifacts/checksum.txt:
cd terra && make artifacts
.PHONY: tilt-test
## Run Integration Test in Tilt
tilt-test: sdk/js/src/icco/__tests__/tilt.json
@if ! pgrep tilt; then echo "Error: tilt not running. Start it before running tests"; exit 1; fi
cd sdk/js && npm run build && npm run test
sdk/js/src/icco/__tests__/tilt.json:
cp tilt.json sdk/js/src/icco/__tests__/tilt.json
.PHONY: tilt-deploy
## Deploy Contracts to Tilt
tilt-deploy: ethereum terra
@if ! pgrep tilt; then echo "Error: tilt not running. Start it before running tests"; exit 1; fi
cd ethereum && make tilt-deploy && npx truffle exec scripts/register_tilt_contributors.js --network eth_devnet
# cd terra && make terrad-deploy
# cd ethereum && node scripts/
all: ethereum terra sdk
.PHONY: clean
## Remove All Builds
clean:
cd ethereum && make clean
cd terra && make clean
cd sdk/js && rm -rf node_modules contracts lib src/icco/__tests__/tilt.json
.PHONY: tilt-clean
## Remove Everything For Tilt
tilt-clean: clean
rm -f sdk/js/src/icco/__tests__/tilt.json
.PHONY: ethereum
## Build Ethereum contracts
ethereum: ethereum/build
ethereum/build:
cd ethereum && make build
.PHONY: terra
## Build Terra contracts
terra: terra/artifacts/checksum.txt
terra/artifacts/checksum.txt:
cd terra && make build
.PHONY: sdk
## Build SDK
sdk: ethereum sdk/js/node_modules
cd sdk/js && npm run build
sdk/js/node_modules:
cd sdk/js && npm ci
.PHONY: tilt-deploy
## Deploy Contracts to Tilt
tilt-deploy: ethereum terra
@if ! pgrep tilt; then echo "Error: tilt not running. Start it before running tests"; exit 1; fi
cd ethereum && make tilt-deploy
cd ethereum && npx truffle exec scripts/register_tilt_contributors.js --network eth_devnet
.PHONY: tilt-test
## Run Integration Test in Tilt
tilt-test: sdk sdk/js/src/icco/__tests__/tilt.json
@if ! pgrep tilt; then echo "Error: tilt not running. Start it before running tests"; exit 1; fi
cd sdk/js && npm run build && npm run test
sdk/js/src/icco/__tests__/tilt.json:
cp tilt.json sdk/js/src/icco/__tests__/tilt.json

View File

@ -1,4 +1,4 @@
## This help screen
## List All Commands
help:
@printf "Available targets:\n\n"
@awk '/^[a-zA-Z\-\_0-9%:\\]+/ { \

280
README.md
View File

@ -1,278 +1,18 @@
# ICCO - Initial Cross-Chain Offerings
## Wormhole ICCO
## Objective
A trustless cross-chain mechanism to conduct a token sale. Please read the [whitepaper](WHITEPAPER.md) for background and design.
To use the Wormhole message passing protocol to enable trustless cross-chain token sales.
## Running in Devnet (Tilt)
## Background
To test the contract interactions, you will need to run Tilt from the [Wormhole repo](https://github.com/certusone/wormhole/tree/dev.v2).
Once Tilt is up, you can now deploy the contracts:
Token sales are one of the major applications of today's blockchains.
Currently they are either conducted on a single chain in a trustless fashion or in a centralized fashion with support to contribute tokens from multiple chains.
Using wormhole we can bridge this gap - Allow users to contribute assets on all supported chains and issue a token that we can bridge to all chains for them to claim after the sale has been concluded.
## Goals
We want to implement a generalized, trustless cross-chain mechanism for token sales.
* Allow contributions of whitelisted assets on all supported chains
* Users don't need to maintain multiple wallets, but can conveniently participate from their native environment.
* Issue a token on wormhole chain and leverage the wormholes token bridge to distribute them to all participants on their chains.
## Non-Goals
* Automatically relay messages across chains. The design assumes there is always a party interested in synchronizing the data across chains, let it be the token issuer or an investor who wants to claim its tokens.
## Overview
There are two programs needed to model this.
* A `TokenSaleConductor`, which lives on one chain (It can exist on all chains, however it only needs to be invoked on one to initiate a sale).
* It holds the tokens that are up for sale and maintains and collects the state around the sale.
* `TokenSaleContributor` contracts live on all chains.
* Collects contributions, distributes tokens to contributors after the sale has ended and the token allocation has been bridged.
## Detailed Design
To create a sale, a user invokes the `createSale()` method on the sale conductor. It takes the following set or arguments:
* A `Raise` struct with the following arguments:
* Offered token address
* Offered token amount
* A start time for when contributions can be accepted
* An end time for when contributions will no loner be accepted
* A minimum USD amount to raise
* A maximum USD amount to raise
* The address that can claim the proceeds of the sale
* The address that should receive the offered tokens in case the minimum raise amount is not met
* An array of accepted tokens on each chain + the USD conversion rate which they are accepted at
The `createSale()` method deposits the offered tokens, assigns an ID which identifies the sale and attests a `SaleInit` packet over the wormhole. This packet contains all the information from above.
The sale information is also stored locally.
The attested `SaleInit` packet is submitted to the `TokenSaleContributor` contracts. The contributor contracts stores the sale information locally which is relevant to its chain.
The `TokenSaleConductor` contract can terminate the sale by calling `abortSaleBeforeStartTime()` before the sale period begins.
During the start and end timestamp the contributor contracts accept contributions in the specified tokens.
After the sale duration anyone can call the `attestContributions()` method on the contributor, which attests a `Contribution` packet over the wormhole.
The `TokenSaleConductor` now collects the `Contributions` packets from all chains & tokens.
After all contributions have been collected, anyone can call the `sealSale()` method on the Conductor.
The method evaluates whether the minimum raise amount has been met using the conversion rates specified initially (a later version could use rates from an oracle at closing). In case it was successful it:
* calculates allocations and excess contributions (if total contributions sum to a value larger than the maximum raise amount)
* excess contributions are calculated by taking the difference between the maximum raise amount and the total contributions.
Each contributor receives excess contributions proportional to their contribution amount (individualContribution / totalContributions * totalExcessContributions)
* emits a `SaleSealed` packet - indicated to the Contributor contracts that the sale was successful
* bridges the relevant share of offered tokens to the Contributor contracts.
Or in case the goal was not met, it:
* emits a `SaleAborted` packet.
The Contributor contracts has two functions to consume the relevant attestations:
* `saleSealed()`
* Starts to accept claims of users acquired tokens via `claimAllocation()`
* Also pays out excess contributions
* Bridges the raised funds over to the recipient
* `saleAborted()`
* Starts to accept refund claims via `claimRefund()`
### API / database schema
**TokenSaleConductor**:
* `createSale(ICCOStructs.Raise memory raise, ICCOStructs.Token[] acceptedTokens)`
* `collectContributions(vaa Contributions)`
* `abortSaleBeforeStartTime(uint saleId)`
* `sealSale(uint saleId)`
* `claimRefund(uint saleId)`
* `saleExists(uint saleId)`
Governance:
* `registerChain(vaa RegisterChain)`
* `upgrade(vaa ConductorUpgrade)`
**TokenSaleContributor**:
* `initSale(vaa SaleInit)`
* `contribute(uint saleId, uint tokenIndex, uint amount)`
* `attestContributions(uint saleId)`
* `saleSealed(vaa SaleSealed)`
* `saleAborted(vaa SaleAborted)`
* `claimAllocation(uint saleId, uint tokenIndex)`
* `claimRefund(uint saleId, uint tokenIndex)`
* `saleExists(uint saleId)`
Governance:
* `upgrade(vaa ContributorUpgrade)`
---
**Structs**:
* Token
* uint16 chainId
* bytes32 address
* uint256 conversionRate
* Contribution
* uint8 tokenIndex (index in accepted tokens array)
* uint256 contributedAmount
* Allocation
* uint8 tokenIndex (index in accepted tokens array)
* uint256 allocation (amount distributed to contributors on this chain)
* uint256 excessContribution (excess contributions refunded to contributors on this chain)
* Raise
* address token (sale token address)
* uint256 tokenAmount (token amount being sold)
* uint256 minRaise (min raise amount)
* uint256 maxRaise (max raise amount)
* uint256 saleStart (timestamp raise start)
* uint256 saleEnd (timestamp raise end)
* address recipient (recipient of sale proceeds)
* address refundRecipient (refund recipient in case the sale is aborted)
---
**Payloads**:
SaleInit:
```
// PayloadID uint8 = 1
uint8 payloadID;
// Sale ID
uint256 saleID;
// Address of the token being sold. Left-zero-padded if shorter than 32 bytes
bytes32 tokenAddress;
// Chain ID of the token being sold
uint16 tokenChain;
// token amount being sold
uint256 tokenAmount;
// min raise amount
uint256 minRaise;
// max raise amount;
uint256 maxRaise;
// timestamp raise start
uint256 saleStart;
// timestamp raise end
uint256 saleEnd;
// accepted tokens length
uint8 tokensLen;
// repeated for tokensLen times, Struct 'Token'
// Address of the token. Left-zero-padded if shorter than 32 bytes
bytes32 tokenAddress;
// Chain ID of the token
uint16 tokenChain;
// conversion rate for the token
uint256 conversionRate;
// recipient of proceeds
bytes32 recipient;
// refund recipient in case the sale is aborted
bytes32 refundRecipient;
```sh
make tilt-deploy
```
ContributionsSealed:
```
// PayloadID uint8 = 2
uint8 payloadID;
// Sale ID
uint256 saleID;
// Chain ID
uint16 chainID;
To run the SDK integration test:
// local contributions length
uint8 contributionsLen;
// repeated for tokensLen times, Struct 'Contribution'
// index in acceptedTokens array
uint8 index
// contributed amount of token
uint256 contributed;
```
SaleSealed:
```
// PayloadID uint8 = 3
uint8 payloadID;
// Sale ID
uint256 saleID;
// local allocations length
uint8 allocationsLen;
// repeated for allocationsLen times, Struct 'Allocation'
// index in acceptedTokens array
uint8 index
// amount of sold tokens allocated to contributors on this chain
uint256 allocation;
// excess contributions refunded to contributors on this chain
uint256 excessContribution;
```
SaleAborted:
```
// PayloadID uint8 = 4
uint8 payloadID;
// Sale ID
uint256 saleID;
```
RegisterChain:
```
// Gov Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (1 for RegisterChain)
Action uint8 = 1
// Target Chain (Where the governance action should be applied)
// (0 is a valid value for all chains)
ChainId uint16
// Packet
// Emitter Chain ID
EmitterChainID uint16
// Emitter address. Left-zero-padded if shorter than 32 bytes
EmitterAddress [32]uint8
```
ConductorUpgrade:
```
// Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (2 for ConductorUpgrade)
Action uint8 = 2
// Target Chain (Where the governance action should be applied)
ChainId uint16
// Packet
// Address of the new contract
NewContract [32]uint8
```
ContributorUpgrade:
```
// Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (3 for ContributorUpgrade)
Action uint8 = 3
// Target Chain (Where the governance action should be applied)
ChainId uint16
// Packet
// Address of the new contract
NewContract [32]uint8
```sh
make tilt-test
```

278
WHITEPAPER.md Normal file
View File

@ -0,0 +1,278 @@
# ICCO - Initial Cross-Chain Offerings
## Objective
To use the Wormhole message passing protocol to enable trustless cross-chain token sales.
## Background
Token sales are one of the major applications of today's blockchains.
Currently they are either conducted on a single chain in a trustless fashion or in a centralized fashion with support to contribute tokens from multiple chains.
Using wormhole we can bridge this gap - Allow users to contribute assets on all supported chains and issue a token that we can bridge to all chains for them to claim after the sale has been concluded.
## Goals
We want to implement a generalized, trustless cross-chain mechanism for token sales.
* Allow contributions of whitelisted assets on all supported chains
* Users don't need to maintain multiple wallets, but can conveniently participate from their native environment.
* Issue a token on wormhole chain and leverage the wormholes token bridge to distribute them to all participants on their chains.
## Non-Goals
* Automatically relay messages across chains. The design assumes there is always a party interested in synchronizing the data across chains, let it be the token issuer or an investor who wants to claim its tokens.
## Overview
There are two programs needed to model this.
* A `TokenSaleConductor`, which lives on one chain (It can exist on all chains, however it only needs to be invoked on one to initiate a sale).
* It holds the tokens that are up for sale and maintains and collects the state around the sale.
* `TokenSaleContributor` contracts live on all chains.
* Collects contributions, distributes tokens to contributors after the sale has ended and the token allocation has been bridged.
## Detailed Design
To create a sale, a user invokes the `createSale()` method on the sale conductor. It takes the following set or arguments:
* A `Raise` struct with the following arguments:
* Offered token address
* Offered token amount
* A start time for when contributions can be accepted
* An end time for when contributions will no loner be accepted
* A minimum USD amount to raise
* A maximum USD amount to raise
* The address that can claim the proceeds of the sale
* The address that should receive the offered tokens in case the minimum raise amount is not met
* An array of accepted tokens on each chain + the USD conversion rate which they are accepted at
The `createSale()` method deposits the offered tokens, assigns an ID which identifies the sale and attests a `SaleInit` packet over the wormhole. This packet contains all the information from above.
The sale information is also stored locally.
The attested `SaleInit` packet is submitted to the `TokenSaleContributor` contracts. The contributor contracts stores the sale information locally which is relevant to its chain.
The `TokenSaleConductor` contract can terminate the sale by calling `abortSaleBeforeStartTime()` before the sale period begins.
During the start and end timestamp the contributor contracts accept contributions in the specified tokens.
After the sale duration anyone can call the `attestContributions()` method on the contributor, which attests a `Contribution` packet over the wormhole.
The `TokenSaleConductor` now collects the `Contributions` packets from all chains & tokens.
After all contributions have been collected, anyone can call the `sealSale()` method on the Conductor.
The method evaluates whether the minimum raise amount has been met using the conversion rates specified initially (a later version could use rates from an oracle at closing). In case it was successful it:
* calculates allocations and excess contributions (if total contributions sum to a value larger than the maximum raise amount)
* excess contributions are calculated by taking the difference between the maximum raise amount and the total contributions.
Each contributor receives excess contributions proportional to their contribution amount (individualContribution / totalContributions * totalExcessContributions)
* emits a `SaleSealed` packet - indicated to the Contributor contracts that the sale was successful
* bridges the relevant share of offered tokens to the Contributor contracts.
Or in case the goal was not met, it:
* emits a `SaleAborted` packet.
The Contributor contracts has two functions to consume the relevant attestations:
* `saleSealed()`
* Starts to accept claims of users acquired tokens via `claimAllocation()`
* Also pays out excess contributions
* Bridges the raised funds over to the recipient
* `saleAborted()`
* Starts to accept refund claims via `claimRefund()`
### API / database schema
**TokenSaleConductor**:
* `createSale(ICCOStructs.Raise memory raise, ICCOStructs.Token[] acceptedTokens)`
* `collectContributions(vaa Contributions)`
* `abortSaleBeforeStartTime(uint saleId)`
* `sealSale(uint saleId)`
* `claimRefund(uint saleId)`
* `saleExists(uint saleId)`
Governance:
* `registerChain(vaa RegisterChain)`
* `upgrade(vaa ConductorUpgrade)`
**TokenSaleContributor**:
* `initSale(vaa SaleInit)`
* `contribute(uint saleId, uint tokenIndex, uint amount)`
* `attestContributions(uint saleId)`
* `saleSealed(vaa SaleSealed)`
* `saleAborted(vaa SaleAborted)`
* `claimAllocation(uint saleId, uint tokenIndex)`
* `claimRefund(uint saleId, uint tokenIndex)`
* `saleExists(uint saleId)`
Governance:
* `upgrade(vaa ContributorUpgrade)`
---
**Structs**:
* Token
* uint16 chainId
* bytes32 address
* uint256 conversionRate
* Contribution
* uint8 tokenIndex (index in accepted tokens array)
* uint256 contributedAmount
* Allocation
* uint8 tokenIndex (index in accepted tokens array)
* uint256 allocation (amount distributed to contributors on this chain)
* uint256 excessContribution (excess contributions refunded to contributors on this chain)
* Raise
* address token (sale token address)
* uint256 tokenAmount (token amount being sold)
* uint256 minRaise (min raise amount)
* uint256 maxRaise (max raise amount)
* uint256 saleStart (timestamp raise start)
* uint256 saleEnd (timestamp raise end)
* address recipient (recipient of sale proceeds)
* address refundRecipient (refund recipient in case the sale is aborted)
---
**Payloads**:
SaleInit:
```
// PayloadID uint8 = 1
uint8 payloadID;
// Sale ID
uint256 saleID;
// Address of the token being sold. Left-zero-padded if shorter than 32 bytes
bytes32 tokenAddress;
// Chain ID of the token being sold
uint16 tokenChain;
// token amount being sold
uint256 tokenAmount;
// min raise amount
uint256 minRaise;
// max raise amount;
uint256 maxRaise;
// timestamp raise start
uint256 saleStart;
// timestamp raise end
uint256 saleEnd;
// accepted tokens length
uint8 tokensLen;
// repeated for tokensLen times, Struct 'Token'
// Address of the token. Left-zero-padded if shorter than 32 bytes
bytes32 tokenAddress;
// Chain ID of the token
uint16 tokenChain;
// conversion rate for the token
uint256 conversionRate;
// recipient of proceeds
bytes32 recipient;
// refund recipient in case the sale is aborted
bytes32 refundRecipient;
```
ContributionsSealed:
```
// PayloadID uint8 = 2
uint8 payloadID;
// Sale ID
uint256 saleID;
// Chain ID
uint16 chainID;
// local contributions length
uint8 contributionsLen;
// repeated for tokensLen times, Struct 'Contribution'
// index in acceptedTokens array
uint8 index
// contributed amount of token
uint256 contributed;
```
SaleSealed:
```
// PayloadID uint8 = 3
uint8 payloadID;
// Sale ID
uint256 saleID;
// local allocations length
uint8 allocationsLen;
// repeated for allocationsLen times, Struct 'Allocation'
// index in acceptedTokens array
uint8 index
// amount of sold tokens allocated to contributors on this chain
uint256 allocation;
// excess contributions refunded to contributors on this chain
uint256 excessContribution;
```
SaleAborted:
```
// PayloadID uint8 = 4
uint8 payloadID;
// Sale ID
uint256 saleID;
```
RegisterChain:
```
// Gov Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (1 for RegisterChain)
Action uint8 = 1
// Target Chain (Where the governance action should be applied)
// (0 is a valid value for all chains)
ChainId uint16
// Packet
// Emitter Chain ID
EmitterChainID uint16
// Emitter address. Left-zero-padded if shorter than 32 bytes
EmitterAddress [32]uint8
```
ConductorUpgrade:
```
// Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (2 for ConductorUpgrade)
Action uint8 = 2
// Target Chain (Where the governance action should be applied)
ChainId uint16
// Packet
// Address of the new contract
NewContract [32]uint8
```
ContributorUpgrade:
```
// Header
// Module Identifier ("TokenSale" left-padded)
Module [32]byte
// Governance Action ID (3 for ContributorUpgrade)
Action uint8 = 3
// Target Chain (Where the governance action should be applied)
ChainId uint16
// Packet
// Address of the new contract
NewContract [32]uint8
```

6
terra/Cargo.lock generated
View File

@ -428,7 +428,7 @@ dependencies = [
[[package]]
name = "cw20-wrapped"
version = "0.1.0"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy#ef08c8550c4c8c460a0a2ab0952d0772adae3bdb"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy"
dependencies = [
"cosmwasm-std",
"cosmwasm-storage",
@ -1426,7 +1426,7 @@ dependencies = [
[[package]]
name = "token-bridge-terra"
version = "0.1.0"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy#ef08c8550c4c8c460a0a2ab0952d0772adae3bdb"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy"
dependencies = [
"bigint",
"cosmwasm-std",
@ -1776,7 +1776,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "wormhole-bridge-terra"
version = "0.1.0"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy#ef08c8550c4c8c460a0a2ab0952d0772adae3bdb"
source = "git+https://github.com/certusone/wormhole?branch=feat/token-bridge-proxy"
dependencies = [
"cosmwasm-std",
"cosmwasm-storage",

View File

@ -7,9 +7,9 @@ WASMS=$(patsubst %, artifacts/%.wasm, $(PACKAGES))
-include ../Makefile.help
.PHONY: artifacts
.PHONY: build
## Build contracts.
artifacts: artifacts/checksums.txt
build: artifacts/checksums.txt
VALID_mainnet=1
VALID_testnet=1
@ -51,6 +51,4 @@ test:
.PHONY: clean
clean:
rm -f $(WASMS)
rm -f artifacts/checksums.txt
rm -rf tools/node_modules
rm -f $(WASMS) artifacts/checksums.txt tools/node_modules