From 250537a85aa02670246e3f78b0ef81d7ac79b1f1 Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Fri, 10 Nov 2023 16:07:06 -0600 Subject: [PATCH 1/6] feat: Add unassigned deposits Signed-off-by: carlos.vdr --- abis/Escrow.abi.json | 181 +++++++++++++++++++++++++++++++++++++++++ schema.graphql | 8 ++ src/mappings/escrow.ts | 41 +++++++++- subgraph.yaml | 10 ++- 4 files changed, 235 insertions(+), 5 deletions(-) diff --git a/abis/Escrow.abi.json b/abis/Escrow.abi.json index 7f5d078..86cd293 100644 --- a/abis/Escrow.abi.json +++ b/abis/Escrow.abi.json @@ -56,6 +56,11 @@ "name": "EscrowStillThawing", "type": "error" }, + { + "inputs": [], + "name": "InputsLengthMismatch", + "type": "error" + }, { "inputs": [ { @@ -77,6 +82,22 @@ "name": "InsufficientThawAmount", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "available", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "required", + "type": "uint256" + } + ], + "name": "InsufficientUnassignedEscrow", + "type": "error" + }, { "inputs": [], "name": "InvalidRAVSigner", @@ -233,6 +254,31 @@ "name": "Deposit", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DepositAssigned", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -351,6 +397,31 @@ "name": "ThawSigner", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "depositor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "UnassignedDeposit", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -396,6 +467,42 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "assignDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "receivers", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "assignDepositMany", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -474,6 +581,42 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "receivers", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "depositMany", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "depositUnassigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -586,6 +729,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "getUnassignedEscrowAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -716,6 +878,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "unassignedAccounts", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/schema.graphql b/schema.graphql index c2cba03..3d19463 100644 --- a/schema.graphql +++ b/schema.graphql @@ -37,6 +37,14 @@ type Transaction @entity{ escrowAccount: EscrowAccount! } +type UnnasignedTransaction @entity{ + id: ID! + transactionGroupID: String! + type: String! + sender: Sender! + amount: BigInt! +} + type AuthorizedSigner @entity{ id: ID! isAuthorized: Boolean! diff --git a/src/mappings/escrow.ts b/src/mappings/escrow.ts index f4aae35..fd3fcc9 100644 --- a/src/mappings/escrow.ts +++ b/src/mappings/escrow.ts @@ -5,9 +5,10 @@ import { Sender, Receiver, EscrowAccount, - AuthorizedSigner + AuthorizedSigner, + UnnasignedTransaction } from '../types/schema' -import { Deposit, Withdraw, Redeem, Thaw, AuthorizeSigner, RevokeAuthorizedSigner, CancelThaw, CancelThawSigner} from '../types/Escrow/Escrow' +import { Deposit, Withdraw, Redeem, Thaw, AuthorizeSigner, RevokeAuthorizedSigner, CancelThaw, CancelThawSigner, UnassignedDeposit, DepositAssigned} from '../types/Escrow/Escrow' let ZERO_BI = BigInt.fromI32(0) let ZERO_AD = '0x0000000000000000000000000000000000000000' @@ -31,6 +32,30 @@ export function handleCancelThaw(event: CancelThaw): void { escrow.save() } +export function handleUnassignedDeposit(event: UnassignedDeposit): void{ + let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.depositor.toHexString(), event.params.sender.toHexString()) + unnasignedTransaction.type = 'deposit' + unnasignedTransaction.amount.plus(event.params.amount) + unnasignedTransaction.save() +} + +export function handleDepositAssigned(event: DepositAssigned): void{ + let transaction = new Transaction(event.transaction.hash.toHexString() + '-' + event.logIndex.toString()) + let sender = createOrLoadSender(event.params.sender.toHexString()) + let receiver = createOrLoadReceiver(event.params.receiver.toHexString()) + let escrow = createOrLoadEscrowAccount(event.params.sender.toHexString(), event.params.receiver.toHexString()) + + transaction.type = "deposit" + transaction.sender = sender.id + transaction.receiver = receiver.id + transaction.amount = event.params.amount + transaction.escrowAccount = escrow.id + transaction.transactionGroupID = event.transaction.hash.toHexString() + + transaction.save() + escrow.save() +} + export function handleDeposit(event: Deposit): void { let transaction = new Transaction(event.transaction.hash.toHexString() + '-' + event.logIndex.toString()) let sender = createOrLoadSender(event.params.sender.toHexString()) @@ -168,4 +193,16 @@ export function createOrLoadEscrowAccount(sender: string, receiver: string): Esc escrowAccount.save() } return escrowAccount as EscrowAccount +} +// ID: would be the depositer +export function createOrLoadUnassignedTransaction(id: string, sender: string): UnnasignedTransaction{ + let unassignedTransaction = UnnasignedTransaction.load(id) + if(unassignedTransaction == null){ + unassignedTransaction = new UnnasignedTransaction(id) + unassignedTransaction.sender = sender + unassignedTransaction.amount = ZERO_BI + unassignedTransaction.type = '' + unassignedTransaction.save() + } + return unassignedTransaction as UnnasignedTransaction } \ No newline at end of file diff --git a/subgraph.yaml b/subgraph.yaml index 8ffb9b0..5270c4c 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -6,11 +6,11 @@ schema: dataSources: - kind: ethereum name: Escrow - network: mainnet + network: goerli source: - address: '0xe2e5421247C9aac3eee8417900138aB741b9f990' + address: '0xD46c60558F7960407F4D00098145D77Fd061aD90' abi: Escrow - startBlock: 0 + startBlock: 9765074 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -40,3 +40,7 @@ dataSources: handler: handleThawSigner - event: CancelThawSigner(indexed address,indexed address,uint256) handler: handleCancelThawSigner + - event: UnassignedDeposit(indexed address,indexed address,uint256) + handler: handleUnassignedDeposit + - event: DepositAssigned(indexed address,indexed address,uint256) + handler: handleDepositAssigned From 009c4be073b1a38024b4642a655894da5824f76b Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Thu, 16 Nov 2023 11:50:15 -0600 Subject: [PATCH 2/6] feat: Changed id relationship to the sender Signed-off-by: carlos.vdr --- schema.graphql | 3 +-- src/mappings/escrow.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/schema.graphql b/schema.graphql index 3d19463..ff2f4c3 100644 --- a/schema.graphql +++ b/schema.graphql @@ -41,8 +41,7 @@ type UnnasignedTransaction @entity{ id: ID! transactionGroupID: String! type: String! - sender: Sender! - amount: BigInt! + balance: BigInt! } type AuthorizedSigner @entity{ diff --git a/src/mappings/escrow.ts b/src/mappings/escrow.ts index fd3fcc9..253a24a 100644 --- a/src/mappings/escrow.ts +++ b/src/mappings/escrow.ts @@ -33,9 +33,9 @@ export function handleCancelThaw(event: CancelThaw): void { } export function handleUnassignedDeposit(event: UnassignedDeposit): void{ - let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.depositor.toHexString(), event.params.sender.toHexString()) + let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.sender.toHexString()) unnasignedTransaction.type = 'deposit' - unnasignedTransaction.amount.plus(event.params.amount) + unnasignedTransaction.balance.plus(event.params.amount) unnasignedTransaction.save() } @@ -44,6 +44,7 @@ export function handleDepositAssigned(event: DepositAssigned): void{ let sender = createOrLoadSender(event.params.sender.toHexString()) let receiver = createOrLoadReceiver(event.params.receiver.toHexString()) let escrow = createOrLoadEscrowAccount(event.params.sender.toHexString(), event.params.receiver.toHexString()) + let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.sender.toHexString()) transaction.type = "deposit" transaction.sender = sender.id @@ -52,6 +53,8 @@ export function handleDepositAssigned(event: DepositAssigned): void{ transaction.escrowAccount = escrow.id transaction.transactionGroupID = event.transaction.hash.toHexString() + unnasignedTransaction.balance.minus(event.params.amount) + transaction.save() escrow.save() } @@ -195,12 +198,11 @@ export function createOrLoadEscrowAccount(sender: string, receiver: string): Esc return escrowAccount as EscrowAccount } // ID: would be the depositer -export function createOrLoadUnassignedTransaction(id: string, sender: string): UnnasignedTransaction{ +export function createOrLoadUnassignedTransaction(id: string): UnnasignedTransaction{ let unassignedTransaction = UnnasignedTransaction.load(id) if(unassignedTransaction == null){ unassignedTransaction = new UnnasignedTransaction(id) - unassignedTransaction.sender = sender - unassignedTransaction.amount = ZERO_BI + unassignedTransaction.balance = ZERO_BI unassignedTransaction.type = '' unassignedTransaction.save() } From 48b42bec3862ac681b78a31298bd835b856b7fce Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Fri, 17 Nov 2023 09:34:07 -0600 Subject: [PATCH 3/6] fix: removed goerli Signed-off-by: carlos.vdr --- subgraph.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subgraph.yaml b/subgraph.yaml index 5270c4c..f9e6f51 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -6,11 +6,11 @@ schema: dataSources: - kind: ethereum name: Escrow - network: goerli + network: mainnet source: - address: '0xD46c60558F7960407F4D00098145D77Fd061aD90' + address: '0xe2e5421247C9aac3eee8417900138aB741b9f990' abi: Escrow - startBlock: 9765074 + startBlock: 0 mapping: kind: ethereum/events apiVersion: 0.0.6 From d387e63437fc8346fb310436a73d4a627bb9d161 Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Fri, 17 Nov 2023 09:35:31 -0600 Subject: [PATCH 4/6] refactor: Moved unassigned info into sender Signed-off-by: carlos.vdr --- schema.graphql | 7 +------ src/mappings/escrow.ts | 26 +++++++------------------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/schema.graphql b/schema.graphql index ff2f4c3..0737538 100644 --- a/schema.graphql +++ b/schema.graphql @@ -16,6 +16,7 @@ type Sender @entity { escrowAccounts: [EscrowAccount!] @derivedFrom(field: "sender") transactions: [Transaction!] @derivedFrom(field: "sender") authorizedSigners: [AuthorizedSigner!] @derivedFrom(field: "sender") + unassignedBalance: BigInt! } type Receiver @entity { @@ -37,12 +38,6 @@ type Transaction @entity{ escrowAccount: EscrowAccount! } -type UnnasignedTransaction @entity{ - id: ID! - transactionGroupID: String! - type: String! - balance: BigInt! -} type AuthorizedSigner @entity{ id: ID! diff --git a/src/mappings/escrow.ts b/src/mappings/escrow.ts index 253a24a..b168c31 100644 --- a/src/mappings/escrow.ts +++ b/src/mappings/escrow.ts @@ -5,8 +5,7 @@ import { Sender, Receiver, EscrowAccount, - AuthorizedSigner, - UnnasignedTransaction + AuthorizedSigner } from '../types/schema' import { Deposit, Withdraw, Redeem, Thaw, AuthorizeSigner, RevokeAuthorizedSigner, CancelThaw, CancelThawSigner, UnassignedDeposit, DepositAssigned} from '../types/Escrow/Escrow' let ZERO_BI = BigInt.fromI32(0) @@ -33,10 +32,9 @@ export function handleCancelThaw(event: CancelThaw): void { } export function handleUnassignedDeposit(event: UnassignedDeposit): void{ - let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.sender.toHexString()) - unnasignedTransaction.type = 'deposit' - unnasignedTransaction.balance.plus(event.params.amount) - unnasignedTransaction.save() + let sender = createOrLoadSender(event.params.sender.toHexString()) + sender.unassignedBalance.plus(event.params.amount) + sender.save() } export function handleDepositAssigned(event: DepositAssigned): void{ @@ -44,7 +42,6 @@ export function handleDepositAssigned(event: DepositAssigned): void{ let sender = createOrLoadSender(event.params.sender.toHexString()) let receiver = createOrLoadReceiver(event.params.receiver.toHexString()) let escrow = createOrLoadEscrowAccount(event.params.sender.toHexString(), event.params.receiver.toHexString()) - let unnasignedTransaction = createOrLoadUnassignedTransaction(event.params.sender.toHexString()) transaction.type = "deposit" transaction.sender = sender.id @@ -53,10 +50,11 @@ export function handleDepositAssigned(event: DepositAssigned): void{ transaction.escrowAccount = escrow.id transaction.transactionGroupID = event.transaction.hash.toHexString() - unnasignedTransaction.balance.minus(event.params.amount) + sender.unassignedBalance.minus(event.params.amount) transaction.save() escrow.save() + sender.save() } export function handleDeposit(event: Deposit): void { @@ -157,6 +155,7 @@ export function createOrLoadSender(id: string): Sender{ let sender = Sender.load(id) if(sender == null){ sender = new Sender(id) + sender.unassignedBalance = ZERO_BI sender.save() } return sender as Sender @@ -197,14 +196,3 @@ export function createOrLoadEscrowAccount(sender: string, receiver: string): Esc } return escrowAccount as EscrowAccount } -// ID: would be the depositer -export function createOrLoadUnassignedTransaction(id: string): UnnasignedTransaction{ - let unassignedTransaction = UnnasignedTransaction.load(id) - if(unassignedTransaction == null){ - unassignedTransaction = new UnnasignedTransaction(id) - unassignedTransaction.balance = ZERO_BI - unassignedTransaction.type = '' - unassignedTransaction.save() - } - return unassignedTransaction as UnnasignedTransaction -} \ No newline at end of file From d0e122c654b3875eb9db5abea060517d73e03f12 Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Fri, 17 Nov 2023 12:32:20 -0600 Subject: [PATCH 5/6] tests: Added tests for unassigned deposits Signed-off-by: carlos.vdr --- src/mappings/escrow.ts | 6 +++-- tests/helpers.py | 21 ++++++++++++++++++ tests/local_contract_calls.py | 41 ++++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/mappings/escrow.ts b/src/mappings/escrow.ts index b168c31..54e3527 100644 --- a/src/mappings/escrow.ts +++ b/src/mappings/escrow.ts @@ -33,7 +33,7 @@ export function handleCancelThaw(event: CancelThaw): void { export function handleUnassignedDeposit(event: UnassignedDeposit): void{ let sender = createOrLoadSender(event.params.sender.toHexString()) - sender.unassignedBalance.plus(event.params.amount) + sender.unassignedBalance = sender.unassignedBalance.plus(event.params.amount) sender.save() } @@ -50,7 +50,9 @@ export function handleDepositAssigned(event: DepositAssigned): void{ transaction.escrowAccount = escrow.id transaction.transactionGroupID = event.transaction.hash.toHexString() - sender.unassignedBalance.minus(event.params.amount) + sender.unassignedBalance = sender.unassignedBalance.minus(event.params.amount) + + escrow.balance = escrow.balance.plus(event.params.amount) transaction.save() escrow.save() diff --git a/tests/helpers.py b/tests/helpers.py index ec210bb..4c1a389 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -131,6 +131,27 @@ def check_subgraph_transaction( raise Exception(f"Subgraph expected info at amount incorrect") +@backoff.on_exception(backoff.expo, Exception, max_tries=MAX_TRIES) +def check_subgraph_sender(id, unassignedBalance, endpoint=subgraph_endpoint): + graphql_query = """ + query($id: String!){ + senders(where: {id: $id}) { + unassignedBalance + } + } + """ + vars = {"id": id.lower()} + request_data = {"query": graphql_query, "variables": vars} + resp = obtain_subgraph_info_backoff(endpoint, request_data, "senders") + print(f" ==== Subgraph response ==== \n {resp.text}") + + data = json.loads(resp.text)["data"]["senders"][0] + print(data) + balance = str(data["unassignedBalance"]) + if balance != str(unassignedBalance): + raise Exception(f"Subgraph expected info at unassignedBalance incorrect") + + @backoff.on_exception(backoff.expo, Exception, max_tries=MAX_TRIES) def check_subgraph_escrow_account( sender, receiver, total_amount_thawing, balance, endpoint=subgraph_endpoint diff --git a/tests/local_contract_calls.py b/tests/local_contract_calls.py index 8848c4e..28411b8 100644 --- a/tests/local_contract_calls.py +++ b/tests/local_contract_calls.py @@ -1,27 +1,19 @@ import json +import os import sys import time -import os from eip712.messages import EIP712Message from eth_account.messages import encode_defunct +from helpers import (ALLOCATION_ID, ALLOCATIONID_PK, GATEWAY, RECEIVER, SIGNER, + SIGNER_PK, check_subgraph_escrow_account, + check_subgraph_sender, check_subgraph_signer, + check_subgraph_transaction, decode_custom_error, + time_remaining) from web3 import Web3 from web3.exceptions import ContractCustomError, ContractLogicError -from helpers import ( - ALLOCATION_ID, - ALLOCATIONID_PK, - GATEWAY, - RECEIVER, - SIGNER, - SIGNER_PK, - check_subgraph_escrow_account, - check_subgraph_signer, - check_subgraph_transaction, - decode_custom_error, - time_remaining, -) - +ZERO_AD = "0x0000000000000000000000000000000000000000" # This script will help test that the subgraph is actually catching the required information ESCROW_ADDRESS = sys.argv[1] TAP_ADDRESS = sys.argv[2] @@ -113,10 +105,14 @@ class ReceiptAggregateVoucher(EIP712Message): eth_signed_message = encode_defunct(hexstr=message_hash.hex()) # Sign the message with the private key - signature = w3.eth.account.sign_message(eth_signed_message, private_key=ALLOCATIONID_PK) + signature = w3.eth.account.sign_message( + eth_signed_message, private_key=ALLOCATIONID_PK + ) arbitraryBytes32 = os.urandom(32) print("Allocate receiver with allocationid") - mockStaking.functions.allocate(arbitraryBytes32, 1000, ALLOCATION_ID, arbitraryBytes32, RECEIVER).transact({"from": RECEIVER}) + mockStaking.functions.allocate( + arbitraryBytes32, 1000, ALLOCATION_ID, arbitraryBytes32, RECEIVER + ).transact({"from": RECEIVER}) except ContractCustomError as e: raise ContractCustomError(decode_custom_error(mockStaking_abi_json, str(e), w3)) except ContractLogicError as e: @@ -228,6 +224,17 @@ class ReceiptAggregateVoucher(EIP712Message): check_subgraph_signer(SIGNER, False, False) + txn = escrow.functions.depositUnassigned(GATEWAY, 72).transact({"from": GATEWAY}) + print(f"Unassigned Deposit txn hash: {txn.hex()}") + check_subgraph_sender(GATEWAY, 72) + + print("Running Unnasigned tests") + txn = escrow.functions.assignDeposit(RECEIVER, 50).transact({"from": GATEWAY}) + print(f"Unassigned Deposit txn hash: {txn.hex()}") + check_subgraph_sender(GATEWAY, 22) + check_subgraph_transaction(txn.hex(), GATEWAY, RECEIVER, "deposit", 50) + check_subgraph_escrow_account(GATEWAY, RECEIVER, 0, 72) + print("Transactions ran succesfully") except ContractCustomError as e: raise ContractCustomError(decode_custom_error(escrow_abi_json, str(e), w3)) From 577af6647427a921e8205c074c4d644318b29c5a Mon Sep 17 00:00:00 2001 From: "carlos.vdr" Date: Fri, 17 Nov 2023 12:32:47 -0600 Subject: [PATCH 6/6] style: run isort for tesnet contract calls Signed-off-by: carlos.vdr --- tests/testnet_contract_calls.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/testnet_contract_calls.py b/tests/testnet_contract_calls.py index 777fadc..30e6e7c 100644 --- a/tests/testnet_contract_calls.py +++ b/tests/testnet_contract_calls.py @@ -7,12 +7,11 @@ import backoff from eip712.messages import EIP712Message from eth_account.messages import encode_defunct -from web3 import Web3 -from web3.exceptions import ContractCustomError, ContractLogicError - from helpers import (TEST_NET_VARS, add_nonce, check_deployed_subgraph_transaction, check_subgraph_signer, init_nonce) +from web3 import Web3 +from web3.exceptions import ContractCustomError, ContractLogicError testnet = sys.argv[1] @@ -153,9 +152,7 @@ def deposit_to_escrow(sender_account, receiver, amount, nonce_data): ) # Send ERC20 approval - print( - "txn hash aprove: ", sign_and_send_tx(sender_account, approve_txn).hex() - ) + print("txn hash aprove: ", sign_and_send_tx(sender_account, approve_txn).hex()) nonce_data = add_nonce(sender_account.address, nonce_data) deposit_txn = escrow_contract.functions.deposit(receiver, amount).build_transaction(