Skip to content

Commit

Permalink
test: Add integration test for refund from failed FT deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
jbencin committed Apr 10, 2023
1 parent 08f59c1 commit d09d49e
Show file tree
Hide file tree
Showing 3 changed files with 620 additions and 37 deletions.
61 changes: 61 additions & 0 deletions core-contracts/contracts/helper/simple-ft-l2-no-deposit.clar
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(define-constant ERR_NOT_AUTHORIZED (err u1001))

(impl-trait 'ST000000000000000000002AMW42H.subnet.ft-trait)

(define-fungible-token ft-token)

;; get the token balance of owner
(define-read-only (get-balance (owner principal))
(ok (ft-get-balance ft-token owner)))

;; returns the total number of tokens
(define-read-only (get-total-supply)
(ok (ft-get-supply ft-token)))

;; returns the token name
(define-read-only (get-name)
(ok "ft-token"))

;; the symbol or "ticker" for this token
(define-read-only (get-symbol)
(ok "EXFT"))

;; the number of decimals used
(define-read-only (get-decimals)
(ok u0))

;; Transfers tokens to a recipient
(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
(begin
(asserts! (is-eq tx-sender sender) ERR_NOT_AUTHORIZED)
(try! (ft-transfer? ft-token amount sender recipient))
(print memo)
(ok true)
)
)

(define-read-only (get-token-uri)
(ok none)
)

(define-public (gift-tokens (amount uint) (recipient principal))
(begin
(asserts! (is-eq tx-sender recipient) ERR_NOT_AUTHORIZED)
(ft-mint? ft-token amount recipient)
)
)

(impl-trait 'ST000000000000000000002AMW42H.subnet.subnet-asset)

;; Called for deposit from the burnchain to the subnet
(define-public (deposit-from-burnchain (amount uint) (recipient principal))
ERR_NOT_AUTHORIZED
)

;; Called for withdrawal from the subnet to the burnchain
(define-public (burn-for-withdrawal (amount uint) (owner principal))
(begin
(asserts! (is-eq tx-sender owner) ERR_NOT_AUTHORIZED)
(ft-burn? ft-token amount owner)
)
)
91 changes: 56 additions & 35 deletions src/chainstate/stacks/db/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,31 +762,29 @@ fn make_withdrawal_event(
token: Token,
mainnet: bool,
) -> StacksTransactionEvent {
let (withdrawal_type, mut values) = match token {
Token::Nft { id } => ("nft", vec![("id".into(), Value::UInt(id))]),
Token::Ft { amount } => ("ft", vec![("amount".into(), Value::UInt(amount))]),
let (withdrawal_type, withdrawal_value) = match token {
Token::Nft { id } => ("nft", ("id".into(), Value::UInt(id))),
Token::Ft { amount } => ("ft", ("amount".into(), Value::UInt(amount))),
};

values.extend(
vec![
(
"event".into(),
Value::string_ascii_from_bytes("withdraw".into())
.expect("Supplied string was not ASCII"),
),
(
"type".into(),
Value::string_ascii_from_bytes(withdrawal_type.into())
.expect("Supplied string was not ASCII"),
),
("sender".into(), Value::Principal(sender)),
(
"asset-contract".into(),
Value::Principal(PrincipalData::Contract(subnet_contract_id)),
),
]
.into_iter(),
);
let values = vec![
("sender".into(), Value::Principal(sender)),
(
"event".into(),
Value::string_ascii_from_bytes("withdraw".into())
.expect("Supplied string was not ASCII"),
),
(
"type".into(),
Value::string_ascii_from_bytes(withdrawal_type.into())
.expect("Supplied string was not ASCII"),
),
(
"asset-contract".into(),
Value::Principal(PrincipalData::Contract(subnet_contract_id)),
),
withdrawal_value,
];

StacksTransactionEvent::SmartContractEvent(SmartContractEventData {
key: (boot_code_id("subnet", mainnet), "print".into()),
Expand Down Expand Up @@ -4722,7 +4720,7 @@ impl StacksChainState {
None,
&subnet_contract_id,
DEPOSIT_FUNCTION_NAME,
&[Value::UInt(amount), Value::Principal(sender)],
&[Value::UInt(amount), Value::Principal(sender.clone())],
|_, _| false,
)
});
Expand All @@ -4732,17 +4730,40 @@ impl StacksChainState {
.expect("BUG: cost declined between executions");

match result {
Ok((value, _, events)) => Some(StacksTransactionReceipt {
transaction: TransactionOrigin::Burn(deposit_ft_op.into()),
events,
result: value,
post_condition_aborted: false,
stx_burned: 0,
contract_analysis: None,
execution_cost,
microblock_header: None,
tx_index: 0,
}),
Ok((value, _, mut events)) => {
// Examine response to see if transaction failed
let deposit_op_failed = match &value {
Value::Response(r) => r.committed == false,
_ => {
// TODO: Do anything for the case where `value` is not of type `Value::Response()`?
warn!("DepositFt op returned unexpected value"; "value" => %value);
false
}
};

// If deposit fails, create a withdrawal event to send NFT back to user
if deposit_op_failed {
info!("DepositFt op failed. Issue withdrawal tx");
events.push(make_withdrawal_event(
subnet_contract_id,
sender,
Token::Ft { amount },
mainnet,
));
};

Some(StacksTransactionReceipt {
transaction: TransactionOrigin::Burn(deposit_ft_op.into()),
events,
result: value,
post_condition_aborted: false,
stx_burned: 0,
contract_analysis: None,
execution_cost,
microblock_header: None,
tx_index: 0,
})
}
Err(e) => {
info!("DepositFt op processing error.";
"error" => ?e,
Expand Down
Loading

0 comments on commit d09d49e

Please sign in to comment.