decred.org/dcrdex@v1.0.5/client/asset/eth/contractor_test.go (about) 1 package eth 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/big" 7 "testing" 8 9 "decred.org/dcrdex/client/asset" 10 "decred.org/dcrdex/dex/encode" 11 dexeth "decred.org/dcrdex/dex/networks/eth" 12 swapv0 "decred.org/dcrdex/dex/networks/eth/contracts/v0" 13 "github.com/ethereum/go-ethereum/accounts/abi/bind" 14 "github.com/ethereum/go-ethereum/common" 15 "github.com/ethereum/go-ethereum/core/types" 16 ) 17 18 type tContractV0 struct { 19 lastInits []swapv0.ETHSwapInitiation 20 initErr error 21 lastRedeems []swapv0.ETHSwapRedemption 22 redeemErr error 23 swap swapv0.ETHSwapSwap 24 swapErr error 25 } 26 27 func (c *tContractV0) Initiate(opts *bind.TransactOpts, initiations []swapv0.ETHSwapInitiation) (*types.Transaction, error) { 28 c.lastInits = initiations 29 return nil, c.initErr 30 } 31 32 func (c *tContractV0) Redeem(opts *bind.TransactOpts, redemptions []swapv0.ETHSwapRedemption) (*types.Transaction, error) { 33 c.lastRedeems = redemptions 34 return nil, c.redeemErr 35 } 36 37 func (c *tContractV0) Swap(opts *bind.CallOpts, secretHash [32]byte) (swapv0.ETHSwapSwap, error) { 38 return c.swap, c.swapErr 39 } 40 41 func (c *tContractV0) Refund(opts *bind.TransactOpts, secretHash [32]byte) (*types.Transaction, error) { 42 return nil, nil 43 } 44 45 func (c tContractV0) IsRefundable(opts *bind.CallOpts, secretHash [32]byte) (bool, error) { 46 return false, nil 47 } 48 49 func TestInitV0(t *testing.T) { 50 abiContract := &tContractV0{} 51 c := contractorV0{contractV0: abiContract, evmify: dexeth.GweiToWei} 52 addrStr := "0xB6De8BB5ed28E6bE6d671975cad20C03931bE981" 53 secretHashB := encode.RandomBytes(32) 54 const gweiVal = 123456 55 const lockTime = 100_000_000 56 57 contract := &asset.Contract{ 58 SecretHash: secretHashB, 59 Address: addrStr, 60 Value: gweiVal, 61 LockTime: lockTime, 62 } 63 64 contracts := []*asset.Contract{contract} 65 66 checkResult := func(tag string, wantErr bool) { 67 _, err := c.initiate(nil, contracts) 68 if (err != nil) != wantErr { 69 t.Fatal(tag) 70 } 71 } 72 73 checkResult("first success", false) 74 75 if len(abiContract.lastInits) != 1 { 76 t.Fatalf("wrong number of inits translated, %d", len(abiContract.lastInits)) 77 } 78 init := abiContract.lastInits[0] 79 if init.RefundTimestamp.Uint64() != lockTime { 80 t.Fatalf("wrong RefundTimestamp. expected %d, got %d", lockTime, init.RefundTimestamp.Uint64()) 81 } 82 if !bytes.Equal(init.SecretHash[:], secretHashB) { 83 t.Fatalf("wrong secret hash.") 84 } 85 if init.Participant != common.HexToAddress(addrStr) { 86 t.Fatalf("wrong address. wanted %s, got %s", common.HexToAddress(addrStr), init.Participant) 87 } 88 if dexeth.WeiToGwei(init.Value) != gweiVal { 89 t.Fatalf("wrong value. wanted %d, got %d", gweiVal, dexeth.WeiToGwei(init.Value)) 90 } 91 92 // wrong secret hash size 93 contract.SecretHash = encode.RandomBytes(20) 94 checkResult("bad hash", true) 95 contract.SecretHash = encode.RandomBytes(32) 96 97 // dupe hash 98 contracts = []*asset.Contract{contract, contract} 99 checkResult("dupe hash", true) 100 101 // ok with two 102 contract2 := *contract 103 contract2.SecretHash = encode.RandomBytes(32) 104 contracts = []*asset.Contract{contract, &contract2} 105 checkResult("ok two", false) 106 contracts = []*asset.Contract{contract} 107 108 if len(abiContract.lastInits) != 2 { 109 t.Fatalf("two contracts weren't passed") 110 } 111 112 // bad address 113 contract.Address = "badaddress" 114 checkResult("bad address", true) 115 contract.Address = addrStr 116 117 // Initiate error 118 abiContract.initErr = fmt.Errorf("test error") 119 checkResult("contract error", true) 120 abiContract.initErr = nil 121 122 // Success again 123 checkResult("success again", false) 124 } 125 126 func TestRedeemV0(t *testing.T) { 127 abiContract := &tContractV0{} 128 c := contractorV0{contractV0: abiContract, evmify: dexeth.GweiToWei} 129 130 secretB := encode.RandomBytes(32) 131 secretHashB := encode.RandomBytes(32) 132 133 redemption := &asset.Redemption{ 134 Secret: secretB, 135 Spends: &asset.AuditInfo{SecretHash: secretHashB}, 136 } 137 138 redemptions := []*asset.Redemption{redemption} 139 140 checkResult := func(tag string, wantErr bool) { 141 _, err := c.redeem(nil, redemptions) 142 if (err != nil) != wantErr { 143 t.Fatal(tag, err) 144 } 145 } 146 147 checkResult("initial success", false) 148 149 if len(abiContract.lastRedeems) != 1 { 150 t.Fatalf("contract not passed") 151 } 152 redeem := abiContract.lastRedeems[0] 153 if !bytes.Equal(redeem.Secret[:], secretB) { 154 t.Fatalf("secret not translated") 155 } 156 if !bytes.Equal(redeem.SecretHash[:], secretHashB) { 157 t.Fatalf("secret hash not translated") 158 } 159 160 // bad secret hash length 161 redemption.Spends.SecretHash = encode.RandomBytes(20) 162 checkResult("bad secret hash length", true) 163 redemption.Spends.SecretHash = encode.RandomBytes(32) 164 165 // bad secret length 166 redemption.Secret = encode.RandomBytes(20) 167 checkResult("bad secret length", true) 168 redemption.Secret = encode.RandomBytes(32) 169 170 // Redeem error 171 abiContract.redeemErr = fmt.Errorf("test error") 172 checkResult("contract error", true) 173 abiContract.redeemErr = nil 174 175 // Error on dupe. 176 redemptions = []*asset.Redemption{redemption, redemption} 177 checkResult("dupe error", true) 178 179 // two OK 180 redemption2 := &asset.Redemption{ 181 Secret: encode.RandomBytes(32), 182 Spends: &asset.AuditInfo{SecretHash: encode.RandomBytes(32)}, 183 } 184 redemptions = []*asset.Redemption{redemption, redemption2} 185 checkResult("two ok", false) 186 } 187 188 func TestSwapV0(t *testing.T) { 189 abiContract := &tContractV0{} 190 c := contractorV0{ 191 contractV0: abiContract, 192 evmify: dexeth.GweiToWei, 193 atomize: dexeth.WeiToGwei, 194 } 195 196 var secret [32]byte 197 const valGwei = 123_456 198 const blockNum = 654_321 199 const stamp = 789_654 200 var initiator, participant common.Address 201 copy(initiator[:], encode.RandomBytes(32)) 202 copy(participant[:], encode.RandomBytes(32)) 203 const state = 128 204 205 abiContract.swap = swapv0.ETHSwapSwap{ 206 Secret: secret, 207 Value: dexeth.GweiToWei(valGwei), 208 InitBlockNumber: big.NewInt(blockNum), 209 RefundBlockTimestamp: big.NewInt(stamp), 210 Initiator: initiator, 211 Participant: participant, 212 State: state, 213 } 214 215 // error path 216 abiContract.swapErr = fmt.Errorf("test error") 217 _, err := c.swap(nil, [32]byte{}) 218 if err == nil { 219 t.Fatalf("swap error not transmitted") 220 } 221 abiContract.swapErr = nil 222 223 swap, err := c.swap(nil, [32]byte{}) 224 if err != nil { 225 t.Fatalf("swap error: %v", err) 226 } 227 228 if swap.Secret != secret { 229 t.Fatalf("wrong secret") 230 } 231 if dexeth.WeiToGwei(swap.Value) != valGwei { 232 t.Fatalf("wrong value") 233 } 234 if swap.BlockHeight != blockNum { 235 t.Fatalf("wrong block height") 236 } 237 if swap.LockTime.Unix() != stamp { 238 t.Fatalf("wrong lock time") 239 } 240 if swap.Initiator != initiator { 241 t.Fatalf("initiator not transmitted") 242 } 243 if swap.Participant != participant { 244 t.Fatalf("participant not transmitted") 245 } 246 if swap.State != state { 247 t.Fatalf("state not transmitted") 248 } 249 }