Appearance
Withdraw a refund
The exact contract function is:
solidity
withdrawRefund(uint256 submissionId)After finalization, an eligible author of a non-winning submission may withdraw the refundable CLAY belonging to that submission. The winning submission cannot withdraw its settled bid.
Before calling withdrawRefund:
- read the submission and its auction;
- confirm that finalization has completed;
- confirm the connected account is the submission author;
- read canonical refund eligibility; and
- simulate the withdrawal.
Example: check eligibility and withdraw
ts
const refund = await withdrawRefund(41n);ts
import {
encodeFunctionData,
getAddress,
parseEventLogs,
type Hash,
} from "viem";
import { tabletsAbi } from "@tablets/abi";
import {
TABLETS_ADDRESS,
assertPin,
getActiveAccount,
invariant,
only,
pinLatestBlock,
publicClient,
waitForExactTransaction,
walletClient,
} from "./tablets-client.js";
export type WithdrawnRefund = {
readonly transactionHash: Hash;
readonly blockNumber: bigint;
readonly auctionId: bigint;
readonly submissionId: bigint;
readonly amount: bigint;
};
export async function withdrawRefund(
submissionId: bigint,
): Promise<WithdrawnRefund> {
invariant(submissionId > 0n, "submissionId must be positive");
const account = await getActiveAccount();
const pin = await pinLatestBlock();
const submission = await publicClient.readContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "getSubmission",
args: [submissionId],
blockNumber: pin.number,
});
const [auction, refundable] = await Promise.all([
publicClient.readContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "getAuction",
args: [submission.auctionId],
blockNumber: pin.number,
}),
publicClient.readContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "isRefundable",
args: [submissionId],
blockNumber: pin.number,
}),
]);
invariant(
getAddress(submission.submitter) === account &&
auction.finalized &&
auction.winnerSubmissionId !== submissionId &&
!submission.refundWithdrawn &&
refundable,
"Caller is not canonically eligible for this refund",
);
const { request } = await publicClient.simulateContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "withdrawRefund",
args: [submissionId],
account,
blockNumber: pin.number,
});
await assertPin(pin);
const input = encodeFunctionData({
abi: tabletsAbi,
functionName: "withdrawRefund",
args: [submissionId],
});
const transactionHash = await walletClient.writeContract(request);
const receipt = await waitForExactTransaction(transactionHash, {
account,
to: TABLETS_ADDRESS,
input,
});
const withdrawn = only(
parseEventLogs({
abi: tabletsAbi,
eventName: "RefundWithdrawn",
logs: receipt.logs.filter(
(log) => getAddress(log.address) === TABLETS_ADDRESS,
),
strict: true,
}),
"RefundWithdrawn event",
);
invariant(
withdrawn.args.auctionId === submission.auctionId &&
withdrawn.args.submissionId === submissionId &&
getAddress(withdrawn.args.submitter) === account &&
withdrawn.args.amount === submission.bidAmount,
"RefundWithdrawn event mismatch",
);
const [stored, stillRefundable] = await Promise.all([
publicClient.readContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "getSubmission",
args: [submissionId],
blockNumber: receipt.blockNumber,
}),
publicClient.readContract({
address: TABLETS_ADDRESS,
abi: tabletsAbi,
functionName: "isRefundable",
args: [submissionId],
blockNumber: receipt.blockNumber,
}),
]);
invariant(
stored.refundWithdrawn && !stillRefundable,
"Receipt-pinned refund state mismatch",
);
return {
transactionHash,
blockNumber: receipt.blockNumber,
auctionId: withdrawn.args.auctionId,
submissionId,
amount: withdrawn.args.amount,
};
}After confirmation, decode RefundWithdrawn. Do not infer success from a transaction hash alone.