Skip to content

Commit

Permalink
eth v1 contract
Browse files Browse the repository at this point in the history
Implements the version 1 contracts for ethereum and tokens. Based
on feedback in #1426, everything is now encoded in the
"contract data". This "contract data", is the msgjson.Init.Contract
-> msgjson.Audit.Contract -> MatchMetaData.Proof.CounterContract,
AuditInfo.Contract -> Redemption.Spends.Contract.

A few new terms are introduced to differentiate various encodings and
data sets. The aforementioned contract data did encode a version
and a secret hash. It now encodes a version and a "locator", which is
a []byte whose length and content depend on the version. For
version 0, the locator is still just the secretHash[:]. For v1,
the locator encodes all of the immutable data that defines the
swap. This immutable data is now collected in something called
a "vector" (dexeth.SwapVector). For version 0, some vector data
is stored on-chain indexed by the secret hash. For version 1, all
vector data is encoded in the locator.

I've also made an effort to standardize the use of status/step,
and eliminated the use of ambiguous "ver" variables throughout.
A "status" is now the collection of mutable contract data: the step,
the init block height, and the secret. The status and vector
collectively fully characterize the swap.

client/asset/eth:
New contractV1 and tokenContractorV1 interfaces. To avoid duplication,
the ERC20 parts of the tokenContractors are separated into a new type
erc20Contractor that is embedded by both versions. Getters for
status and vector are added in place of the old method "swap".

assetWallet and embedding types are updated to work with the new
version-dependent locators and the status and vector model.

dex/networks/{eth,erc20}:
New contracts added. New methods for dealing with locators. Simnet
entries added for eth and dextt.eth in the ContractAddresses and Tokens
maps. txDataHandler interace is replaced with versioned package-level
functions.

server/asset/eth:
Server is fully switched to version 1. No option to use version 0.
Translation to new version was straightforward, with one notable
difference that we can no longer get a block height from the
contract once the swap is redeemed.
  • Loading branch information
buck54321 committed Oct 26, 2023
1 parent 8b54693 commit fe3fb28
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 68 deletions.
106 changes: 52 additions & 54 deletions client/asset/eth/nodeclient_harness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,10 @@ var (
participantAddr common.Address
participantAcct *accounts.Account
participantEthClient ethFetcher
ethSwapContractAddr common.Address
simnetContractor contractor
participantContractor contractor
simnetTokenContractor tokenContractor
participantTokenContractor tokenContractor
ethGases = dexeth.VersionedGases[0]
ethGases *dexeth.Gases
tokenGases *dexeth.Gases
testnetSecPerBlock = 15 * time.Second
Expand Down Expand Up @@ -131,6 +129,8 @@ var (
testTokenID uint32
masterToken *dexeth.Token

contractAddr common.Address

v1 bool
ver uint32
)
Expand Down Expand Up @@ -393,7 +393,7 @@ func runSimnet(m *testing.M) (int, error) {
fmt.Printf("Token swap contract addr is %v\n", token.SwapContracts[ver].Address)
fmt.Printf("Test token contract addr is %v\n", token.Address)

ethSwapContractAddr = dexeth.ContractAddresses[ver][dex.Simnet]
contractAddr = dexeth.ContractAddresses[ver][dex.Simnet]

initiatorProviders, participantProviders := rpcEndpoints(dex.Simnet)

Expand Down Expand Up @@ -510,8 +510,8 @@ func runTestnet(m *testing.M) (int, error) {
return 1, fmt.Errorf("error creating testnet participant wallet dir: %v", err)
}
secPerBlock = testnetSecPerBlock
ethSwapContractAddr = dexeth.ContractAddresses[ver][dex.Testnet]
fmt.Printf("ETH swap contract address is %v\n", ethSwapContractAddr)
contractAddr = dexeth.ContractAddresses[ver][dex.Testnet]
fmt.Printf("ETH swap contract address is %v\n", contractAddr)

initiatorRPC, participantRPC := rpcEndpoints(dex.Testnet)

Expand Down Expand Up @@ -560,20 +560,20 @@ func runTestnet(m *testing.M) (int, error) {
simnetAddr = simnetAcct.Address
participantAddr = participantAcct.Address

contractAddr, exists := dexeth.ContractAddresses[contractVer][dex.Testnet]
contractAddr, exists := dexeth.ContractAddresses[ver][dex.Testnet]
if !exists || contractAddr == (common.Address{}) {
return 1, fmt.Errorf("no contract address for version %d", contractVer)
return 1, fmt.Errorf("no contract address for version %d", ver)
}

ctor, tokenCtor := newV0Contractor, newV0TokenContractor
if ver == 1 {
ctor = newV1Contractor, newV1TokenContractor
ctor, tokenCtor = newV1Contractor, newV1TokenContractor
}

if simnetContractor, err = ctor(dex.Testnet, simnetAddr, ethClient.contractBackend()); err != nil {
if simnetContractor, err = ctor(dex.Testnet, contractAddr, simnetAddr, ethClient.contractBackend()); err != nil {
return 1, fmt.Errorf("newV0Contractor error: %w", err)
}
if participantContractor, err = ctor(dex.Testnet, participantAddr, participantEthClient.contractBackend()); err != nil {
if participantContractor, err = ctor(dex.Testnet, contractAddr, participantAddr, participantEthClient.contractBackend()); err != nil {
return 1, fmt.Errorf("participant newV0Contractor error: %w", err)
}

Expand Down Expand Up @@ -622,14 +622,14 @@ func prepareV1SimnetContractors() (err error) {
}

func prepareSimnetContractors(c contractorConstructor, tc tokenContractorConstructor) (err error) {
if simnetContractor, err = c(dex.Simnet, simnetAddr, ethClient.contractBackend()); err != nil {
if simnetContractor, err = c(dex.Simnet, contractAddr, simnetAddr, ethClient.contractBackend()); err != nil {
return fmt.Errorf("new contractor error: %w", err)
}
if participantContractor, err = c(dex.Simnet, participantAddr, participantEthClient.contractBackend()); err != nil {
if participantContractor, err = c(dex.Simnet, contractAddr, participantAddr, participantEthClient.contractBackend()); err != nil {
return fmt.Errorf("participant new contractor error: %w", err)
}

if simnetTokenContractor, err = tc(dex.Simnet, testTokenID, simnetAddr, ethClient.contractBackend()); err != nil {
if simnetTokenContractor, err = tc(dex.Simnet, masterToken, simnetAddr, ethClient.contractBackend()); err != nil {
return fmt.Errorf("new token contractor error: %w", err)
}

Expand All @@ -638,7 +638,7 @@ func prepareSimnetContractors(c contractorConstructor, tc tokenContractorConstru
// (*BoundContract).Call while calling (*ERC20Swap).TokenAddress.
time.Sleep(time.Second)

if participantTokenContractor, err = tc(dex.Simnet, testTokenID, participantAddr, participantEthClient.contractBackend()); err != nil {
if participantTokenContractor, err = tc(dex.Simnet, masterToken, participantAddr, participantEthClient.contractBackend()); err != nil {
return fmt.Errorf("participant new token contractor error: %w", err)
}
return
Expand Down Expand Up @@ -678,8 +678,10 @@ func TestMain(m *testing.M) {
}

ethGases = dexeth.VersionedGases[ver]
contractAddr = dexeth.ContractAddresses[BipID][dex.Simnet]

if isTestnet {
contractAddr = dexeth.ContractAddresses[BipID][dex.Testnet]
tmpDir, err := os.MkdirTemp("", "")
if err != nil {
fmt.Fprintf(os.Stderr, "error creating temporary directory: %v", err)
Expand Down Expand Up @@ -862,7 +864,7 @@ func TestContract(t *testing.T) {
}

func TestGas(t *testing.T) {
t.Run("testInitiateGas", func(t *testing.T) { testInitiateGas(t, BipID) })
// t.Run("testInitiateGas", func(t *testing.T) { testInitiateGas(t, BipID) })
t.Run("testRedeemGas", func(t *testing.T) { testRedeemGas(t, BipID) })
t.Run("testRefundGas", func(t *testing.T) { testRefundGas(t, BipID) })
}
Expand All @@ -877,7 +879,7 @@ func TestTokenContract(t *testing.T) {
func TestTokenGas(t *testing.T) {
t.Run("testTransferGas", testTransferGas)
t.Run("testApproveGas", testApproveGas)
t.Run("testInitiateTokenGas", func(t *testing.T) { testInitiateGas(t, testTokenID) })
// t.Run("testInitiateTokenGas", func(t *testing.T) { testInitiateGas(t, testTokenID) })
t.Run("testRedeemTokenGas", func(t *testing.T) { testRedeemGas(t, testTokenID) })
t.Run("testRefundTokenGas", func(t *testing.T) { testRefundGas(t, testTokenID) })
}
Expand Down Expand Up @@ -1165,43 +1167,39 @@ func testSyncProgress(t *testing.T) {
spew.Dump(p)
}

func testInitiateGas(t *testing.T, assetID uint32) {
if assetID != BipID {
prepareTokenClients(t)
}

net := dex.Simnet
if isTestnet {
net = dex.Testnet
}
gases := gases(BipID, assetID, ver, net)

var previousGas uint64
maxSwaps := 50
for i := 1; i <= maxSwaps; i++ {
gas, err := c.estimateInitGas(ctx, i)
if err != nil {
t.Fatalf("unexpected error from estimateInitGas(%d): %v", i, err)
}

var expectedGas uint64
var actualGas uint64
if i == 1 {
expectedGas = gases.Swap
actualGas = gas
} else {
expectedGas = gases.SwapAdd
actualGas = gas - previousGas
}
if actualGas > expectedGas || actualGas < expectedGas/2 {
t.Fatalf("Expected incremental gas for %d initiations to be close to %d but got %d",
i, expectedGas, actualGas)
}

fmt.Printf("Gas used for batch initiating %v swaps: %v. %v more than previous \n", i, gas, gas-previousGas)
previousGas = gas
}
}
// func testInitiateGas(t *testing.T, assetID uint32) {
// if assetID != BipID {
// prepareTokenClients(t)
// }

// gases := gases(ver, dexeth.VersionedGases)

// var previousGas uint64
// maxSwaps := 50
// for i := 1; i <= maxSwaps; i++ {
// gas, err := ethClient.estimateInitGas(ctx, i)
// if err != nil {
// t.Fatalf("unexpected error from estimateInitGas(%d): %v", i, err)
// }

// var expectedGas uint64
// var actualGas uint64
// if i == 1 {
// expectedGas = gases.Swap
// actualGas = gas
// } else {
// expectedGas = gases.SwapAdd
// actualGas = gas - previousGas
// }
// if actualGas > expectedGas || actualGas < expectedGas/2 {
// t.Fatalf("Expected incremental gas for %d initiations to be close to %d but got %d",
// i, expectedGas, actualGas)
// }

// fmt.Printf("Gas used for batch initiating %v swaps: %v. %v more than previous \n", i, gas, gas-previousGas)
// previousGas = gas
// }
// }

// feesAtBlk calculates the gas fee at blkNum. This adds the base fee at blkNum
// to a minimum gas tip cap.
Expand Down Expand Up @@ -2310,7 +2308,7 @@ func testGetCodeAt(t *testing.T) {
if !is {
t.Skip("getCode tests only run for nodeClient")
}
byteCode, err := cl.getCodeAt(ctx, ethSwapContractAddr)
byteCode, err := cl.getCodeAt(ctx, contractAddr)
if err != nil {
t.Fatalf("Failed to get bytecode: %v", err)
}
Expand Down
18 changes: 14 additions & 4 deletions dex/networks/eth/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func MaybeReadSimnetAddrs() {

func MaybeReadSimnetAddrsDir(
dir string,
contractsAddrs map[uint32]map[dex.Network]common.Address,
contractAddrs map[uint32]map[dex.Network]common.Address,
multiBalandAddresses map[dex.Network]common.Address,
token *NetToken,
) {
Expand All @@ -296,15 +296,23 @@ func MaybeReadSimnetAddrsDir(
return
}

fmt.Println("------------")
for ver, nets := range contractAddrs {
fmt.Println("--MaybeReadSimnetAddrsDir.0", ver, len(nets))
for net, addr := range nets {
fmt.Println("--MaybeReadSimnetAddrsDir.1", net, addr)
}
}

ethSwapContractAddrFileV0 := filepath.Join(harnessDir, "eth_swap_contract_address.txt")
tokenSwapContractAddrFileV0 := filepath.Join(harnessDir, "erc20_swap_contract_address.txt")
ethSwapContractAddrFileV1 := filepath.Join(harnessDir, "eth_swap_contract_address_v1.txt")
tokenSwapContractAddrFileV1 := filepath.Join(harnessDir, "erc20_swap_contract_address_v1.txt")
testTokenContractAddrFile := filepath.Join(harnessDir, "test_token_contract_address.txt")
multiBalanceContractAddrFile := filepath.Join(harnessDir, "multibalance_address.txt")

contractsAddrs[0][dex.Simnet] = getContractAddrFromFile(ethSwapContractAddrFileV0)
contractsAddrs[1][dex.Simnet] = getContractAddrFromFile(ethSwapContractAddrFileV1)
contractAddrs[0][dex.Simnet] = getContractAddrFromFile(ethSwapContractAddrFileV0)
contractAddrs[1][dex.Simnet] = getContractAddrFromFile(ethSwapContractAddrFileV1)
multiBalandAddresses[dex.Simnet] = getContractAddrFromFile(multiBalanceContractAddrFile)

token.SwapContracts[0].Address = getContractAddrFromFile(tokenSwapContractAddrFileV0)
Expand All @@ -315,7 +323,9 @@ func MaybeReadSimnetAddrsDir(
func getContractAddrFromFile(fileName string) (addr common.Address) {
addrBytes, err := os.ReadFile(fileName)
if err != nil {
fmt.Printf("error reading contract address: %v \n", err)
if !os.IsNotExist(err) {
fmt.Printf("error reading contract address: %v \n", err)
}
return
}
addrLen := len(addrBytes)
Expand Down
2 changes: 2 additions & 0 deletions dex/networks/polygon/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var (
dex.Testnet: common.HexToAddress("0xd45e648D97Beb2ee0045E5e91d1C2C751Cd0Bc00"), // txid: 0xa5f71d47998c175c9d2aba37ad2eff390ce7d20c312cee0472e3a5d606da385d
dex.Simnet: common.HexToAddress(""), // Filled in by MaybeReadSimnetAddrs
},
1: {},
}

MultiBalanceAddresses = map[dex.Network]common.Address{
Expand Down Expand Up @@ -110,6 +111,7 @@ var (
Transfer: 64_539,
},
},
1: {},
},
},
},
Expand Down
9 changes: 3 additions & 6 deletions server/asset/eth/coiner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,12 @@ func TestNewSwapCoin(t *testing.T) {
txCoinIDBytes := txHash[:]
badCoinIDBytes := encode.RandomBytes(39)
const gasPrice = 30
const value = 5e9
value := tSwap1.Value + tSwap2.Value
const gasTipCap = 2
wantGas, err := dexeth.WeiToGweiUint64(big.NewInt(3e10))
if err != nil {
t.Fatal(err)
}
wantVal, err := dexeth.WeiToGweiUint64(big.NewInt(5e18))
if err != nil {
t.Fatal(err)
}
wantGasTipCap, err := dexeth.WeiToGweiUint64(big.NewInt(2e9))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -237,10 +233,11 @@ func TestNewSwapCoin(t *testing.T) {

if sc.vector.To != tSwap2.Participant ||
sc.vector.SecretHash != tRedeem2.V.SecretHash ||
dexeth.WeiToGwei(sc.value) != wantVal ||
dexeth.WeiToGwei(sc.value) != value ||
sc.gasFeeCap != wantGas ||
sc.gasTipCap != wantGasTipCap ||
sc.vector.LockTime != tSwap2.RefundTimestamp {

t.Fatalf("returns do not match expected for test %q / %v", test.name, sc)
}
}
Expand Down
9 changes: 6 additions & 3 deletions server/asset/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func networkToken(vToken *VersionedToken, net dex.Network) (netToken *dexeth.Net
if !found {
return nil, nil, fmt.Errorf("no addresses for %s on %s", vToken.Name, net)
}

contract, found = netToken.SwapContracts[vToken.Ver]
if !found || contract.Address == (common.Address{}) {
return nil, nil, fmt.Errorf("no version %d address for %s on %s", vToken.Ver, vToken.Name, net)
Expand Down Expand Up @@ -584,13 +585,15 @@ func (eth *TokenBackend) ValidateContract(contractData []byte) error {
if err != nil { // ensures secretHash is proper length
return err
}

if ver != eth.VersionedToken.Ver {
return fmt.Errorf("incorrect token swap contract version %d, wanted %d", ver, eth.VersionedToken.Ver)
}

_, _, err = networkToken(eth.VersionedToken, eth.net)
if err != nil {
return fmt.Errorf("error locating token: %v", err)
}
if ver != eth.VersionedToken.Ver {
return fmt.Errorf("incorrect token swap contract version %d, wanted %d", ver, eth.VersionedToken.Ver)
}

return nil
}
Expand Down
11 changes: 10 additions & 1 deletion server/asset/eth/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,15 @@ func testValidateContract(t *testing.T, assetID uint32) {
ValidateContract([]byte) error
}

if assetID != BipID {
c := dexeth.Tokens[testTokenID].NetTokens[dex.Simnet].SwapContracts[0]
ogAddr := c.Address
c.Address = common.Address{0x01}
defer func() {
c.Address = ogAddr
}()
}

for _, test := range tests {
eth, _ := tNewBackend(assetID)
var cv contractValidator
Expand All @@ -737,7 +746,7 @@ func testValidateContract(t *testing.T, assetID uint32) {
AssetBackend: eth,
VersionedToken: &VersionedToken{
Token: dexeth.Tokens[testTokenID],
Ver: 0,
Ver: test.ver,
},
}
}
Expand Down

0 comments on commit fe3fb28

Please sign in to comment.