Giter VIP home page Giter VIP logo

safe-apps-sdk's Introduction

Safe Apps Developer Tools Monorepo

Logo

license

Developer tools to integrate third-party applications (Safe Apps) with Safe (https://app.safe.global/).

You can find more resources on Safe Apps in the Safe Developer Portal.

safeapps_pathways_v4

Packages

Package Description
cra-template-safe-app CRA template to quickly bootstrap a Safe app
safe-apps-react-sdk A wrapper of safe-apps-sdk with helpful React Hooks
safe-apps-sdk JavaScript SDK
safe-apps-provider A generic provider that can be used with common web3 libraries (e.g. web3.js or Ethers)
safe-apps-onboard Blocknative included Safe App support in onboard.js v1.26.0. Check Blocknative docs for the integration guide
safe-apps-web3modal A wrapper around Web3Modal that would automatically connect to the Safe if the app is loaded as a Safe app
safe-apps-web3-react A web3-react connector for Safe is included in web3-react starting from version 8
safe-apps-wagmi A wagmi connector for Safe Apps
safe-apps-test-app A test app to test the Safe Apps SDK

Testing your Safe App

You can directly use our production interface for testing your Safe App

Setting up development environment

Installing dependencies

yarn install

Running commands

We will use build command as an example. Same applies to other commands.

For all packages:

yarn build

For a specific package:

yarn lerna run --scope @safe-global/safe-apps-sdk build --stream

--stream options enables command output. By default, lerna displays it only in case of an error.

Release process

Release process is described in releases.md

Useful links

License

This project is licensed under the MIT License - see the LICENSE.md file for details

safe-apps-sdk's People

Contributors

apoorvlathey avatar bannik avatar danisomoza avatar dasanra avatar dependabot[bot] avatar fmrsabino avatar germartinez avatar giacomolicari avatar github-actions[bot] avatar iamacook avatar julienkode avatar katspaugh avatar lukasschor avatar maxaleks avatar mmv08 avatar nicosampler avatar nikgraf avatar paulrberg avatar rmeissner avatar robriks avatar santteegt avatar schmanu avatar solimander avatar soptq avatar tomafrench avatar uxio0 avatar vladimirmikulic avatar yagopv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

safe-apps-sdk's Issues

Allow to specify `safeTxGas`

Often developers of dapps have a good understanding how much gas is required by their dapps. Therefore for normal transactions it is possible to provide the wallet with a gasLimit that should be used. For the Safe contracts safeTxGas is this gas limit. Therefore we should allow that a sapp can provide this information

Create a simple developer interface without a dependency on Gnosis infrastructure

Some projects are used to test on different testnets that are not supported by the Safe (e.g. Ropsten / Goerli). Developing a Safe App, therefore, requires deploying the same contracts also on Rinkeby or testing directly on Mainnet.

This can be solved by developing a lightweight dev interface (single-owner, no service dependencies, ...)

What it should be able to do:

  • Deploy a master copy if it's not deployed to the network of user's wallet
  • Deploy a 1oo1 safe
  • Load a safe app
  • Safe app should be able to propose transactions/rpc calls

Need of signature mechanism into the safe apps

Hello guys, Great job!

I am currently creating a safe app for Request.

For our use case, we need the off-chain signature mechanism, usually using Metamask.
It doesn't seem possible to access Metamask from the iframe. it would be great if the SDK could provide a signature method.

Cheers,

Provide apps access to Safe's addressbook / owners list

There are situations when certain apps would benefit from having access to addresses which are relevant to the Safe being used:

  • Users can attach real world names to be displayed in dashboards, etc. Useful for viewing Sablier streams or seeing how people voted through governance apps, etc.
  • In payments apps users can easily select names from address book in a dropdown to pay repeat clients, reducing errors

This is very much a nice-to-have for when the ecosystem is a bit more developed (plus it has some privacy implications which would need to be addressed)

Allow to sign message via connected owner wallet

Signing messages allows to authenticate a user. This can be used in Safe apps to identify/ authenticate the connected wallet. Currently it is not possible to request a signature from the wallet connected to the web interface. This is to avoid potential security risks. We should find a way to limit the security risk and allow dapps to request an owner signature.

Security notes

  • If a Safe app triggers a signature request the Wallet will display it as if it was requested by the Safe react interface
  • A Safe app could request a signature for a Safe transaction if no protection is in place

Update CI for monorepo setup

On tag the CI generates an archive with released versions. This got broken with the new monorepo setup. Should be fixed.

NODE_ENV=production yarn start — Uncaught SyntaxError: Unexpected token '<' — Manifest: Line: 1, column: 1, Syntax error.

yarn start - works for me

NODE_ENV=production yarn start - fails

image

Everything else is the same.

What are you actually trying to do?

if (production) {
  contractAddress = 0xABC..
} else if (dev) {
  contractAdress = 0xDEF...
}

https://riptutorial.com/node-js/example/10101/setting-node-env--production-

And this https://stackoverflow.com/questions/37885952/export-in-an-if-statement-using-meteor

"Exports must be defined at the top level (from §A.5 of the spec). This is related to how modules are handled when lazy-loading or circular dependencies occur and the code can't be executed during or before loading."
"Exporting a function able to decide is a far more robust solution."

The trouble that I have: NODE_ENV=production does not allow thing to start at all :(

Add safe-apps-sdk as a peer dependency to other packages

Jose ran into the following error:

image

This was because there were two versions of the SDKs installed: 2.0.0 as a separate entry in package.json and 1.1.1 as a dependency for ethers provider. SDK type signatures contain a private field, and while the signatures are equal, a private field may not.

I think we should add safe-apps-sdk as a peer dependency to avoid such errors.

Switch to promisified API

With the current API where you have to map requests to responses, it's an additional challenge for the developer and it's something unordinary, 99% of the libs use promises.

Requirements:

  • Switch action methods where the response is expected to promise-based API (.sendTransactions, .eth.*)

Error while running vanilla CRA template

When running the current CRA template from scratch the app doesn't load and I keep getting the error below in the Safe-React app:

ThirdPartyApp: A message was received without message id.

Any idea what's wrong?

Add `getBlockNumber` to eth methods

Currently there is no way to get the current block number.

Edit: I think it would be nice to send custom requests too (e.g. by specifying the method and aparams). As part of this it might make sense to expose the commnicator.

Improve type definitions

Currently there are things that are loosely typed like .sendTransactions

Why would we want this?

Reliability and developer experience, the types serve as a documentation

Add test example for cra-template-safe-app

Currently, if you try to render a component that uses useSafeAppsSdk hook inside a test, it will throw an error

We need to add an easy test example (like create-react-app) to push good engineering practices and also then reuse this in our apps.

safe-apps-web3modal fails to compile

Hi team,

While trying to integrate @gnosis.pm/safe-apps-web3modal into my app. I get the following error:

./node_modules/@gnosis.pm/safe-apps-web3modal/dist/index.js
Module not found: Can't resolve './modal' in './node_modules/@gnosis.pm/safe-apps-web3modal/dist'

I noticed that this is because the directory at ./node_modules/@gnosis.pm/safe-apps-web3modal/dist has only one file index.js

$ ls ./node_modules/@gnosis.pm/safe-apps-web3modal/dist
index.js

The package.json I'm using reads as follows:

    "@gnosis.pm/safe-apps-sdk": "^2.2.0",
    "@gnosis.pm/safe-apps-web3modal": "^0.2.0",
    "web3modal": "^1.9.3"

Please check and release an updated version with a fix. Do let me know if you need any other details.

Remove error logs when receiving a message without an id

Currently the safe web interface sends messages for the old and new sdk version and therefore the sdks log an error for an invalid message.

We should not log this as an error. Either we remove this log completely or convert it to a warning (or maybe even a debug log).

Screenshot

image

@safe-apps-sdk - bundle size - consider importing semverGte directly, or remove semver altogether

Semver makes up 58% of this javascript bundle, according to bundlephobia.

Semver is only used on one line:
https://github.com/gnosis/safe-apps-sdk/blob/9568ed238b584251ac9ee5e21c5cbbaf1693fc9f/packages/safe-apps-sdk/src/communication/index.ts

Consider importing the function directly for better code-splitting (this probably won't reduce the predicted size on bundlephobia, but may reduce final bundle size for projects with tree-shaking)

const semverGte = require('semver/functions/gte')

Or even better, compare version by hand and remove semver from package.json :)

Not sure if this is high-prio as it's possible the above file is already tree-shaken in most projects, I haven't looked where that file is actually used

Allow using the provider from the Safe interface for call requests

It should be possible to perform eth_call and other read calls requests via the Safe interface.

Why would we want this?

Currently every dapp provider needs to provide their own infura key. If the user uses a custom provider (e.g. via metamask) this is likely not used in the Safe app.

Notes?

This should only work for read calls (maybe each of these is a different function)

  • eth_call
  • eth_getBalance
  • eth_getLogs

Improve documentation

It should be easy to start developing a Safe app by following our documentation. Also we should expose our documentation more (link to developer portal)

Why would we want this?

We want developers to write Safe apps, therefore we should support them as best as we can.

Notes?

  • Should we make documentation framework-agnostic? Currently the example is written in react

Developer UI: cannot connect a different wallet

If you disconnect a wallet, clicking "Connect" again will always connect to the previously connected wallet, but it should display a modal where you should be able to select a different one.

`onSafeInfo` is triggered in a loop

When I use onSafeInfo as recommended in your docs, my react app gets in a render loop. It didn't happen with the previous version (0.1.1) of the SDK. I don't know when exactly the bug was introduced, last time I built a Safe App, I used SDK v0.1.1.

Compare these code samples:

With SDK 0.3.1 this code logs 'render' and 'onSafeInfo' in never ending loop

  const [appsSdk] = useState(initSdk());
  const [safeInfo, setSafeInfo] = useState<SafeInfo>();

  console.log("render");

  useEffect(() => {
    appsSdk.addListeners({
      onSafeInfo: (info) => {
        console.log("onSafeInfo");
        setSafeInfo(info);
      },
    });

    return () => appsSdk.removeListeners();
  }, [appsSdk]);

so I have to add an extra check, which was not necessary in v0.1.1

  const [appsSdk] = useState(initSdk());
  const [safeInfo, setSafeInfo] = useState<SafeInfo>();

  console.log("render");

  useEffect(() => {
    appsSdk.addListeners({
      onSafeInfo: (info) => {
        console.log("onSafeInfo");
        if (!safeInfo) {
          setSafeInfo(info);
        }
      },
    });

    return () => appsSdk.removeListeners();
  }, [appsSdk, safeInfo]);

Could you check and advise?

Return information about the tx submitted (if submitted, hash)

After a Safe app submitted a transaction it should get the safeTxHash of that transaction in return. This way it can request information about this transaction at a later point in time.

Why would we want this?

Currently the Safe app is closed after a transaction has been submitted (switch to transactions tab). Also there is no way for the Safe app to check if the transaction has been accepted or not.

Notes?

For this it is required to add some way to connect events to the protocol (similar to the ID field in the json rpc request). This is required for many of the features in this document and could even be its own feature.

Allow Safe apps to perform delegatecall actions

A number of projects (e.g. MakerDAO, Balancer, DefiSaver) make use of DSProxy contracts to allow improved UX by grouping several transactions into one by using script contracts such as Balancer's BActions.

Due to its ability to batch transactions, a Safe can fulfill much the same role by making calls to ERC20 contracts to give approvals, etc. before sending the "proper" transaction. This is less flexible than a script contract as shown by the createSmartPool function in the BActions contract. Here we deploy a smart pool controller contract and then immediately call a function on that new contract to deploy the underlying pool, something not possible to do through transaction batching.

In this case, ownership over this smart pool is transferable so it can be created by another contract and then transferred to the Safe in a single transaction; were this not the case then the user of a Safe app would be required to perform 2 separate transactions to deploy a smart pool.

Allowing the use of delegatecalls would allow a "GnosisBActions" (without all the tokens transfers) script contract to perform atomic deployment in this situation.

Add method to onboard and web3modal wrappers to check if running as SafeApp

Currently the only way to check if the app is running as a Safe app is to query the safe info again, which potentially tries to connect to the interface again. It would be nicer to have a isConnectedToSafe (or similar) method that just checks if it is connected (e.g. by checking the cached safe info).

Request id's are duplicated in firefox

I just discovered that safe apps that use RPC calls aren't working well in firefox because for some reason request ids are duplicated, and it's all because:
window?.performance.now().toString(36); // this is the code used to generate a request id
In chrome, it would return something like 251131.48499999807 but in Firefox it returns only the integer part, turns out they did it to protect from fingerprinting 🤯

Research a proper monorepo workflow

The amount of packages in the repository is growing but the publishing is done manually. This is not optimal. We should take inspiration from other monorepos (ethers, web3.js) and automate the process.

Use of private fields prevents use of SDK in Vue 3 apps

https://github.com/gnosis/safe-apps-sdk/blob/cb6c4657500ba3f62b89cbefdf3acd1321db2a95/packages/safe-apps-sdk/src/txs/index.ts#L6

Use of the #variable syntax causes the SDK to break in situations where the sdk is stored in a proxy as they change the value of this. Vue3 uses proxies extensively for state management so this creates a barrier for making Vue apps Safe-compatible.

This could be fixed by switching to the private variable syntax as used in the SafeAppProvider (although this comes at the cost of removing runtime enforcement). Alternatively I'd have to maintain a fork which can be used in Vue apps.

Some more info here: tc39/proposal-class-fields#106

SafeAppsProvider doesn't work with ethers v4

import { ethers } from 'ethers'
import SafeAppsSDK, { SafeInfo } from '@gnosis.pm/safe-apps-sdk'
import { SafeAppProvider } from '@gnosis.pm/safe-apps-provider'
const sdk = new SafeAppsSDK()
const safe = {
  network: "RINKEBY",
  safeAddress: "0x17c1dEe221f14321E82698f20905161042ce1c16"
}
new ethers.providers.Web3Provider(new SafeAppProvider(safe, sdk))

Here is the error that occurs:

Error: invalid web3Provider (arg="web3Provider", value={"submittedTxs":{},"events":{"_events":{},"_eventsCount":3},"safe":{"safeAddress":"0x17c1dEe221f14321E82698f20905161042ce1c16","network":"RINKEBY"},"sdk":{"communicator":{"allowedOrigins":null,"callbacks":{}},"eth":{"communicator":{"allowedOrigins":null,"callbacks":{}}},"txs":{"txServiceUrl":"https://safe-transaction.rinkeby.gnosis.io/api/v1","communicator":{"allowedOrigins":null,"callbacks":{}}}},"autoRefreshOnNetworkChange":false}, version=4.0.48)

Essentially it comes down to the fact that ethers is not able to see the methods on the class prototype object

[bug] onTransactionConfirmation is called before safe transaction can be polled using the SDK

When trying to obtain the transaction details from the SDK calling getBySafeTxHash inside of onTransactionConfirmation, the object returned is always { detail: 'Not found' }:

import initSdk, { SafeInfo } from "@gnosis.pm/safe-apps-sdk"

const appsSdk = initSdk()

const onTransactionConfirmation = ({ requestId, safeTxHash }) => {
  appsSdk.txs.getBySafeTxHash(e.safeTxHash).then((tx) => {
      console.log({ tx }) // { tx: { detail: 'Not found' } }
   })
};

appsSdk.addListeners({
  onTransactionConfirmation,
})

I worked around that by using setting a timeout, which is not ideal:

setTimeout(() => appsSdk.txs.getBySafeTxHash(safeTxHash).then((safeTx) => {
   console.log({ safeTx }) // { safeTx: { safe: '0x...', ... } }
}), 2000)

However, the safeTx object returned has the property transactionHash equal to null and another (longer) setTimeout seems to be needed.

I recommend delaying the confirmation notification until the transactionHash exist, or alternatively adding another listener to track the transaction e.g. onTransactionReady or onTransactionExecuted

Remove network type

Because the interface can theoretically be hosted on any network, maintaining types for networks can become cumbersome. Let's just switch to string

Another solution: add chainId instead of network name

related to #108

Allow to disable logging

Currently we log every incomming message, this massively polutes the logs and makes it hard to see the logs for devs

Safe-Apps starter-kit

We think it could be a good idea to create a starter-kit, to allow developers to start developing safe-apps as quickly as possible.

We propose to fork create-react-app and allow users to install a safe version of it like so: npx create-react-safe-app. After running this command, the users will have a TS sapp running, integrated with safe-react-components and the SDK.

They will only need to deploy it to IPFS/Netlify and the app will show a basic component with the Safe info.

Notes:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.