Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tlin_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ jobs:
- name: checkout code
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0

- name: checkout tlin
uses: actions/checkout@v4
Expand Down
37 changes: 20 additions & 17 deletions contract/r/gnoswap/v1/pool/pool.gno
Original file line number Diff line number Diff line change
Expand Up @@ -327,23 +327,26 @@ func collectProtocol(
amount0 := u256Min(amount0Req, pool.ProtocolFeesToken0())
amount1 := u256Min(amount1Req, pool.ProtocolFeesToken1())

amount0, amount1 = pool.saveProtocolFees(amount0.Clone(), amount1.Clone())
uAmount0 := safeConvertToInt64(amount0)
uAmount1 := safeConvertToInt64(amount1)

common.SafeGRC20Transfer(cross, pool.token0Path, recipient, uAmount0)
newBalanceToken0, err := updatePoolBalance(pool.BalanceToken0(), pool.BalanceToken1(), amount0, true)
if err != nil {
panic(err)
}
pool.balances.token0 = newBalanceToken0

common.SafeGRC20Transfer(cross, pool.token1Path, recipient, uAmount1)
newBalanceToken1, err := updatePoolBalance(pool.BalanceToken0(), pool.BalanceToken1(), amount1, false)
if err != nil {
panic(err)
}
pool.balances.token1 = newBalanceToken1
amount0, amount1 = pool.saveProtocolFees(amount0.Clone(), amount1.Clone())

// Effects: update internal pool balances first
newBalanceToken0, err := updatePoolBalance(pool.BalanceToken0(), pool.BalanceToken1(), amount0, true)
if err != nil {
panic(err)
}
pool.balances.token0 = newBalanceToken0

newBalanceToken1, err := updatePoolBalance(pool.BalanceToken0(), pool.BalanceToken1(), amount1, false)
if err != nil {
panic(err)
}
pool.balances.token1 = newBalanceToken1

// Interactions: then perform external transfers
uAmount0 := safeConvertToInt64(amount0)
uAmount1 := safeConvertToInt64(amount1)
common.SafeGRC20Transfer(cross, pool.token0Path, recipient, uAmount0)
common.SafeGRC20Transfer(cross, pool.token1Path, recipient, uAmount1)

return amount0.ToString(), amount1.ToString()
}
Expand Down
117 changes: 60 additions & 57 deletions contract/r/gnoswap/v1/pool/transfer.gno
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,29 @@ func (p *Pool) safeTransfer(
))
}

absAmount := amount.Abs()

token0 := p.BalanceToken0()
token1 := p.BalanceToken1()

if err := validatePoolBalance(token0, token1, absAmount, isToken0); err != nil {
panic(err)
}
amountInt64 := safeConvertToInt64(absAmount)

common.SafeGRC20Transfer(cross, tokenPath, to, amountInt64)

newBalance, err := updatePoolBalance(token0, token1, absAmount, isToken0)
if err != nil {
panic(err)
}

if isToken0 {
p.balances.token0 = newBalance
} else {
p.balances.token1 = newBalance
}
absAmount := amount.Abs()

token0 := p.BalanceToken0()
token1 := p.BalanceToken1()

if err := validatePoolBalance(token0, token1, absAmount, isToken0); err != nil {
panic(err)
}

// Effects: compute and apply new internal balance first
newBalance, err := updatePoolBalance(token0, token1, absAmount, isToken0)
if err != nil {
panic(err)
}
if isToken0 {
p.balances.token0 = newBalance
} else {
p.balances.token1 = newBalance
}

// Interactions: perform external transfer after state change
amountInt64 := safeConvertToInt64(absAmount)
common.SafeGRC20Transfer(cross, tokenPath, to, amountInt64)
}

// safeTransferFrom securely transfers tokens into the pool while ensuring balance consistency.
Expand Down Expand Up @@ -107,41 +108,43 @@ func (p *Pool) safeTransferFrom(
amount *u256.Uint,
isToken0 bool,
) {
amountInt64 := safeConvertToInt64(amount)

token := common.GetToken(tokenPath)
beforeBalance := token.BalanceOf(to)

common.SafeGRC20TransferFrom(cross, tokenPath, from, to, amountInt64)

afterBalance := token.BalanceOf(to)
if (beforeBalance + amountInt64) != afterBalance {
panic(ufmt.Sprintf(
"%v. beforeBalance(%d) + amount(%d) != afterBalance(%d)",
errTransferFailed, beforeBalance, amountInt64, afterBalance,
))
}

// update pool balances
if isToken0 {
beforeToken0 := p.balances.token0.Clone()
p.balances.token0 = u256.Zero().Add(p.balances.token0, amount)
if p.balances.token0.Lt(beforeToken0) {
panic(ufmt.Sprintf(
"%v. token0(%s) < beforeToken0(%s)",
errBalanceUpdateFailed, p.balances.token0.ToString(), beforeToken0.ToString(),
))
}
} else {
beforeToken1 := p.balances.token1.Clone()
p.balances.token1 = u256.Zero().Add(p.balances.token1, amount)
if p.balances.token1.Lt(beforeToken1) {
panic(ufmt.Sprintf(
"%v. token1(%s) < beforeToken1(%s)",
errBalanceUpdateFailed, p.balances.token1.ToString(), beforeToken1.ToString(),
))
}
}
amountInt64 := safeConvertToInt64(amount)

token := common.GetToken(tokenPath)
beforeBalance := token.BalanceOf(to)

// Effects: update internal balances before interaction
if isToken0 {
beforeToken0 := p.balances.token0.Clone()
p.balances.token0 = u256.Zero().Add(p.balances.token0, amount)
if p.balances.token0.Lt(beforeToken0) {
panic(ufmt.Sprintf(
"%v. token0(%s) < beforeToken0(%s)",
errBalanceUpdateFailed, p.balances.token0.ToString(), beforeToken0.ToString(),
))
}
} else {
beforeToken1 := p.balances.token1.Clone()
p.balances.token1 = u256.Zero().Add(p.balances.token1, amount)
if p.balances.token1.Lt(beforeToken1) {
panic(ufmt.Sprintf(
"%v. token1(%s) < beforeToken1(%s)",
errBalanceUpdateFailed, p.balances.token1.ToString(), beforeToken1.ToString(),
))
}
}

// Interactions: perform external transfer after state change
common.SafeGRC20TransferFrom(cross, tokenPath, from, to, amountInt64)

// Post-condition: verify external balance reflects the transfer
afterBalance := token.BalanceOf(to)
if (beforeBalance + amountInt64) != afterBalance {
panic(ufmt.Sprintf(
"%v. beforeBalance(%d) + amount(%d) != afterBalance(%d)",
errTransferFailed, beforeBalance, amountInt64, afterBalance,
))
}
}

// safeSwapCallback validates the balance of the token path with the swap callback.
Expand Down
Loading