From 1d18062739fd5c986f17c868c3e13b2b26ca2a72 Mon Sep 17 00:00:00 2001
From: Alex Ni <12097569+nialexsan@users.noreply.github.com>
Date: Tue, 15 Oct 2024 11:30:37 -0400
Subject: [PATCH 1/3] code ref plugin
---
docs/evm/cadence/vm-bridge.md | 642 +------------------------
docusaurus.config.js | 1 +
package.json | 2 +
src/plugins/code-reference.js | 49 ++
src/plugins/insert-info-tags-loader.js | 32 --
yarn.lock | 39 ++
6 files changed, 108 insertions(+), 657 deletions(-)
create mode 100644 src/plugins/code-reference.js
delete mode 100644 src/plugins/insert-info-tags-loader.js
diff --git a/docs/evm/cadence/vm-bridge.md b/docs/evm/cadence/vm-bridge.md
index bf4b029200..d45d3358ac 100644
--- a/docs/evm/cadence/vm-bridge.md
+++ b/docs/evm/cadence/vm-bridge.md
@@ -87,129 +87,16 @@ Below are transactions relevant to onboarding assets:
onboard_by_type.cdc
-```cadence title="onboard_by_type.cdc"
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_type.cdc
-
-import "FungibleToken"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-
-/// This transaction onboards the asset type to the bridge, configuring the bridge to move assets between environments
-/// NOTE: This must be done before bridging a Cadence-native asset to EVM
-///
-/// @param type: The Cadence type of the bridgeable asset to onboard to the bridge
-///
-transaction(type: Type) {
-
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
-
- prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) {
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(FlowEVMBridgeConfig.onboardFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- execute {
- // Onboard the asset Type
- FlowEVMBridge.onboardByType(
- type,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- destroy self.scopedProvider
- }
-
- post {
- FlowEVMBridge.typeRequiresOnboarding(type) == false:
- "Asset ".concat(type.identifier).concat(" was not onboarded to the bridge.")
- }
-}
+```cadence onboard_by_type.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_type.cdc
```
onboard_by_evm_address.cdc
-```
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc
-
-import "FungibleToken"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-
-/// This transaction onboards the NFT type to the bridge, configuring the bridge to move NFTs between environments
-/// NOTE: This must be done before bridging a Cadence-native NFT to EVM
-///
-/// @param contractAddressHex: The EVM address of the contract defining the bridgeable asset to be onboarded
-///
-transaction(contractAddressHex: String) {
-
- let contractAddress: EVM.EVMAddress
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
-
- prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) {
- /* --- Construct EVMAddress from hex string (no leading `"0x"`) --- */
- //
- self.contractAddress = EVM.addressFromString(contractAddressHex)
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(FlowEVMBridgeConfig.onboardFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- execute {
- // Onboard the EVM contract
- FlowEVMBridge.onboardByEVMAddress(
- self.contractAddress,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- destroy self.scopedProvider
- }
-}
+```cadence onboard_by_evm_address.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc
```
@@ -234,26 +121,10 @@ You may also retrieve the type associated with a given EVM contract address usin
get_associated_type.cdc
-```cadence title="get_associated_type.cdc"
-// source: https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_type.cdc
-
-import "EVM"
-
-import "FlowEVMBridgeConfig"
-
-/// Returns the Cadence Type associated with the given EVM address (as its hex String)
-///
-/// @param evmAddressHex: The hex-encoded address of the EVM contract as a String
-///
-/// @return The Cadence Type associated with the EVM address or nil if the address is not onboarded. `nil` may also be
-/// returned if the address is not a valid EVM address.
-///
-access(all)
-fun main(addressHex: String): Type? {
- let address = EVM.addressFromString(addressHex)
- return FlowEVMBridgeConfig.getTypeAssociated(with: address)
-}
+```cadence get_associated_type.cdc
+!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_type.cdc
```
+
Alternatively, given some onboarded Cadence type, you can retrieve the associated EVM address using the following
@@ -263,28 +134,8 @@ script:
get_associated_address.cdc
-```cadence title="get_associated_address.cdc"
-// source: https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_evm_address.cdc
-
-import "EVM"
-
-import "FlowEVMBridgeConfig"
-
-/// Returns the EVM address associated with the given Cadence type (as its identifier String)
-///
-/// @param typeIdentifier: The Cadence type identifier String
-///
-/// @return The EVM address as a hex string if the type has an associated EVMAddress, otherwise nil
-///
-access(all)
-fun main(identifier: String): String? {
- if let type = CompositeType(identifier) {
- if let address = FlowEVMBridgeConfig.getEVMAddressAssociated(with: type) {
- return address.toString()
- }
- }
- return nil
-}
+```cadence get_associated_address.cdc
+!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_evm_address.cdc
```
@@ -300,127 +151,8 @@ Below are transactions relevant to bridging NFTs:
bridge_nft_to_evm.cdc
-```cadence title="bridge_nft_to_evm.cdc"
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc
-
-import "FungibleToken"
-import "NonFungibleToken"
-import "ViewResolver"
-import "MetadataViews"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-import "FlowEVMBridgeUtils"
-
-/// Bridges an NFT from the signer's collection in Cadence to the signer's COA in FlowEVM
-///
-/// NOTE: This transaction also onboards the NFT to the bridge if necessary which may incur additional fees
-/// than bridging an asset that has already been onboarded.
-///
-/// @param nftIdentifier: The Cadence type identifier of the NFT to bridge - e.g. nft.getType().identifier
-/// @param id: The Cadence NFT.id of the NFT to bridge to EVM
-///
-transaction(nftIdentifier: String, id: UInt64) {
-
- let nft: @{NonFungibleToken.NFT}
- let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount
- let requiresOnboarding: Bool
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
-
- prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) {
- /* --- Reference the signer's CadenceOwnedAccount --- */
- //
- // Borrow a reference to the signer's COA
- self.coa = signer.storage.borrow(from: /storage/evm)
- ?? panic("Could not borrow COA from provided gateway address")
-
- /* --- Construct the NFT type --- */
- //
- // Construct the NFT type from the provided identifier
- let nftType = CompositeType(nftIdentifier)
- ?? panic("Could not construct NFT type from identifier: ".concat(nftIdentifier))
- // Parse the NFT identifier into its components
- let nftContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: nftType)
- ?? panic("Could not get contract address from identifier: ".concat(nftIdentifier))
- let nftContractName = FlowEVMBridgeUtils.getContractName(fromType: nftType)
- ?? panic("Could not get contract name from identifier: ".concat(nftIdentifier))
-
- /* --- Retrieve the NFT --- */
- //
- // Borrow a reference to the NFT collection, configuring if necessary
- let viewResolver = getAccount(nftContractAddress).contracts.borrow<&{ViewResolver}>(name: nftContractName)
- ?? panic("Could not borrow ViewResolver from NFT contract")
- let collectionData = viewResolver.resolveContractView(
- resourceType: nftType,
- viewType: Type()
- ) as! MetadataViews.NFTCollectionData? ?? panic("Could not resolve NFTCollectionData view")
- let collection = signer.storage.borrow(
- from: collectionData.storagePath
- ) ?? panic("Could not access signer's NFT Collection")
-
- // Withdraw the requested NFT & calculate the approximate bridge fee based on NFT storage usage
- let currentStorageUsage = signer.storage.used
- self.nft <- collection.withdraw(withdrawID: id)
- let withdrawnStorageUsage = signer.storage.used
- var approxFee = FlowEVMBridgeUtils.calculateBridgeFee(
- bytes: currentStorageUsage - withdrawnStorageUsage
- ) * 1.10
- // Determine if the NFT requires onboarding - this impacts the fee required
- self.requiresOnboarding = FlowEVMBridge.typeRequiresOnboarding(self.nft.getType())
- ?? panic("Bridge does not support this asset type")
- if self.requiresOnboarding {
- approxFee = approxFee + FlowEVMBridgeConfig.onboardFee
- }
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- pre {
- self.nft.getType().identifier == nftIdentifier:
- "Attempting to send invalid nft type - requested: ".concat(nftIdentifier)
- .concat(", sending: ").concat(self.nft.getType().identifier)
- }
-
- execute {
- if self.requiresOnboarding {
- // Onboard the NFT to the bridge
- FlowEVMBridge.onboardByType(
- self.nft.getType(),
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- }
- // Execute the bridge
- self.coa.depositNFT(
- nft: <-self.nft,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- // Destroy the ScopedFTProvider
- destroy self.scopedProvider
- }
-}
+```cadence bridge_nft_to_evm.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc
```
@@ -428,115 +160,8 @@ transaction(nftIdentifier: String, id: UInt64) {
bridge_nft_from_evm.cdc
-```cadence title="bridge_nft_from_evm.cdc"
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc
-
-import "FungibleToken"
-import "NonFungibleToken"
-import "ViewResolver"
-import "MetadataViews"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-import "FlowEVMBridgeUtils"
-
-/// This transaction bridges an NFT from EVM to Cadence assuming it has already been onboarded to the FlowEVMBridge
-/// NOTE: The ERC721 must have first been onboarded to the bridge. This can be checked via the method
-/// FlowEVMBridge.evmAddressRequiresOnboarding(address: self.evmContractAddress)
-///
-/// @param nftIdentifier: The Cadence type identifier of the NFT to bridge - e.g. nft.getType().identifier
-/// @param id: The ERC721 id of the NFT to bridge to Cadence from EVM
-///
-transaction(nftIdentifier: String, id: UInt256) {
-
- let nftType: Type
- let collection: &{NonFungibleToken.Collection}
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
- let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount
-
- prepare(signer: auth(BorrowValue, CopyValue, IssueStorageCapabilityController, PublishCapability, SaveValue, UnpublishCapability) &Account) {
- /* --- Reference the signer's CadenceOwnedAccount --- */
- //
- // Borrow a reference to the signer's COA
- self.coa = signer.storage.borrow(from: /storage/evm)
- ?? panic("Could not borrow COA from provided gateway address")
-
- /* --- Construct the NFT type --- */
- //
- // Construct the NFT type from the provided identifier
- self.nftType = CompositeType(nftIdentifier)
- ?? panic("Could not construct NFT type from identifier: ".concat(nftIdentifier))
- // Parse the NFT identifier into its components
- let nftContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: self.nftType)
- ?? panic("Could not get contract address from identifier: ".concat(nftIdentifier))
- let nftContractName = FlowEVMBridgeUtils.getContractName(fromType: self.nftType)
- ?? panic("Could not get contract name from identifier: ".concat(nftIdentifier))
-
- /* --- Reference the signer's NFT Collection --- */
- //
- // Borrow a reference to the NFT collection, configuring if necessary
- let viewResolver = getAccount(nftContractAddress).contracts.borrow<&{ViewResolver}>(name: nftContractName)
- ?? panic("Could not borrow ViewResolver from NFT contract")
- let collectionData = viewResolver.resolveContractView(
- resourceType: self.nftType,
- viewType: Type()
- ) as! MetadataViews.NFTCollectionData? ?? panic("Could not resolve NFTCollectionData view")
- if signer.storage.borrow<&{NonFungibleToken.Collection}>(from: collectionData.storagePath) == nil {
- signer.storage.save(<-collectionData.createEmptyCollection(), to: collectionData.storagePath)
- signer.capabilities.unpublish(collectionData.publicPath)
- let collectionCap = signer.capabilities.storage.issue<&{NonFungibleToken.Collection}>(collectionData.storagePath)
- signer.capabilities.publish(collectionCap, at: collectionData.publicPath)
- }
- self.collection = signer.storage.borrow<&{NonFungibleToken.Collection}>(from: collectionData.storagePath)
- ?? panic("Could not borrow collection from storage path")
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Calculate the bridge fee - bridging from EVM consumes no storage, so flat fee
- let approxFee = FlowEVMBridgeUtils.calculateBridgeFee(bytes: 0)
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- execute {
- // Execute the bridge
- let nft: @{NonFungibleToken.NFT} <- self.coa.withdrawNFT(
- type: self.nftType,
- id: id,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- // Ensure the bridged nft is the correct type
- assert(
- nft.getType() == self.nftType,
- message: "Bridged nft type mismatch - requeswted: ".concat(self.nftType.identifier)
- .concat(", received: ").concat(nft.getType().identifier)
- )
- // Deposit the bridged NFT into the signer's collection
- self.collection.deposit(token: <-nft)
- // Destroy the ScopedFTProvider
- destroy self.scopedProvider
- }
-}
+```cadence bridge_nft_from_evm.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc
```
@@ -560,128 +185,8 @@ Below are transactions relevant to bridging fungible tokens:
bridge_tokens_to_evm.cdc
-```cadence title="bridge_tokens_to_evm.cdc"
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc
-
-import "FungibleToken"
-import "ViewResolver"
-import "FungibleTokenMetadataViews"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-import "FlowEVMBridgeUtils"
-
-/// Bridges a Vault from the signer's storage to the signer's COA in EVM.Account.
-///
-/// NOTE: This transaction also onboards the Vault to the bridge if necessary which may incur additional fees
-/// than bridging an asset that has already been onboarded.
-///
-/// @param vaultIdentifier: The Cadence type identifier of the FungibleToken Vault to bridge
-/// - e.g. vault.getType().identifier
-/// @param amount: The amount of tokens to bridge from EVM
-///
-transaction(vaultIdentifier: String, amount: UFix64) {
-
- let sentVault: @{FungibleToken.Vault}
- let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount
- let requiresOnboarding: Bool
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
-
- prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) {
- /* --- Reference the signer's CadenceOwnedAccount --- */
- //
- // Borrow a reference to the signer's COA
- self.coa = signer.storage.borrow(from: /storage/evm)
- ?? panic("Could not borrow COA from provided gateway address")
-
- /* --- Construct the Vault type --- */
- //
- // Construct the Vault type from the provided identifier
- let vaultType = CompositeType(vaultIdentifier)
- ?? panic("Could not construct Vault type from identifier: ".concat(vaultIdentifier))
- // Parse the Vault identifier into its components
- let tokenContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: vaultType)
- ?? panic("Could not get contract address from identifier: ".concat(vaultIdentifier))
- let tokenContractName = FlowEVMBridgeUtils.getContractName(fromType: vaultType)
- ?? panic("Could not get contract name from identifier: ".concat(vaultIdentifier))
-
- /* --- Retrieve the funds --- */
- //
- // Borrow a reference to the FungibleToken Vault
- let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName)
- ?? panic("Could not borrow ViewResolver from FungibleToken contract")
- let vaultData = viewResolver.resolveContractView(
- resourceType: vaultType,
- viewType: Type()
- ) as! FungibleTokenMetadataViews.FTVaultData? ?? panic("Could not resolve FTVaultData view")
- let vault = signer.storage.borrow(
- from: vaultData.storagePath
- ) ?? panic("Could not access signer's FungibleToken Vault")
-
- // Withdraw the requested balance & calculate the approximate bridge fee based on storage usage
- let currentStorageUsage = signer.storage.used
- self.sentVault <- vault.withdraw(amount: amount)
- let withdrawnStorageUsage = signer.storage.used
- // Approximate the bridge fee based on the difference in storage usage with some buffer
- var approxFee = FlowEVMBridgeUtils.calculateBridgeFee(
- bytes: currentStorageUsage - withdrawnStorageUsage
- ) * 1.10
- // Determine if the Vault requires onboarding - this impacts the fee required
- self.requiresOnboarding = FlowEVMBridge.typeRequiresOnboarding(self.sentVault.getType())
- ?? panic("Bridge does not support this asset type")
- if self.requiresOnboarding {
- approxFee = approxFee + FlowEVMBridgeConfig.onboardFee
- }
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- pre {
- self.sentVault.getType().identifier == vaultIdentifier:
- "Attempting to send invalid vault type - requested: ".concat(vaultIdentifier)
- .concat(", sending: ").concat(self.sentVault.getType().identifier)
- }
-
- execute {
- if self.requiresOnboarding {
- // Onboard the Vault to the bridge
- FlowEVMBridge.onboardByType(
- self.sentVault.getType(),
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- }
- // Execute the bridge
- self.coa.depositTokens(
- vault: <-self.sentVault,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- // Destroy the ScopedFTProvider
- destroy self.scopedProvider
- }
-}
+```cadence bridge_tokens_to_evm.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc
```
@@ -689,121 +194,8 @@ transaction(vaultIdentifier: String, amount: UFix64) {
bridge_tokens_from_evm.cdc
-```cadence title="bridge_tokens_from_evm.cdc"
-// source: https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc
-
-import "FungibleToken"
-import "FungibleTokenMetadataViews"
-import "ViewResolver"
-import "MetadataViews"
-import "FlowToken"
-
-import "ScopedFTProviders"
-
-import "EVM"
-
-import "FlowEVMBridge"
-import "FlowEVMBridgeConfig"
-import "FlowEVMBridgeUtils"
-
-/// This transaction bridges fungible tokens from EVM to Cadence assuming it has already been onboarded to the
-/// FlowEVMBridge.
-///
-/// NOTE: The ERC20 must have first been onboarded to the bridge. This can be checked via the method
-/// FlowEVMBridge.evmAddressRequiresOnboarding(address: self.evmContractAddress)
-///
-/// @param vaultIdentifier: The Cadence type identifier of the FungibleToken Vault to bridge
-/// - e.g. vault.getType().identifier
-/// @param amount: The amount of tokens to bridge from EVM
-///
-transaction(vaultIdentifier: String, amount: UInt256) {
-
- let vaultType: Type
- let receiver: &{FungibleToken.Vault}
- let scopedProvider: @ScopedFTProviders.ScopedFTProvider
- let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount
-
- prepare(signer: auth(BorrowValue, CopyValue, IssueStorageCapabilityController, PublishCapability, SaveValue, UnpublishCapability) &Account) {
- /* --- Reference the signer's CadenceOwnedAccount --- */
- //
- // Borrow a reference to the signer's COA
- self.coa = signer.storage.borrow(from: /storage/evm)
- ?? panic("Could not borrow COA from provided gateway address")
-
- /* --- Construct the Vault type --- */
- //
- // Construct the Vault type from the provided identifier
- self.vaultType = CompositeType(vaultIdentifier)
- ?? panic("Could not construct Vault type from identifier: ".concat(vaultIdentifier))
- // Parse the Vault identifier into its components
- let tokenContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: self.vaultType)
- ?? panic("Could not get contract address from identifier: ".concat(vaultIdentifier))
- let tokenContractName = FlowEVMBridgeUtils.getContractName(fromType: self.vaultType)
- ?? panic("Could not get contract name from identifier: ".concat(vaultIdentifier))
-
- /* --- Reference the signer's Vault --- */
- //
- // Borrow a reference to the FungibleToken Vault, configuring if necessary
- let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName)
- ?? panic("Could not borrow ViewResolver from FungibleToken contract")
- let vaultData = viewResolver.resolveContractView(
- resourceType: self.vaultType,
- viewType: Type()
- ) as! FungibleTokenMetadataViews.FTVaultData? ?? panic("Could not resolve FTVaultData view")
- // If the vault does not exist, create it and publish according to the contract's defined configuration
- if signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) == nil {
- signer.storage.save(<-vaultData.createEmptyVault(), to: vaultData.storagePath)
-
- signer.capabilities.unpublish(vaultData.receiverPath)
- signer.capabilities.unpublish(vaultData.metadataPath)
-
- let receiverCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath)
- let metadataCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath)
-
- signer.capabilities.publish(receiverCap, at: vaultData.receiverPath)
- signer.capabilities.publish(metadataCap, at: vaultData.metadataPath)
- }
- self.receiver = signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath)
- ?? panic("Could not borrow Vault from storage path")
-
- /* --- Configure a ScopedFTProvider --- */
- //
- // Calculate the bridge fee - bridging from EVM consumes no storage, so flat fee
- let approxFee = FlowEVMBridgeUtils.calculateBridgeFee(bytes: 0)
- // Issue and store bridge-dedicated Provider Capability in storage if necessary
- if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
- let providerCap = signer.capabilities.storage.issue(
- /storage/flowTokenVault
- )
- signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
- }
- // Copy the stored Provider capability and create a ScopedFTProvider
- let providerCapCopy = signer.storage.copy>(
- from: FlowEVMBridgeConfig.providerCapabilityStoragePath
- ) ?? panic("Invalid Provider Capability found in storage.")
- let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee)
- self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
- provider: providerCapCopy,
- filters: [ providerFilter ],
- expiration: getCurrentBlock().timestamp + 1.0
- )
- }
-
- execute {
- // Execute the bridge request
- let vault: @{FungibleToken.Vault} <- self.coa.withdrawTokens(
- type: self.vaultType,
- amount: amount,
- feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
- )
- // Ensure the bridged vault is the correct type
- assert(vault.getType() == self.vaultType, message: "Bridged vault type mismatch")
- // Deposit the bridged token into the signer's vault
- self.receiver.deposit(from: <-vault)
- // Destroy the ScopedFTProvider
- destroy self.scopedProvider
- }
-}
+```cadence bridge_tokens_from_evm.cdc
+!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc
```
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 7c32808ab0..ad9e7f4daa 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -177,6 +177,7 @@ const config = {
({
docs: {
beforeDefaultRemarkPlugins: [
+ require('./src/plugins/code-reference'),
[
remarkCodeHike,
{ theme: 'nord', lineNumbers: true, showCopyButton: true },
diff --git a/package.json b/package.json
index c8889b51bf..b69ed545d1 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"dotenv": "16.0.3",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
+ "node-fetch": "^3.3.2",
"postcss": "^8.4.31",
"prettier": "^2.8.7",
"prism-react-renderer": "^1.3.5",
@@ -51,6 +52,7 @@
"shiki": "1.14.1",
"tailwind-scrollbar-hide": "1.1.7",
"tailwindcss": "^3.3.5",
+ "unist-util-visit": "^5.0.0",
"webpack-merge": "5.8.0"
},
"devDependencies": {
diff --git a/src/plugins/code-reference.js b/src/plugins/code-reference.js
new file mode 100644
index 0000000000..779f1f13d7
--- /dev/null
+++ b/src/plugins/code-reference.js
@@ -0,0 +1,49 @@
+import { visit } from 'unist-util-visit';
+import fetch from 'node-fetch';
+
+const VALUE_STARTS_WITH = '!from ';
+
+const githubReplace = /^(https:\/\/)(www.)?github.com\/(.+)\/blob\/(.+)/;
+
+const getUrl = (nodeValue) => {
+ const url = nodeValue.replace(VALUE_STARTS_WITH, '').trim();
+
+ return url.replace(githubReplace, '$1raw.githubusercontent.com/$3/$4');
+};
+
+const plugin = () => {
+ const transformer = async (ast) => {
+ const promises = [];
+ visit(ast, 'code', (node) => {
+ if (node.value?.startsWith(VALUE_STARTS_WITH)) {
+ const url = getUrl(node.value);
+ if (!url) {
+ return;
+ }
+ const fetchPromise = fetch(url)
+ .then((res) => {
+ if (!res.ok) {
+ throw new Error(
+ `Failed to fetch code from ${url}: ${res.statusText}`,
+ );
+ }
+ return res.text();
+ })
+ .then((code) => {
+ node.value = code;
+ })
+ .catch((err) => {
+ console.error(err);
+ node.value = `Error fetching code: ${err.message}`;
+ });
+
+ promises.push(fetchPromise);
+ }
+ });
+
+ await Promise.all(promises);
+ };
+ return transformer;
+};
+
+export default plugin;
diff --git a/src/plugins/insert-info-tags-loader.js b/src/plugins/insert-info-tags-loader.js
deleted file mode 100644
index a930d3a095..0000000000
--- a/src/plugins/insert-info-tags-loader.js
+++ /dev/null
@@ -1,32 +0,0 @@
-module.exports = function (source) {
- const infoBannerMessage =
- 'For Cadence 0.42 go to [Legacy Docs](https://legacy.developers.flow.com/)';
- // Function to check if a page content contains "cadence" code block
- const containsCadenceCodeBlock = (content) => {
- return content.includes('```cadence');
- };
-
- // Function to insert :::info::: tag into content
- const insertInfoTag = (content) => {
- const infoBanner = ':::info\n' + infoBannerMessage + '\n:::\n';
- // Check fof front matter
- if (!content.startsWith('---\n')) {
- // Insert :::info::: tag at the beginning of the content
- return infoBanner + content;
- }
- // Split the content into front matter and body
- const [frontMatter, ...body] = content.split('---\n').slice(1);
-
- // Insert :::info::: tag after front matter
- return `---\n${frontMatter}---\n${infoBanner}${body.join('---\n')}`;
- };
-
- // Check if the content contains a "cadence" code block
- if (containsCadenceCodeBlock(source)) {
- // Insert :::info::: tag
- return insertInfoTag(source);
- }
-
- // Return the original content if no changes are needed
- return source;
-};
diff --git a/yarn.lock b/yarn.lock
index 7180ea239e..7a74733951 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5414,6 +5414,11 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
+data-uri-to-buffer@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
+ integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
+
date-fns@2.29.3:
version "2.29.3"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
@@ -6608,6 +6613,14 @@ feed@^4.2.2:
dependencies:
xml-js "^1.6.11"
+fetch-blob@^3.1.2, fetch-blob@^3.1.4:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
+ integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
+ dependencies:
+ node-domexception "^1.0.0"
+ web-streams-polyfill "^3.0.3"
+
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -6790,6 +6803,13 @@ format@^0.2.0:
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==
+formdata-polyfill@^4.0.10:
+ version "4.0.10"
+ resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
+ integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
+ dependencies:
+ fetch-blob "^3.1.2"
+
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -9415,6 +9435,11 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
+node-domexception@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
+ integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
+
node-downloader-helper@^2.1.6:
version "2.1.9"
resolved "https://registry.yarnpkg.com/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz#a59ee7276b2bf708bbac2cc5872ad28fc7cd1b0e"
@@ -9444,6 +9469,15 @@ node-fetch@^2.0.0, node-fetch@^2.6.1:
dependencies:
whatwg-url "^5.0.0"
+node-fetch@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b"
+ integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==
+ dependencies:
+ data-uri-to-buffer "^4.0.0"
+ fetch-blob "^3.1.4"
+ formdata-polyfill "^4.0.10"
+
node-forge@^1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
@@ -13055,6 +13089,11 @@ web-namespaces@^2.0.0:
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
+web-streams-polyfill@^3.0.3:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
+ integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
+
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
From a409880b528564665508c798863c25fd2eb2e6af Mon Sep 17 00:00:00 2001
From: Alex Ni <12097569+nialexsan@users.noreply.github.com>
Date: Tue, 15 Oct 2024 19:45:47 -0400
Subject: [PATCH 2/3] contributing
---
CONTRIBUTING.md => CONTRIBUTING | 48 ++++++++++++++++++++++++++-------
1 file changed, 38 insertions(+), 10 deletions(-)
rename CONTRIBUTING.md => CONTRIBUTING (95%)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING
similarity index 95%
rename from CONTRIBUTING.md
rename to CONTRIBUTING
index 57dff0a2f9..81a8d03e9f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING
@@ -135,18 +135,23 @@ import { useLocation } from '@docusaurus/router';
```
-
+:::warning
+
The `index` page should only include information that is available elsewhere within the category's other pages.
-
+
+:::
### Using DocCardList
Using `DocCardList` improves the layout of the index page:
-
+:::note Example
+
![edit page](./static/images/contributing/doc-card-list-light.png#gh-light-mode-only)
+
![edit page](./static/images/contributing/doc-card-list-dark.png#gh-dark-mode-only)
-
+
+:::
On the most pages you can use just `` component imported from `'@theme/DocCardList'`
@@ -173,12 +178,13 @@ import { useLocation } from '@docusaurus/router';
!isSamePath(item.href, useLocation().pathname))}/>
```
-
+:::warning
+
If you use `` on the top level category index page (e.g. `./docs/tools/index.mdx`), Docusaurus will throw an error:
> useCurrentSidebarCategory() should only be used on category index pages.
-
+:::
## SEO
@@ -225,9 +231,11 @@ Writing links in your documents is easy if you follow this rule-of-thumb: If it
[link](https://www.google.com)
```
-
+:::tip
+
Use relative links directly to .md/.mdx files
-
+
+:::
### Callouts
@@ -243,12 +251,32 @@ Available types:
Example:
```markdown
-
+:::tip
+
Use relative links directly to .md/.mdx files
-
+:::
```
+### Code references
+
+To include code from a file using a direct URL use `!from` operand inside a code block.
+
+Example:
+
+````
+```
+!from https://raw.githubusercontent.com/onflow/docs/refs/heads/main/docs/evm/about.md
+```
+````
+
+mdx
+Copy code
+```javascript
+{code}
+This method keeps your documentation synchronized with your codebase by pulling the latest code directly into your docs.
+
+
## Content Validation
Content is validated each time a PR is submitted to the `docs` repository.
From 1c5dca84fddd361699c90d8764ce98858d1f7fac Mon Sep 17 00:00:00 2001
From: Alex Ni <12097569+nialexsan@users.noreply.github.com>
Date: Wed, 16 Oct 2024 10:17:41 -0400
Subject: [PATCH 3/3] markdown snippet
---
CONTRIBUTING | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING b/CONTRIBUTING
index 81a8d03e9f..585bdf8bc9 100644
--- a/CONTRIBUTING
+++ b/CONTRIBUTING
@@ -264,7 +264,7 @@ To include code from a file using a direct URL use `!from` operand inside a code
Example:
-````
+````markdown
```
!from https://raw.githubusercontent.com/onflow/docs/refs/heads/main/docs/evm/about.md
```