diff --git a/crates/erc20_payment_lib/config-payments.toml b/crates/erc20_payment_lib/config-payments.toml index b8da244b..0a7bd766 100644 --- a/crates/erc20_payment_lib/config-payments.toml +++ b/crates/erc20_payment_lib/config-payments.toml @@ -142,7 +142,7 @@ transaction-timeout = 100 token = { address = "0x8888888815bf4DB87e57B609A50f938311EEd068", symbol = "tGLM" } multi-contract = { address = "0xAaAAAaA00E1841A63342db7188abA84BDeE236c7", max-at-once = 10 } mint-contract = { address = "0xFACe100969FF47EB58d2CF603321B581A84bcEaC", max-glm-allowed = 400 } -lock-contract = { address = "0xAca2C77b0CbeB83AB0D3BbF6Fe185cc8c18934fb" } +lock-contract = { address = "0x6a5daa611235abf4c0bf4481eee7375b56f40734" } faucet-client = { max-eth-allowed = 0.009, faucet-srv = "_holesky-faucet._tcp", faucet-host = "faucet.testnet.golem.network", faucet-lookup-domain = "dev.golem.network", faucet-srv-port = 4002 } confirmation-blocks = 0 block-explorer-url = "https://holesky.etherscan.io" diff --git a/crates/erc20_payment_lib/contracts/lock_payments.json b/crates/erc20_payment_lib/contracts/lock_payments.json index d1ddeaae..36a8f5ea 100644 --- a/crates/erc20_payment_lib/contracts/lock_payments.json +++ b/crates/erc20_payment_lib/contracts/lock_payments.json @@ -26,27 +26,12 @@ { "inputs": [ { - "internalType": "uint32", + "internalType": "uint256", "name": "id", - "type": "uint32" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "extraFee", - "type": "uint128" - }, - { - "internalType": "uint32", - "name": "blockNo", - "type": "uint32" + "type": "uint256" } ], - "name": "addFundsToAllocation", + "name": "closeDeposit", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -54,9 +39,14 @@ { "inputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint128", @@ -65,16 +55,16 @@ }, { "internalType": "uint128", - "name": "extraFee", + "name": "feeAmount", "type": "uint128" }, { - "internalType": "uint32", - "name": "blockNo", - "type": "uint32" + "internalType": "uint64", + "name": "validToTimestamp", + "type": "uint64" } ], - "name": "addFundsToAllocationInternal", + "name": "createDeposit", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -82,32 +72,35 @@ { "inputs": [ { - "internalType": "uint32", + "internalType": "uint256", "name": "id", - "type": "uint32" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" + "type": "uint256" }, { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, + "internalType": "bytes32[]", + "name": "payments", + "type": "bytes32[]" + } + ], + "name": "depositTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint128", - "name": "feeAmount", - "type": "uint128" + "internalType": "uint256", + "name": "id", + "type": "uint256" }, { - "internalType": "uint32", - "name": "blockNo", - "type": "uint32" + "internalType": "bytes32[]", + "name": "payments", + "type": "bytes32[]" } ], - "name": "createAllocation", + "name": "depositTransferAndClose", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -115,10 +108,13 @@ { "inputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "deposits", + "outputs": [ { "internalType": "address", "name": "spender", @@ -135,25 +131,38 @@ "type": "uint128" }, { - "internalType": "uint32", - "name": "blockNo", - "type": "uint32" + "internalType": "uint64", + "name": "validTo", + "type": "uint64" } ], - "name": "createAllocationInternal", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, { "internalType": "uint128", - "name": "amount", + "name": "extraAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "extraFee", "type": "uint128" + }, + { + "internalType": "uint64", + "name": "validToTimestamp", + "type": "uint64" } ], - "name": "deposit", + "name": "extendDeposit", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -161,27 +170,20 @@ { "inputs": [ { - "internalType": "uint32", + "internalType": "uint256", "name": "id", - "type": "uint32" + "type": "uint256" } ], - "name": "freeAllocation", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "funderFromId", + "outputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" + "internalType": "address", + "name": "", + "type": "address" } ], - "name": "freeAllocationInternal", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "pure", "type": "function" }, { @@ -206,37 +208,54 @@ { "inputs": [ { - "internalType": "uint32", - "name": "", - "type": "uint32" + "internalType": "uint256", + "name": "id", + "type": "uint256" } ], - "name": "lockedAmounts", + "name": "getDeposit", "outputs": [ { - "internalType": "address", - "name": "customer", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "feeAmount", - "type": "uint128" - }, - { - "internalType": "uint32", - "name": "block_no", - "type": "uint32" + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "feeAmount", + "type": "uint128" + }, + { + "internalType": "uint64", + "name": "validTo", + "type": "uint64" + } + ], + "internalType": "struct DepositView", + "name": "", + "type": "tuple" } ], "stateMutability": "view", @@ -245,132 +264,106 @@ { "inputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" - }, - { - "internalType": "bytes32[]", - "name": "payments", - "type": "bytes32[]" + "internalType": "uint64", + "name": "nonce", + "type": "uint64" } ], - "name": "payoutMultiple", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "id", - "type": "uint32" - }, + "name": "getMyDeposit", + "outputs": [ { - "internalType": "bytes32[]", - "name": "payments", - "type": "bytes32[]" + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "feeAmount", + "type": "uint128" + }, + { + "internalType": "uint64", + "name": "validTo", + "type": "uint64" + } + ], + "internalType": "struct DepositView", + "name": "", + "type": "tuple" } ], - "name": "payoutMultipleInternal", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint64", + "name": "nonce", + "type": "uint64" } ], - "name": "payoutSingle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "id", - "type": "uint32" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, + "name": "idFromNonce", + "outputs": [ { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "payoutSingleInternal", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint256", + "name": "id", + "type": "uint256" } ], - "name": "transferInternal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "nonceFromId", + "outputs": [ { - "internalType": "address", - "name": "recipient", - "type": "address" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "name": "transferInternalAll", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "pure", "type": "function" }, { "inputs": [ { - "internalType": "uint128", - "name": "amount", - "type": "uint128" + "internalType": "uint64", + "name": "nonce", + "type": "uint64" } ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawAll", + "name": "terminateDeposit", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/src/actions/scan_chain.rs b/src/actions/scan_chain.rs index 72edb311..020ca54f 100644 --- a/src/actions/scan_chain.rs +++ b/src/actions/scan_chain.rs @@ -22,7 +22,6 @@ async fn scan_int( web3: Arc, start_block: i64, end_block: i64, - current_block: i64, sender: Option
, ) -> Result<(), PaymentError> { let txs = import_erc20_txs(ImportErc20TxsArgs { @@ -127,7 +126,6 @@ async fn scan_auto_step( ); return Ok(()); } - }; log::info!( @@ -144,7 +142,6 @@ async fn scan_auto_step( web3.clone(), start_block, end_block, - current_block, sender, ) .await?; @@ -274,7 +271,7 @@ pub async fn scan_blockchain_local( log::info!("Scan step failed - trying again: {}", e); } } - //tokio::time::sleep(std::time::Duration::from_millis(1000)).await; + // tokio::time::sleep(std::time::Duration::from_millis(1000)).await; } } else { if current_block < scan_info.last_block { @@ -324,12 +321,12 @@ pub async fn scan_blockchain_local( } } - let current_end_block = std::cmp::min( + /*let current_end_block = std::cmp::min( end_block, start_block + scan_blockchain_options.blocks_at_once as i64, - ); + );*/ - let mut scan_info = scan_info.clone(); + //let mut scan_info = scan_info.clone(); scan_int( conn.clone(), &scan_blockchain_options, @@ -337,7 +334,6 @@ pub async fn scan_blockchain_local( web3.clone(), start_block, end_block, - current_end_block, sender, ) .await?; diff --git a/yatestnet/contracts/contracts/LockPayment.sol b/yatestnet/contracts/contracts/LockPayment.sol index f4b9d157..d36d1748 100644 --- a/yatestnet/contracts/contracts/LockPayment.sol +++ b/yatestnet/contracts/contracts/LockPayment.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; +pragma solidity ^0.8.24; /** * @dev Interface of the ERC20 standard as defined in the EIP. @@ -79,21 +79,28 @@ interface IERC20 { ) external returns (bool); } - /** * Actors: - * - spender - the address that spends the funds - * - - the address that requested the funds - + * - Spender - the address that spends the funds + * - Funder - the address that deposits the funds */ struct Deposit { address spender; //address that can spend the funds provided by customer uint128 amount; //remaining funds locked uint128 feeAmount; //fee amount locked for spender - uint32 block_no; //after this block funds can be returned to customer + uint64 validTo; //after this timestamp funds can be returned to customer } + struct DepositView { + uint256 id; //unique id + uint64 nonce; //nonce unique for each funder + address funder; //address that can spend the funds provided by customer + address spender; //address that can spend the funds provided by customer + uint128 amount; //remaining funds locked + uint128 feeAmount; //fee amount locked for spender + uint64 validTo; //after this timestamp funds can be returned to customer + } /** * @dev This contract is part of GLM payment system. Visit https://golem.network for details. @@ -103,7 +110,7 @@ contract LockPayment { IERC20 public GLM; // allocation is stored using arbitrary id - mapping(uint32 => Allocation) public lockedAmounts; + mapping(uint256 => Deposit) public deposits; // fees are stored using spender address mapping(address => uint128) public funds; @@ -111,6 +118,27 @@ contract LockPayment { GLM = _GLM; } + function idFromNonce(uint64 nonce) public view returns (uint256) { + return (uint256(uint160(msg.sender)) << 96) ^ uint256(nonce); + } + + function nonceFromId(uint256 id) public pure returns (uint64) { + return uint64(id); + } + + function funderFromId(uint256 id) public pure returns (address) { + return address(uint160(id >> 96)); + } + + function getMyDeposit(uint64 nonce) public view returns (DepositView memory) { + Deposit memory deposit = deposits[idFromNonce(nonce)]; + return DepositView(idFromNonce(nonce), nonce, funderFromId(idFromNonce(nonce)), deposit.spender, deposit.amount, deposit.feeAmount, deposit.validTo); + } + + function getDeposit(uint256 id) public view returns (DepositView memory) { + Deposit memory deposit = deposits[id]; + return DepositView(id, nonceFromId(id), funderFromId(id), deposit.spender, deposit.amount, deposit.feeAmount, deposit.validTo); + } // createDeposit - Customer locks funds for usage by spender // @@ -121,95 +149,77 @@ contract LockPayment { // blockNo - block number until which funds are guaranteed to be locked for spender. // Spender still can use the funds after this block, // but customer can request the funds to be returned clearing allocation after (or equal to) this block number. - function createDeposit(uint32 nonce, address spender, uint128 amount, uint128 feeAmount, uint64 timestamp) external { + function createDeposit(uint64 nonce, address spender, uint128 amount, uint128 feeAmount, uint64 validToTimestamp) public { //check if id is not used - require(lockedAmounts[id].amount == 0, "lockedAmounts[id].amount == 0"); + uint256 id = idFromNonce(nonce); + require(deposits[id].amount == 0, "deposits[id].amount == 0"); require(amount > 0, "amount > 0"); - + require(spender != address(0), "spender cannot be null address"); + require(msg.sender != spender, "spender cannot be funder"); require(GLM.transferFrom(msg.sender, address(this), amount + feeAmount), "transferFrom failed"); - lockedAmounts[id] = Allocation(msg.sender, spender, amount, feeAmount, blockNo); + deposits[id] = Deposit(spender, amount, feeAmount, validToTimestamp); } - function extendDeposit(uint32 short_id, uint128 amount, uint128 extraFee, uint64 timestamp) external { - Allocation memory allocation = lockedAmounts[id]; - require(msg.sender == allocation.customer, "msg.sender == allocation.customer"); - require(GLM.transferFrom(msg.sender, address(this), amount + extraFee), "transferFrom failed"); - require(allocation.block_no <= blockNo, "allocation.block_no <= blockNo"); - allocation.amount += amount; - allocation.feeAmount += extraFee; - allocation.block_no = blockNo; - lockedAmounts[id] = allocation; + function extendDeposit(uint64 nonce, uint128 extraAmount, uint128 extraFee, uint64 validToTimestamp) public { + uint256 id = idFromNonce(nonce); + Deposit memory deposit = deposits[id]; + require(GLM.transferFrom(msg.sender, address(this), extraAmount + extraFee), "transferFrom failed"); + require(deposit.validTo <= validToTimestamp, "allocation.validTo <= validTo"); + deposit.amount += extraAmount; + deposit.feeAmount += extraFee; + deposit.validTo = validToTimestamp; + deposits[id] = deposit; } - // only spender and customer can return funds after block_no // these are two parties interested in returning funds - function closeAllocation(uint32 id) external { - Allocation memory allocation = lockedAmounts[id]; + function closeDeposit(uint256 id) public { + Deposit memory deposit = deposits[id]; // customer cannot return funds before block_no // sender can return funds at any time - require((msg.sender == allocation.customer && allocation.block_no <= block.number) || msg.sender == allocation.spender); - require(GLM.transfer(allocation.customer, allocation.amount + allocation.feeAmount), "transfer failed"); - lockedAmounts[id].amount = 0; - lockedAmounts[id].feeAmount = 0; + require(msg.sender == deposit.spender); + require(GLM.transfer(funderFromId(id), deposit.amount + deposit.feeAmount), "return transfer failed"); + if (deposit.feeAmount > 0) { + require(GLM.transfer(deposit.spender, deposit.feeAmount), "fee transfer failed"); + deposit.feeAmount = 0; + } + deposits[id].amount = 0; + deposits[id].feeAmount = 0; } - function freeAllocationInternal(uint32 id) external { - Allocation memory allocation = lockedAmounts[id]; + // funder can terminate deposit after validTo date elapses + function terminateDeposit(uint64 nonce) public { + uint256 id = idFromNonce(nonce); + Deposit memory deposit = deposits[id]; // customer cannot return funds before block_no // sender can return funds at any time - require((msg.sender == allocation.customer && allocation.block_no <= block.number) || msg.sender == allocation.spender); - funds[allocation.customer] += allocation.amount + allocation.feeAmount; - lockedAmounts[id].amount = 0; - lockedAmounts[id].feeAmount = 0; - } - - function depositTransferSingle(uint32 id, address recipient, uint128 amount) external { - Allocation memory allocation = lockedAmounts[id]; - require(msg.sender == allocation.spender, "msg.sender == allocation.spender"); - require(allocation.amount >= amount, "allocation.amount >= amount"); - - require(GLM.transfer(recipient, amount), "transfer failed"); - allocation.amount -= amount; - - if (allocation.feeAmount > 0) { - require(GLM.transfer(allocation.spender, allocation.feeAmount), "transfer failed"); - allocation.feeAmount = 0; - } - - if (allocation.amount == 0) { - delete lockedAmounts[id]; - } else { - lockedAmounts[id] = allocation; - } + require(deposit.validTo < block.timestamp); + require(GLM.transfer(msg.sender, deposit.amount + deposit.feeAmount), "transfer failed"); + deposits[id].amount = 0; + deposits[id].feeAmount = 0; } - function depositTransfer(uint32 id, bytes32[] calldata payments) external { - Allocation memory allocation = lockedAmounts[id]; - require(msg.sender == allocation.spender, "msg.sender == allocation.spender"); + function depositTransfer(uint256 id, bytes32[] calldata payments) public { + Deposit memory deposit = deposits[id]; + require(msg.sender == deposit.spender, "msg.sender == deposit.spender"); - for (uint i = 0; i < payments.length; ++i) { + for (uint32 i = 0; i < payments.length; ++i) { // A payment contains compressed data: // first 160 bits (20 bytes) is an address. // following 96 bits (12 bytes) is a value, bytes32 payment = payments[i]; address addr = address(bytes20(payment)); - uint128 amount = uint128(uint(payment) % 2**96); + uint128 amount = uint128(uint256(payment) % 2 ** 96); + require(addr != deposit.spender, "cannot transfer to spender"); require(GLM.transferFrom(msg.sender, addr, amount), "transferFrom failed"); - require(allocation.amount >= amount, "allocation.amount >= amount"); - allocation.amount -= amount; - } - - if (allocation.feeAmount > 0) { - require(GLM.transfer(allocation.spender, allocation.feeAmount), "transfer failed"); - allocation.feeAmount = 0; + require(deposit.amount >= amount, "deposit.amount >= amount"); + deposit.amount -= amount; } - if (allocation.amount == 0) { - delete lockedAmounts[id]; - } else { - lockedAmounts[id] = allocation; - } + deposits[id].amount = deposit.amount; } - + function depositTransferAndClose(uint256 id, bytes32[] calldata payments) public { + depositTransfer(id, payments); + closeDeposit(id); + } }