Adjusted implementation based on lock returned

This commit is contained in:
Filipe Soccol 2022-11-01 17:07:34 -03:00
parent c9243a38d1
commit 1298b0d368
4 changed files with 94 additions and 43 deletions

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/e163883cb06c01d261c8d27101a410f2.json" "buildInfo": "../../build-info/e53d155f4d4e8ba3d5f49011e7166818.json"
} }

File diff suppressed because one or more lines are too long

View File

@ -6,8 +6,9 @@ contract P2PIX {
event DepositAdded(address indexed seller, bytes32 depositID, address token, uint256 amount); event DepositAdded(address indexed seller, bytes32 depositID, address token, uint256 amount);
event DepositClosed(address indexed seller, bytes32 depositID); event DepositClosed(address indexed seller, bytes32 depositID);
event DepositWithdrawn(address indexed seller, bytes32 depositID, uint256 amount); event DepositWithdrawn(address indexed seller, bytes32 depositID, uint256 amount);
event LockAdded(address indexed buyer, bytes32 lockID, uint256 amount); event LockAdded(address indexed buyer, bytes32 indexed lockID, bytes32 depositID, uint256 amount);
event LockReleased(address indexed buyer, bytes32 lockId); event LockReleased(address indexed buyer, bytes32 lockId);
event LockReturned(address indexed buyer, bytes32 lockId);
struct Deposit { struct Deposit {
address seller; address seller;
@ -23,22 +24,19 @@ contract P2PIX {
address relayerAddress; // Relayer address that facilitated this transaction address relayerAddress; // Relayer address that facilitated this transaction
uint256 relayerPremium; // Amount to be paid for relayer uint256 relayerPremium; // Amount to be paid for relayer
uint256 amount; // Amount to be transfered to buyer uint256 amount; // Amount to be transfered to buyer
uint256 expirationBlock; // IF not paid until this block will be expired uint256 expirationBlock; // If not paid at this block will be expired
bool paid;
} }
// Default blocks that lock will hold tokens // Default blocks that lock will hold tokens
uint256 internal defaultLockBlocks; uint256 public defaultLockBlocks;
// List of valid Bacen signature addresses // List of valid Bacen signature addresses
mapping(address => bool) public validBacenSigners; mapping(address => bool) public validBacenSigners;
// Seller list of deposits // Seller list of deposits
mapping(bytes32 => Deposit) mapDeposits; mapping(bytes32 => Deposit) mapDeposits;
mapping(bytes32 => bytes32[]) activeDepositLocks; // List of Locks
mapping(bytes32 => uint16) activeLocksPerDeposit;
// ***** ESTA PARTE É A MAIS CRÍTICA VISTO QUE É NECESSÁRIO FORMAS DE TRAVAR DEPOSITOS *****
// ************ PORÉM SEM A NECESSIDADE DE PERCORRER GRANDES ARRAYS ************************
mapping(bytes32 => Lock) mapLocks; mapping(bytes32 => Lock) mapLocks;
// List of Pix transactions already signed
mapping(bytes32 => bool) usedTransactions; mapping(bytes32 => bool) usedTransactions;
modifier onlySeller(bytes32 depositID) { modifier onlySeller(bytes32 depositID) {
@ -68,6 +66,12 @@ contract P2PIX {
emit DepositAdded(msg.sender, depositID, token, amount); emit DepositAdded(msg.sender, depositID, token, amount);
} }
// Vendedor pode invalidar da ordem de venda impedindo novos locks na mesma (isso não afeta nenhum lock que esteja ativo).
function cancelDeposit(bytes32 depositID) public onlySeller(depositID) {
mapDeposits[depositID].valid = false;
emit DepositClosed(mapDeposits[depositID].seller, depositID);
}
// Relayer interaje adicionando um lock na ordem de venda. // Relayer interaje adicionando um lock na ordem de venda.
// O lock precisa incluir address do comprador + address do relayer + reembolso/premio relayer + valor. // O lock precisa incluir address do comprador + address do relayer + reembolso/premio relayer + valor.
// ** poder ter um lock em aberto para cada (ordem de venda, valor)**. // ** poder ter um lock em aberto para cada (ordem de venda, valor)**.
@ -79,8 +83,10 @@ contract P2PIX {
address targetAddress, address targetAddress,
address relayerAddress, address relayerAddress,
uint256 relayerPremium, uint256 relayerPremium,
uint256 amount uint256 amount,
bytes32[] calldata expiredLocks
) public returns (bytes32 lockID){ ) public returns (bytes32 lockID){
unlockExpired(expiredLocks);
Deposit storage d = mapDeposits[depositID]; Deposit storage d = mapDeposits[depositID];
require(d.valid, "P2PIX: Deposit not valid anymore"); require(d.valid, "P2PIX: Deposit not valid anymore");
require(d.remaining > amount, "P2PIX: Not enough remaining"); require(d.remaining > amount, "P2PIX: Not enough remaining");
@ -89,12 +95,17 @@ contract P2PIX {
mapLocks[lockID].expirationBlock < block.number, mapLocks[lockID].expirationBlock < block.number,
"P2PIX: Another lock with same ID is not expired yet" "P2PIX: Another lock with same ID is not expired yet"
); );
Lock memory l = Lock(depositID, targetAddress, relayerAddress, relayerPremium, amount, block.number+defaultLockBlocks, false); Lock memory l = Lock(
depositID,
targetAddress,
relayerAddress,
relayerPremium,
amount,
block.number+defaultLockBlocks
);
mapLocks[lockID] = l; mapLocks[lockID] = l;
activeDepositLocks[depositID][activeLocksPerDeposit[depositID]] = lockID;
activeLocksPerDeposit[depositID]++;
d.remaining -= amount; d.remaining -= amount;
emit LockAdded(targetAddress, lockID, amount); emit LockAdded(targetAddress, lockID, depositID, amount);
} }
// Relayer interage com o smart contract, colocando no calldata o comprovante do PIX realizado. // Relayer interage com o smart contract, colocando no calldata o comprovante do PIX realizado.
@ -117,40 +128,32 @@ contract P2PIX {
require(!usedTransactions[message], "Transaction already used to unlock payment."); require(!usedTransactions[message], "Transaction already used to unlock payment.");
address signer = ecrecover(message, v, r, s); address signer = ecrecover(message, v, r, s);
require(validBacenSigners[signer], "Signer is not a valid signer."); require(validBacenSigners[signer], "Signer is not a valid signer.");
// TODO Transfer token to target // TODO Transfer token to l.target
l.paid = true; // TODO Transfer relayer fees to relayer
l.amount = 0;
usedTransactions[message] = true; usedTransactions[message] = true;
activeLocksPerDeposit[l.depositID] = unlockExpired(l.depositID);
emit LockReleased(l.targetAddress, lockID); emit LockReleased(l.targetAddress, lockID);
} }
// Unlock expired locks // Unlock expired locks
function unlockExpired(bytes32 depositID) internal returns(uint16 locksLength){ function unlockExpired(bytes32[] calldata lockIDs) internal {
bytes32[] storage locks = activeDepositLocks[depositID]; uint256 locksSize = lockIDs.length;
uint16 locksPreviousLength = activeLocksPerDeposit[depositID]; for (uint16 i = 0; i < locksSize; i++){
locksLength = 0; Lock storage l = mapLocks[lockIDs[i]];
for (uint16 i = 0; i < locksPreviousLength; i++){ require(l.expirationBlock < block.number && l.amount > 0, "P2PIX: Lock not expired or already paid");
Lock memory l = mapLocks[locks[i]]; mapDeposits[l.depositID].remaining += l.amount;
if (l.expirationBlock > block.number && !l.paid) { l.amount = 0;
locks[locksLength] = locks[i]; emit LockReturned(l.targetAddress, lockIDs[i]);
locksLength++;
} else if (l.expirationBlock < block.number && !l.paid) {
mapDeposits[depositID].remaining += l.amount;
}
} }
return locksLength;
}
// Vendedor pode invalidar da ordem de venda impedindo novos locks na mesma (isso não afeta nenhum lock que esteja ativo).
function cancelDeposit(bytes32 depositID) public onlySeller(depositID) {
mapDeposits[depositID].valid = false;
emit DepositClosed(mapDeposits[depositID].seller, depositID);
} }
// Após os locks expirarem, vendedor pode interagir c/ o contrato e recuperar os tokens de um depósito específico. // Após os locks expirarem, vendedor pode interagir c/ o contrato e recuperar os tokens de um depósito específico.
function withdraw(bytes32 depositID) public onlySeller(depositID) { function withdraw(
// Unlock expired locks at depositID bytes32 depositID,
unlockExpired(depositID); bytes32[] calldata expiredLocks
) public onlySeller(depositID) {
unlockExpired(expiredLocks);
if (mapDeposits[depositID].valid) cancelDeposit(depositID);
// TODO Transfer remaining tokens back to the seller // TODO Transfer remaining tokens back to the seller
// Withdraw remaining tokens from mapDeposit[depositID] // Withdraw remaining tokens from mapDeposit[depositID]
uint256 amount = mapDeposits[depositID].remaining; uint256 amount = mapDeposits[depositID].remaining;

View File

@ -63,7 +63,7 @@ describe("P2PIX deposit test", function () {
}) })
it("Should allow withdraw the deposit", async function () { it("Should allow withdraw the deposit", async function () {
const transaction = await p2pix.withdraw(depositID); const transaction = await p2pix.withdraw(depositID, []);
await expect(transaction).to.emit(p2pix, 'DepositWithdrawn').withArgs( await expect(transaction).to.emit(p2pix, 'DepositWithdrawn').withArgs(
owner.address, owner.address,
depositID, depositID,