Escrow
The escrow mechanism is designed to discourage users from behaving in a way that negatively affects other users. It serves the same purpose as cancellation fees on centralized platforms.
Last updated
The escrow mechanism is designed to discourage users from behaving in a way that negatively affects other users. It serves the same purpose as cancellation fees on centralized platforms.
Last updated
The escrow mechanism is a crucial component of the nRide protocol that ensures trust and security for both riders and drivers. By locking funds in escrow until the pickup is completed, the mechanism mitigates the risk of a late cancellation or no-show. This creates a level playing field for riders and drivers and incentivizes them to fulfill their respective obligations. In the following section, we will describe the workings of the escrow mechanism in detail, including the different stages of the process and the various outputs that can result from its operation.
The escrow smart-contract allows multiple users to create independent escrows. Each escrow involves two users and has a unique id (for future calls to reference it) as well as other parameters that guard the state transitions that are involved in the lifecycle of the escrow.
Each escrow is composed of two accounts, each guarded by what we call a secret. Once an escrow is funded by both parties, a user must obtain the other user’s secret to unlock all of their deposit, otherwise they will lose a portion of it. In effect, the secret is simply the private component of a cryptographic key pair created for the purpose of the escrow. When a user funds their account in the escrow, they create a new key pair locally, and set the new public key as the ‘lock’ of their account in the escrow. The other user will need to obtain the private key - the secret - to unlock their deposit. Users exchange secrets offline, and the procedure for doing so is not covered by the protocol (could be by tapping phones through NFC, or by sending a message over the NKN network). The escrow smart-contract implements a state machine that guards all possible transitions and outputs given initial configuration and the messages submitted by the users.
How it works:
Both parties, A and B, lock the same amount of tokens in the smart contract. Once the funds are locked, each party can send one of two messages to the smart contract:
Approve(secret) - A message containing the counterparty’s secret.
Cancel - A message signifying the user’s desire to redeem a proportion of their deposit prior to completion, or because they failed to obtain the other user’s secret.
Additionally, the escrow smart contract is configured with two timeouts:
T1: After the first deposit is paid into the escrow account, party B has T1 time to send their deposit, after which party A will get their deposit back. T1 is left to the discretion of the first party to create and instantiate the contract. However, T1 is intended to be relatively short, only a few minutes after the agreement is initially formed and the first party engages with the contract (i.e. sending tokens to the contract).
T2: T2 is a longer timeout that triggers a default action in case either of the parties fails to submit a message to the smart contract after both deposits have been paid. T2 is intended to cover the time it would take to complete the pickup and is left to the discretion of the first party that creates the escrow.
The following table contains the 16 possible end states of an escrow:
Approve(B,secret_a) | Cancel(B) | T1(B) | T2(B) | |
---|---|---|---|---|
Approve(A, secret_b) | (1, 1) | (1.3, 0.7) | X | (1.5, 0.5) |
Cancel(A) | (0.7, 1.3) | (0.5, 0.5) | (1, 0) | (0.5, 0) |
T1(A) | X | (0, 1) | X | (0, 1) |
T2(A) | (0.5, 1.5) | (0, 0.5) | (1,0) | (0, 0) |
In this table, the columns represent the four possible actions that can be taken by party B, while the rows represent the four possible actions that can be taken by party A. Each cell in the table represents the outcome of the escrow mechanism for the combination of actions taken by both parties.
The table lists the coefficients that determine how much of the escrow funds each party receives in each possible outcome. For example, if both parties approve the transaction and exchange secrets, they both receive the same amount of funds they originally deposited (1, 1). If one party cancels and the other approves using the cancelling party's secret, the approving party receives 1.3 times their original deposit, while the cancelling party receives 0.7 times their original deposit (1.3, 0.7). If both parties cancel, they both receive 0.5 times their original deposit, and the remaining funds go to the protocol treasury (0.5, 0.5). Finally, if both parties fail to take any action after both deposits have been paid, both parties lose their deposits, and the funds go to the treasury (0, 0).
Here is an explanation of all 16 possible outputs of the escrow mechanism:
Approve(B, secret_a) & Approve(A, secret_b): Both parties send each other their secrets before T2, resulting in both parties receiving their full deposit back.
Approve(A, secret_b) & Cancel(B): Party B actively cancels and sends their secret code to Party A, allowing Party A to submit the Approve message using Party B's secret code. Party A receives 1.3 times their initial deposit, and Party B receives 0.7 times their initial deposit.
Approve(A, secret_b) & T1(B): Not possible because the smart contract does not allow Party A to approve unless Party B's account is funded.
Approve(A, secret_b) & T2(B): Party B sends their secret code to Party A, but for some reason, Party B did not cancel or send an Approve message before T2. In this case, Party B is penalized a bit more than if they had actively canceled because they made Party A wait for the expiry of the timeout. Party A receives 1.5 times their initial deposit, and Party B receives 0.5 times their initial deposit.
Cancel(A) & Approve(B, secret_a): Symmetrical to output 2.
Cancel(A) & Cancel(B): Both parties actively cancel, but neither is able to submit the other's secret code. Both parties get penalized the same amount, and funds go to the treasury. Both parties receive 0.5 times their initial deposit.
Cancel(A) & T1(B): Party B never funded their account. After T1, Party A can withdraw their full deposit.
Cancel(A) & T2(B): Party A actively cancels, they never received Party B's secret code, and Party B timed out. This happens when one party is a no-show, and they get penalized completely.
T1(A) & Approve(A, secret_b): Not possible. Symmetrical to output 2.
T1(A) & Cancel(B): Symmetrical to output 7.
T1(A) & T1(B): Not possible. Creating an escrow requires funding the creator's account, so at least one account is funded.
T1(A) & T2(B): Party A never funded their account. Party B can Cancel before T2 to get their funds back, but even if they wait until after T2, they will still get their deposit back.
T2(A) & Approve(B, secret_a): Symmetrical to output 4.
T2(A) & Cancel(B): Symmetrical to output 8.
T2(A) & T1(B): Symmetrical to output 12.
T2(A) & T2(B): Both parties are penalized completely, and funds go to the treasury. Both parties receive 0 times their initial deposit.
How do users receive compensation when their counterparties cancel or fail to fulfill an obligation?
If the counterparty decides to cancel a confirmed commitment, they have two options: actively cancel and provide their secret code to the other user or do nothing. If they choose to provide their secret code, the other user can submit the Approve(secret) message to receive a cancellation fee of 1.3 or 1.5 times their initial deposit, depending on the timing of the cancellation.
The escrow mechanism is designed to encourage the counterparty to disclose their secret code as this allows them to retain a portion of their initial deposit. If they successfully submit the cancel message before T2, they will be able to retain 0.7 of their initial deposit. If they submit the cancel message after T2, they will only be able to retain 0.5 of their initial deposit. By providing an incentive for the counterparty to disclose their secret code, the escrow mechanism helps to ensure that both parties are able to recover at least a portion of their initial deposit in case of a cancellation.
How does the escrow system protect against bots programmed to automatically accept or request pickups without fulfilling commitments?
If a bot accepts or requests pickups automatically without fulfilling its commitments, it will likely be unable to recover its initial deposit from the escrow account. This is because the counterparty will not release the secret code needed to send an “Approve” message, and the bot will forfeit its deposit. Therefore, the escrow mechanism discourages bots from engaging in this type of behavior, as it imposes a financial penalty on parties that do not fulfill their commitments.
What happens when both parties turn up at the pickup point, and one of the users receives the other's secret, but doesn't share their own secret (maliciously or for technical reasons)?
This corresponds to "Approve(A, s_b) AND Cancel(B)", or the symmetrical state, and would result in an unfair loss for the person who shared their secret. The exchange of secrets happens at pickup and in person, in the physical realm, so at that stage, refusing to share one's secret is akin to running away without paying after a regular Taxi ride. nRide users will just have to trust each other not to do that. In the eventuality of a technical problem, the affected party can always ask for offline compensation, or refuse to proceed with the journey.