Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fungible Token Switchboard contract and tests #71

Merged
merged 73 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
dea796a
Switchboard contract skeleton
alilloig May 19, 2022
28aa0f5
Added test node_modules to gitignore
alilloig May 19, 2022
ecd48a2
example token first test
alilloig May 23, 2022
4d0b427
example token mint tokens test
alilloig May 24, 2022
4189f3f
example token transfer tokens test
alilloig May 24, 2022
c0d79b1
burn tokens test, comments and a little bit of code cleanup
alilloig May 24, 2022
49f4cef
add switchboard manager interface, removecapabilty function header
alilloig May 25, 2022
cfc8d15
post conditions and prepare-execute (#68)
joshuahannan May 25, 2022
39aac3e
First uncomented version of contract
alilloig May 26, 2022
d71a7cc
removed SwitchboardManager interface
alilloig May 27, 2022
d454c65
Switchboard resource creation and setup account tx
alilloig May 30, 2022
7a4d9ab
Switchboard tests and folder restruct
alilloig May 30, 2022
6bbfe45
Transfer tokens through switchboard tx
alilloig May 30, 2022
2cb1aff
Packed all test in one file
alilloig May 31, 2022
5239096
Added tx for adding and removing ft vault capabilities to switchboard
alilloig May 31, 2022
ed606ba
Missing receiver public path
alilloig May 31, 2022
4c4d321
Fixed addVaultCapability function, type of capability instead of type…
alilloig Jun 1, 2022
362f727
linking a capability just to a <&{FungibleToken.Receiver> rather than…
alilloig Jun 1, 2022
f14d5b0
Actually linking a Switchboard receiver, but keep borrowing an AnyRes…
alilloig Jun 1, 2022
bd7eba0
fixed test for removing capabilities
alilloig Jun 1, 2022
a510241
Full contract comments, added deposit to SwitchboardPublic interface,…
alilloig Jun 1, 2022
9c2b88a
get vault capabilities script and test for it
alilloig Jun 2, 2022
6237539
Commented properly every transaction
alilloig Jun 2, 2022
cb6fe18
go test passed
alilloig Jun 2, 2022
255e361
Fixed removeVaultCapability function. emit VaultCapabilityAdded and V…
alilloig Jun 2, 2022
12f1e66
Pushed bad flow.json file
alilloig Jun 2, 2022
7b2bd64
Move js test from project root to lib/js
alilloig Jun 3, 2022
946ae3a
Rename path variable names
alilloig Jun 3, 2022
98fa540
Remove FungibleTokenSwitchboardInitialized event
alilloig Jun 3, 2022
04e3fa1
Fix typo in comment
alilloig Jun 3, 2022
2b95ca4
Fix more comment typos
alilloig Jun 3, 2022
0363317
Simplify vault receivers fields and function names
alilloig Jun 3, 2022
3b038f5
Make the receiverCapabilities field from switchboard resource private…
alilloig Jun 3, 2022
c298141
Include js test in makefile
alilloig Jun 6, 2022
ce308bb
Add node and npm modules to github ci
alilloig Jun 6, 2022
57e1d36
Add dependencies lock file to github ci
alilloig Jun 6, 2022
2742f0e
Add script test to package-lock.json
alilloig Jun 6, 2022
f710865
Add npm install to lib/js/test makefile
alilloig Jun 7, 2022
de03067
Add flow cli and npm dependencies to github actions
alilloig Jun 7, 2022
94c97dc
Remove SwitchboardInitialized event
alilloig Jun 7, 2022
d8cd883
Add assertions to balance involved tests
alilloig Jun 7, 2022
5200bb6
Correct test name
alilloig Jun 7, 2022
019447c
Change getVaultCapabilities for getVaultTypes
alilloig Jun 8, 2022
7797090
Add safeDeposit function to switchboard. Add safe_transfer tx and tests
alilloig Jun 9, 2022
66c977f
Add first draft of addNewVaultsByPath function
alilloig Jun 9, 2022
516dbe7
Add test for addVaultCapabilitiesByPath
alilloig Jun 21, 2022
dfa20ef
Add switchboard documentation
alilloig Jun 22, 2022
0e6b558
Make addVault functions not to accept already present vaults
alilloig Jun 22, 2022
f4537be
Update comment
alilloig Jun 23, 2022
c721183
Update comments
alilloig Jun 23, 2022
9a1b39d
Fix merge
alilloig Jun 23, 2022
ae056f5
Add optional owner parameters to vault events
alilloig Jun 23, 2022
7c51627
Update README.md
alilloig Jun 28, 2022
21c6b1f
Update README.md
alilloig Jun 28, 2022
0139ee9
Update README.md
alilloig Jun 28, 2022
b09b92f
Update README.md
alilloig Jun 28, 2022
e4ceede
Update README.md
alilloig Jun 28, 2022
df916c2
Update README.md
alilloig Jun 28, 2022
f678837
Update README.md
alilloig Jun 28, 2022
62c56d4
Merge pull request #74 from onflow/alilloig/switchboard-docs
alilloig Jun 28, 2022
a55ea9e
Make safeDeposit function return an optional Vault
alilloig Jun 29, 2022
3c5e535
Merge branch 'master' into alilloig/switchboard
alilloig Jun 29, 2022
0a23d33
Fix ci
alilloig Jun 29, 2022
0b463aa
Include receiverPath as a parameter for transfer_tokens transaction. …
alilloig Jul 6, 2022
b0a2510
Add NotCompletedDeposit event to safeDeposit function
alilloig Jul 13, 2022
0614d31
Modify getVaultTypes method to return only the types of the capabilit…
alilloig Jul 13, 2022
03db287
Merge master, update flow-js-testing
alilloig Jul 25, 2022
d223673
Merge branch 'master' into alilloig/switchboard
alilloig Jul 27, 2022
3b87f4f
Add review improvements
alilloig Jul 27, 2022
343440a
Merge branch 'alilloig/switchboard' of github.com:onflow/flow-ft into…
alilloig Jul 27, 2022
61b48a2
Merge branch 'master' into alilloig/switchboard
alilloig Aug 16, 2022
3298572
Cleanup
alilloig Aug 18, 2022
93287b1
Polish comments
alilloig Aug 19, 2022
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
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,18 @@ jobs:
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- uses: actions/setup-node@v3
with:
node-version: 14
cache: 'npm'
cache-dependency-path: lib/js/test/package-lock.json
- name: Install Flow CLI
run: sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v0.33.1-sc-m5
- name: Flow cli Version
run: flow version
- name: Update PATH
run: echo "/root/.local/bin" >> $GITHUB_PATH
- name: Install dependencies
run: cd lib/js/test && npm ci
- run: make ci

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea
lib/js/test/node_modules/*
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
test:
$(MAKE) generate -C lib/go
$(MAKE) test -C lib/go
$(MAKE) test -C lib/js/test

.PHONY: ci
ci:
$(MAKE) ci -C lib/go
$(MAKE) ci -C lib/js/test
177 changes: 177 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,183 @@ To use the Flow Token contract as is, you need to follow these steps:
8. Use the `create_minter.cdc` transaction to create a new MintandBurn resource
and store it in a new Admin's account.

# Fungible Token Switchboard

`FungibleTokenSwitchboard.cdc`, allows users to receive payments in different fungible tokens using a single `&{FungibleToken.Receiver}` placed in a standard receiver path `/public/GenericFTReceiver`.

## How to use it

Users willing to use the Fungible Token Switchboard will need to setup their accounts by creating a new `FungibleTokenSwitchboard.Switchboard` resource and saving it to their accounts at the `FungibleTokenSwitchboard.StoragePath` path.

This can be acomplished by executing the transaction found in this repository `transactions/switchboard/setup_account.cdc`. This transaction will create and save a Switchboard resource to the signer's account,
and it also will create the needed public capabilities to access it. After setting up their switchboard, in order to make it support receiving a certain token, users will need to add the desired token's receiver capability to their switchboard resource.

## Adding a new vault to the switchboard
When a user wants to receive a new fungible token through their switchboard, they will need to add a new public capability linked to said FT to their switchboard resource. This can be accomplished in two different ways:

1. Adding a single capability using `addNewVault(capability: Capability<&{FungibleToken.Receiver}>)`
* Before calling this method on a transaction you should first retrieve the capability to the token's vault you are
willing to add to the switchboard, as is done in the template transaction `transactions/switchboard/add_vault_capabilty.cdc`.

```cadence
transaction {
let exampleTokenVaultCapabilty: Capability<&{FungibleToken.Receiver}>
let switchboardRef: &FungibleTokenSwitchboard.Switchboard

prepare(signer: AuthAccount) {
// Get the example token vault capability from the signer's account
self.exampleTokenVaultCapabilty =
signer.getCapability<&{FungibleToken.Receiver}>
(ExampleToken.ReceiverPublicPath)
// Get a reference to the signers switchboard
self.switchboardRef = signer.borrow<&FungibleTokenSwitchboard.Switchboard>
(from: FungibleTokenSwitchboard.StoragePath)
?? panic("Could not borrow reference to switchboard")
}

execute {
// Add the capability to the switchboard using addNewVault method
self.switchboardRef.addNewVault(capability: self.exampleTokenVaultCapabilty)
}
}
```
This function will panic if is not possible to `.borrow()` a reference to a `&{FungibleToken.Receiver}` from the passed capability. It will also panic if there is already a capability stored for the same `Type` of resource exposed by the capability.

2. Adding one or more capabilities using the paths where they are stored using `addNewVaultsByPath(paths: [PublicPath], address: Address)`
* When using this method, an array of `PublicPath` objects should be passed along with the `Address` of the account from where the vaults' capabilities should be retrieved.

```cadence
transaction (address: Address) {

let exampleTokenVaultPath: PublicPath
let vaultPaths: [PublicPath]
let switchboardRef: &FungibleTokenSwitchboard.Switchboard

prepare(signer: AuthAccount) {
// Get the example token vault path from the contract
self.exampleTokenVaultPath = ExampleToken.ReceiverPublicPath
// And store it in the array of public paths that will be passed to the
// switchboard method
self.vaultPaths = []
self.vaultPaths.append(self.exampleTokenVaultPath)
// Get a reference to the signers switchboard
self.switchboardRef = signer.borrow<&FungibleTokenSwitchboard.Switchboard>
(from: FungibleTokenSwitchboard.StoragePath)
?? panic("Could not borrow reference to switchboard")
}

execute {
// Add the capability to the switchboard using addNewVault method
self.switchboardRef.addNewVaultsByPath(paths: self.vaultPaths,
address: address)
}
}
```
This function won't panic, instead it will just not add to the `@Switchboard` any capability which can not be retrieved from any of the provided `PublicPath`s. It will also ignore any type of `&{FungibleToken.Receiver}` that is already present on the `@Switchboard`

## Removing a vault from the switchboard
If a user no longer wants to be able to receive deposits from a certain FT, or if they want to update the provided capability for one of them, they will need to remove the vault from the switchboard.
This can be accomplished by using `removeVault(capability: Capability<&{FungibleToken.Receiver}>)`.
This can be observed in the template transaction `transactions/switchboard/remove_vault_capability.cdc`:
```cadence
transaction {
let exampleTokenVaultCapabilty: Capability<&{FungibleToken.Receiver}>
let switchboardRef: &FungibleTokenSwitchboard.Switchboard

prepare(signer: AuthAccount) {
// Get the example token vault capability from the signer's account
self.exampleTokenVaultCapabilty = signer.getCapability
<&{FungibleToken.Receiver}>(ExampleToken.ReceiverPublicPath)
// Get a reference to the signers switchboard
self.switchboardRef = signer.borrow<&FungibleTokenSwitchboard.Switchboard>
(from: FungibleTokenSwitchboard.StoragePath)
?? panic("Could not borrow reference to switchboard")

}

execute {
// Remove the capability from the switchboard using the
// removeVault method
self.switchboardRef.removeVault(capability: self.exampleTokenVaultCapabilty)
}
}
```
This function will panic if is not possible to `.borrow()` a reference to a `&{FungibleToken.Receiver}` from the passed capability.

## Transfering tokens through the switchboard
The Fungible Token Switchboad provides two different ways of depositing tokens to it, using the `deposit(from: @FungibleToken.Vault)` method enforced by the `{FungibleToken.Receiver}` or using the `safeDeposit(from: @FungibleToken.Vault): @FungibleToken`:

1. Using the first method will be just the same as depositing to `&{FungibleToken.Receiver}`. The path for the Switchboard receiver is defined in `FungibleTokenSwitchboard.ReceiverPublicPath`,
the generic receiver path `/public/GenericFTReceiver` that can also be obtained from the NFT MetadataViews contract.
An example of how to do this can be found in the transaction template on this repo `transactions/switchboard/transfer_tokens.cdc`
```cadence
transaction(to: Address, amount: UFix64) {
// The Vault resource that holds the tokens that are being transferred
let sentVault: @FungibleToken.Vault

prepare(signer: AuthAccount) {

// Get a reference to the signer's stored vault
let vaultRef = signer.borrow<&ExampleToken.Vault>
(from: ExampleToken.VaultStoragePath)
?? panic("Could not borrow reference to the owner's Vault!")

// Withdraw tokens from the signer's stored vault
self.sentVault <- vaultRef.withdraw(amount: amount)
}

execute {

// Get the recipient's public account object
let recipient = getAccount(to)

// Get a reference to the recipient's Switchboard Receiver
let switchboardRef = recipient.getCapability
(FungibleTokenSwitchboard.ReceiverPublicPath)
.borrow<&{FungibleToken.Receiver}>()
?? panic("Could not borrow receiver reference to switchboard!")

// Deposit the withdrawn tokens in the recipient's switchboard receiver
switchboardRef.deposit(from: <-self.sentVault)
}
}
```

2. The `safeDeposit(from: @FungibleToken.Vault): @FungibleToken` works in a similar way, with the difference that it will not panic if the desired FT Vault can not be obtained from the Switchboard. The method will return the passed vault, empty if the funds were deposited sucessfully or still containing the funds if the transfer of the funds was not possible. Keep in mind that when using this method on a transaction you will allways have to deal with the returned resource. An example of this can be found on `transactions/switchboard/safe_transfer_tokens.cdc`:
```cadence
transaction(to: Address, amount: UFix64) {
// The reference to the vault from the payer's account
let vaultRef: &ExampleToken.Vault
// The Vault resource that holds the tokens that are being transferred
let sentVault: @FungibleToken.Vault


prepare(signer: AuthAccount) {

// Get a reference to the signer's stored vault
self.vaultRef = signer.borrow<&ExampleToken.Vault>(from: ExampleToken.VaultStoragePath)
?? panic("Could not borrow reference to the owner's Vault!")

// Withdraw tokens from the signer's stored vault
self.sentVault <- self.vaultRef.withdraw(amount: amount)
}

execute {

// Get the recipient's public account object
let recipient = getAccount(to)

// Get a reference to the recipient's Switchboard Receiver
let switchboardRef = recipient.getCapability(FungibleTokenSwitchboard.PublicPath)
.borrow<&FungibleTokenSwitchboard.Switchboard{FungibleTokenSwitchboard.SwitchboardPublic}>()
?? panic("Could not borrow receiver reference to switchboard!")

// Deposit the withdrawn tokens in the recipient's switchboard receiver,
// then deposit the returned vault in the signer's vault
self.vaultRef.deposit(from: <- switchboardRef.safeDeposit(from: <-self.sentVault))
}
}
```

# Running Automated Tests

Expand Down
Loading