Skip to content

Commit

Permalink
Merge pull request #322 from joe-p/fix/arc59_receiverAlgoNeededForClaim
Browse files Browse the repository at this point in the history
ARC59 feedback based on beta testing
  • Loading branch information
SudoWeezy authored Nov 22, 2024
2 parents b4ac7ef + 671a7ed commit f7e4476
Show file tree
Hide file tree
Showing 19 changed files with 5,204 additions and 3,635 deletions.
69 changes: 65 additions & 4 deletions assets/arc-0059/__test__/arc59.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import algosdk from 'algosdk';
import { Arc59Client } from '../contracts/clients/Arc59Client';

const fixture = algorandFixture();
algokit.Config.configure({ populateAppCallResources: true });
algokit.Config.configure({
populateAppCallResources: true,
// eslint-disable-next-line no-console
logger: { error: () => console.error, debug: () => {}, warn: console.warn, info: () => {}, verbose: () => {} },
});

/**
* Send an asset to a receiver using the ARC59 router
Expand All @@ -15,7 +19,6 @@ algokit.Config.configure({ populateAppCallResources: true });
* @param sender The address of the sender
* @param receiver The address of the receiver
* @param algorand The AlgorandClient instance to use to send transactions
* @param sendAlgoForNewAccount Whether to send 201_000 uALGO to the receiver so they can claim the asset with a 0-ALGO balance
*/
async function arc59SendAsset(
appClient: Arc59Client,
Expand Down Expand Up @@ -210,11 +213,21 @@ describe('Arc59', () => {
test('Brand new account getSendAssetInfo', async () => {
const res = await appClient.arc59GetSendAssetInfo({ asset: assetOne, receiver: algosdk.generateAccount().addr });

const itxns = res.return![0];
const mbr = res.return![1];
const [
itxns,
mbr,
routerOptedIn,
receiverOptedIn,
receiverAlgoNeededForClaim,
receiverAlgoNeededForWorstCaseClaim,
] = res.return!;

expect(itxns).toBe(5n);
expect(mbr).toBe(228_100n);
expect(routerOptedIn).toBe(true);
expect(receiverOptedIn).toBe(false);
expect(receiverAlgoNeededForClaim).toBe(201_000n);
expect(receiverAlgoNeededForWorstCaseClaim).toBe(201_000n);
});

test('Brand new account sendAsset', async () => {
Expand Down Expand Up @@ -269,4 +282,52 @@ describe('Arc59', () => {

expect(receiverAssetInfo.balance).toBe(1n);
});

test('two claims from 0-ALGO account', async () => {
const { algorand } = fixture;
const receiver = algorand.account.random();
await arc59SendAsset(appClient, assetOne, alice.addr, receiver.addr, algorand);
await arc59SendAsset(appClient, assetTwo, alice.addr, receiver.addr, algorand);

await arc59Claim(appClient, assetOne, receiver.addr, algorand);
await arc59Claim(appClient, assetTwo, receiver.addr, algorand);

const receiverAssetInfoOne = await algorand.account.getAssetInformation(receiver.addr, assetOne);
const receiverAssetInfoTwo = await algorand.account.getAssetInformation(receiver.addr, assetTwo);

expect(receiverAssetInfoOne.balance).toBe(1n);
expect(receiverAssetInfoTwo.balance).toBe(1n);
});

test('claim from abnormal ALGO balance', async () => {
const { algorand } = fixture;
const receiver = algorand.account.random();

await algorand.send.payment({ sender: alice.addr, receiver: receiver.addr, amount: algokit.microAlgos(123_456) });

await arc59SendAsset(appClient, assetOne, alice.addr, receiver.addr, algorand);
await arc59Claim(appClient, assetOne, receiver.addr, algorand);

const receiverAssetInfo = await algorand.account.getAssetInformation(receiver.addr, assetOne);

expect(receiverAssetInfo.balance).toBe(1n);
});

test('arc59GetSendAssetInfo with small amount of ALGO in inbox', async () => {
const { algorand } = fixture;
const receiver = algorand.account.random();

await arc59SendAsset(appClient, assetOne, alice.addr, receiver.addr, algorand);
await arc59Claim(appClient, assetOne, receiver.addr, algorand);

const inbox = (await appClient.arc59GetInbox({ receiver: receiver.addr })).return!;

await algorand.send.payment({
sender: alice.addr,
receiver: inbox,
amount: algokit.microAlgos(1),
});

await appClient.arc59GetSendAssetInfo({ asset: assetTwo, receiver: receiver.addr });
});
});
34 changes: 26 additions & 8 deletions assets/arc-0059/contracts/arc59.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type SendAssetInfo = {
receiverOptedIn: boolean;
/** The amount of ALGO the receiver would currently need to claim the asset */
receiverAlgoNeededForClaim: uint64;
/** The amount of ALGO the receiver would need if their balance dropped to 0 */
receiverAlgoNeededForWorstCaseClaim: uint64;
};

class ControlledAddress extends Contract {
Expand Down Expand Up @@ -90,6 +92,7 @@ export class ARC59 extends Contract {
routerOptedIn: routerOptedIn,
receiverOptedIn: receiverOptedIn,
receiverAlgoNeededForClaim: 0,
receiverAlgoNeededForWorstCaseClaim: globals.minBalance + globals.assetOptInMinBalance + globals.minTxnFee,
};

if (receiverOptedIn) return info;
Expand All @@ -98,7 +101,7 @@ export class ARC59 extends Contract {

// Determine how much ALGO the receiver needs to claim the asset
if (receiver.balance < algoNeededToClaim) {
info.receiverAlgoNeededForClaim += algoNeededToClaim - receiver.balance;
info.receiverAlgoNeededForClaim = algoNeededToClaim - receiver.balance;
}

// Add mbr and transaction for opting the router in
Expand Down Expand Up @@ -140,6 +143,21 @@ export class ARC59 extends Contract {
}
}

// If the inbox has extra ALGO, we need to account for that extra ALGO but also account for how much is used to claim the asset
if (inbox.balance > inbox.minBalance && info.receiverAlgoNeededForClaim !== 0) {
/**
* The total amount of ALGO needed up-front by the account when they claim the asset
* Add 1 txn for the upfront opt-in, 1 txn for the claim, 2 txns for the ALGO claim
*/
const algoConsumedByClaim = globals.assetOptInMinBalance + (info.itxns + 4) * globals.minTxnFee;
let inboxAlgoAvailable = inbox.balance > inbox.minBalance ? inbox.balance - inbox.minBalance : 0;
inboxAlgoAvailable = inboxAlgoAvailable > algoConsumedByClaim ? inboxAlgoAvailable - algoConsumedByClaim : 0;

if (inboxAlgoAvailable < info.receiverAlgoNeededForClaim) {
info.receiverAlgoNeededForClaim -= inboxAlgoAvailable;
}
}

return info;
}

Expand Down Expand Up @@ -178,13 +196,6 @@ export class ARC59 extends Contract {
const inboxExisted = this.inboxes(receiver).exists;
const inbox = this.arc59_getOrCreateInbox(receiver);

if (additionalReceiverFunds !== 0) {
sendPayment({
receiver: inbox,
amount: additionalReceiverFunds,
});
}

if (!inbox.isOptedInToAsset(axfer.xferAsset)) {
let inboxMbrDelta = globals.assetOptInMinBalance;
if (!inboxExisted) inboxMbrDelta += globals.minBalance;
Expand Down Expand Up @@ -213,6 +224,13 @@ export class ARC59 extends Contract {
xferAsset: axfer.xferAsset,
});

if (additionalReceiverFunds !== 0) {
sendPayment({
receiver: inbox,
amount: additionalReceiverFunds,
});
}

return inbox;
}

Expand Down
Loading

0 comments on commit f7e4476

Please sign in to comment.