fix: approving tokens transfer when creating request (#385)

This commit is contained in:
Adam Uhlíř 2023-03-30 11:34:38 +02:00 committed by GitHub
parent d756bf9dc5
commit 3198db414d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 41 additions and 27 deletions

View File

@ -43,10 +43,6 @@ let config = await marketplace.config()
let collateral = config.collateral.initialAmount let collateral = config.collateral.initialAmount
``` ```
The host then needs to prepare a payment to the smart contract by calling the
`approve` method on the [ERC20 token][2]. Note that interaction with ERC20
contracts is not part of this library.
After preparing the payment, the host can deposit collateral: After preparing the payment, the host can deposit collateral:
```nim ```nim
await storage await storage
@ -83,9 +79,7 @@ let request : StorageRequest = (
When a client wants to submit this request to the network, it needs to pay the When a client wants to submit this request to the network, it needs to pay the
maximum price to the smart contract in advance. The difference between the maximum price to the smart contract in advance. The difference between the
maximum price and the offered price will be reimbursed later. To prepare, the maximum price and the offered price will be reimbursed later.
client needs to call the `approve` method on the [ERC20 token][2]. Note that
interaction with ERC20 contracts is not part of this library.
Once the payment has been prepared, the client can submit the request to the Once the payment has been prepared, the client can submit the request to the
network: network:
@ -152,7 +146,7 @@ Storage proofs
Time is divided into periods, and each period a storage proof may be required Time is divided into periods, and each period a storage proof may be required
from the host. The odds of requiring a storage proof are negotiated through the from the host. The odds of requiring a storage proof are negotiated through the
storage request. For more details about the timing of storage proofs, please storage request. For more details about the timing of storage proofs, please
refer to the [design document][3]. refer to the [design document][2].
At the start of each period of time, the host can check whether a storage proof At the start of each period of time, the host can check whether a storage proof
is required: is required:
@ -178,5 +172,4 @@ await storage
``` ```
[1]: https://github.com/status-im/codex-contracts-eth/ [1]: https://github.com/status-im/codex-contracts-eth/
[2]: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/ [2]: https://github.com/status-im/codex-research/blob/main/design/storage-proof-timing.md
[3]: https://github.com/status-im/codex-research/blob/main/design/storage-proof-timing.md

View File

@ -25,6 +25,12 @@ func new*(_: type OnChainMarket, contract: Marketplace): OnChainMarket =
signer: signer, signer: signer,
) )
method approveFunds*(market: OnChainMarket, amount: UInt256) {.async.} =
let tokenAddress = await market.contract.token()
let token = Erc20Token.new(tokenAddress, market.signer)
await token.approve(market.contract.address(), amount)
method getSigner*(market: OnChainMarket): Future[Address] {.async.} = method getSigner*(market: OnChainMarket): Future[Address] {.async.} =
return await market.signer.getAddress() return await market.signer.getAddress()

View File

@ -1,4 +1,5 @@
import pkg/ethers import pkg/ethers
import pkg/ethers/erc20
import pkg/json_rpc/rpcclient import pkg/json_rpc/rpcclient
import pkg/stint import pkg/stint
import pkg/chronos import pkg/chronos
@ -8,6 +9,7 @@ import ./config
export stint export stint
export ethers export ethers
export erc20
export config export config
type type
@ -31,6 +33,7 @@ type
proc config*(marketplace: Marketplace): MarketplaceConfig {.contract, view.} proc config*(marketplace: Marketplace): MarketplaceConfig {.contract, view.}
proc token*(marketplace: Marketplace): Address {.contract, view.}
proc slashMisses*(marketplace: Marketplace): UInt256 {.contract, view.} proc slashMisses*(marketplace: Marketplace): UInt256 {.contract, view.}
proc slashPercentage*(marketplace: Marketplace): UInt256 {.contract, view.} proc slashPercentage*(marketplace: Marketplace): UInt256 {.contract, view.}
proc minCollateralThreshold*(marketplace: Marketplace): UInt256 {.contract, view.} proc minCollateralThreshold*(marketplace: Marketplace): UInt256 {.contract, view.}

View File

@ -1,10 +0,0 @@
import pkg/chronos
import pkg/stint
import pkg/ethers
type
TestToken* = ref object of Contract
proc mint*(token: TestToken, holder: Address, amount: UInt256) {.contract.}
proc approve*(token: TestToken, spender: Address, amount: UInt256) {.contract.}
proc balanceOf*(token: TestToken, account: Address): UInt256 {.contract, view.}

View File

@ -1,6 +1,7 @@
import pkg/chronos import pkg/chronos
import pkg/upraises import pkg/upraises
import pkg/questionable import pkg/questionable
import pkg/ethers/erc20
import ./contracts/requests import ./contracts/requests
import ./clock import ./clock
@ -18,6 +19,10 @@ type
OnRequestCancelled* = proc(requestId: RequestId) {.gcsafe, upraises:[].} OnRequestCancelled* = proc(requestId: RequestId) {.gcsafe, upraises:[].}
OnRequestFailed* = proc(requestId: RequestId) {.gcsafe, upraises:[].} OnRequestFailed* = proc(requestId: RequestId) {.gcsafe, upraises:[].}
method approveFunds*(market: Market, amount: UInt256) {.base, async.} =
## This is generally needed for On-Chain ERC20 functionality to approve funds transfer to marketplace contract
raiseAssert("not implemented")
method getSigner*(market: Market): Future[Address] {.base, async.} = method getSigner*(market: Market): Future[Address] {.base, async.} =
raiseAssert("not implemented") raiseAssert("not implemented")

View File

@ -10,6 +10,7 @@ method enterAsync(state: PurchasePending) {.async.} =
raiseAssert "invalid state" raiseAssert "invalid state"
try: try:
await purchase.market.approveFunds(request.price())
await purchase.market.requestStorage(request) await purchase.market.requestStorage(request)
except CatchableError as error: except CatchableError as error:
state.switch(PurchaseErrored(error: error)) state.switch(PurchaseErrored(error: error))

View File

@ -28,10 +28,10 @@ Open a terminal and run:
Optionally, if you want to use the Marketplace blockchain functionality, you need to also include these flags: `--persistence --eth-account=<account>`, where `account` can be one following: Optionally, if you want to use the Marketplace blockchain functionality, you need to also include these flags: `--persistence --eth-account=<account>`, where `account` can be one following:
- `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266`
- `0x70997970C51812dc3A010C7d01b50e0d17dc79C8` - `0x70997970C51812dc3A010C7d01b50e0d17dc79C8`
- `0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC` - `0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC`
- `0x90F79bf6EB2c4f870365E785982E1f101E93b906` - `0x90F79bf6EB2c4f870365E785982E1f101E93b906`
- `0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65`
**For each node use a different account!** **For each node use a different account!**

View File

@ -80,6 +80,9 @@ proc new*(_: type MockMarket): MockMarket =
) )
MockMarket(signer: Address.example, config: config) MockMarket(signer: Address.example, config: config)
method approveFunds*(market: MockMarket, amount: UInt256) {.async.} =
discard
method getSigner*(market: MockMarket): Future[Address] {.async.} = method getSigner*(market: MockMarket): Future[Address] {.async.} =
return market.signer return market.signer

View File

@ -1,7 +1,7 @@
import pkg/chronos import pkg/chronos
import pkg/stint import pkg/stint
import codex/contracts import codex/contracts
import codex/contracts/testtoken import ./token
import ../ethertest import ../ethertest
ethersuite "Collateral": ethersuite "Collateral":

View File

@ -2,11 +2,11 @@ import std/json
import pkg/chronos import pkg/chronos
import pkg/ethers/testing import pkg/ethers/testing
import codex/contracts import codex/contracts
import codex/contracts/testtoken
import codex/storageproofs import codex/storageproofs
import ../ethertest import ../ethertest
import ./examples import ./examples
import ./time import ./time
import ./token
ethersuite "Marketplace contracts": ethersuite "Marketplace contracts":
let proof = exampleProof() let proof = exampleProof()

View File

@ -2,11 +2,11 @@ import std/options
import pkg/chronos import pkg/chronos
import pkg/stew/byteutils import pkg/stew/byteutils
import codex/contracts import codex/contracts
import codex/contracts/testtoken
import codex/storageproofs import codex/storageproofs
import ../ethertest import ../ethertest
import ./examples import ./examples
import ./time import ./time
import ./token
ethersuite "On-Chain Market": ethersuite "On-Chain Market":
let proof = exampleProof() let proof = exampleProof()

View File

@ -0,0 +1,9 @@
import pkg/chronos
import pkg/stint
import pkg/ethers
import pkg/ethers/erc20
type
TestToken* = ref object of Erc20Token
proc mint*(token: TestToken, holder: Address, amount: UInt256) {.contract.}

View File

@ -1,5 +1,6 @@
import pkg/ethers/erc20
import codex/contracts import codex/contracts
import codex/contracts/testtoken import ../contracts/token
proc mint*(signer: Signer, amount = 1_000_000.u256) {.async.} = proc mint*(signer: Signer, amount = 1_000_000.u256) {.async.} =
## Mints a considerable amount of tokens and approves them for transfer to ## Mints a considerable amount of tokens and approves them for transfer to
@ -7,10 +8,13 @@ proc mint*(signer: Signer, amount = 1_000_000.u256) {.async.} =
let token = TestToken.new(!deployment().address(TestToken), signer) let token = TestToken.new(!deployment().address(TestToken), signer)
let marketplace = Marketplace.new(!deployment().address(Marketplace), signer) let marketplace = Marketplace.new(!deployment().address(Marketplace), signer)
await token.mint(await signer.getAddress(), amount) await token.mint(await signer.getAddress(), amount)
await token.approve(marketplace.address, amount)
proc deposit*(signer: Signer) {.async.} = proc deposit*(signer: Signer) {.async.} =
## Deposits sufficient collateral into the Marketplace contract. ## Deposits sufficient collateral into the Marketplace contract.
let marketplace = Marketplace.new(!deployment().address(Marketplace), signer) let marketplace = Marketplace.new(!deployment().address(Marketplace), signer)
let config = await marketplace.config() let config = await marketplace.config()
let tokenAddress = await marketplace.token()
let token = Erc20Token.new(tokenAddress, signer)
await token.approve(marketplace.address, config.collateral.initialAmount)
await marketplace.deposit(config.collateral.initialAmount) await marketplace.deposit(config.collateral.initialAmount)

2
vendor/nim-ethers vendored

@ -1 +1 @@
Subproject commit 577e02b8a25198d6897c1f4871b5fd8e1f859e5a Subproject commit 3c12a65769b9a223028df25f78abb6dde06fef35