safe-global / safe-apps-sdk Goto Github PK
View Code? Open in Web Editor NEWClient-side SDKs to create third-party Safe Apps
Home Page: https://safe.global
License: MIT License
Client-side SDKs to create third-party Safe Apps
Home Page: https://safe.global
License: MIT License
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
"@types/jest": "^26.0.22"
Should be a dev-dependency
https://github.com/gnosis/safe-apps-sdk/blob/master/packages/safe-apps-react-sdk/package.json
Hope title says it all :p
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
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.
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 🤯
Update create-react-app safe-app template and react hooks library to use the v1 version of sdk
Currently there are things that are loosely typed like .sendTransactions
Reliability and developer experience, the types serve as a documentation
Currently we log every incomming message, this massively polutes the logs and makes it hard to see the logs for devs
I wish I would afterwards see which contracts I deployed, i.e. addresses of master copy, proxy factory etc.
This could also include viewing what contracts a safe uses.
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.
The endpoint we currently use is set to be deprecated in the near future. We need to check how many projects are using it and depending on that make the change.
https://github.com/gnosis/safe-apps-sdk/blob/master/packages/safe-apps-react-sdk/src/index.tsx#L18
This line here means that a new class will be constructed on every component re-render. I'm not sure how expensive that is in reality, but it's an easy fix:
const [sdk] = useState(() => {
return new SafeAppsSDK(opts)
});
https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
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
We should create a monorepo which would include:
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.
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:
Hi team,
I noticed that the provider for xDai Gnosis Safes does not return chainId
It is returned as undefined
as per https://github.com/gnosis/safe-apps-sdk/blob/4fb096ac61b125cdbb7680f65ab990534f9bb0c3/packages/safe-apps-provider/src/provider.ts#L33
I'm not sure what other places needs changes, but please do the needful for supporting xDai Gnosis Safes =)
Update the image of the old menu in the README file
https://raw.githubusercontent.com/gnosis/safe-apps-sdk/master/assets/safe-tab-apps.png
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.
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.
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.
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.
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:
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,
Jose ran into the following error:
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.
yarn start
- works for me
NODE_ENV=production yarn start
- fails
Everything else is the same.
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 :(
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)
We want developers to write Safe apps, therefore we should support them as best as we can.
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?
As we value 3rd party contributions (and more have been coming in), please coordinate to add the cla assistent to all of our repos. You can find an example in the safe-react repo: https://github.com/gnosis/safe-react/blob/development/.github/workflows/cla.yml Also make sure not to merge contributions of external devs before this is in place please
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).
One of the app developers struggled with that a little bit, I think it would be great to expose a method that would use GET /balances
endpoint from tx service
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
TBD
There are situations when certain apps would benefit from having access to addresses which are relevant to the Safe being used:
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)
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?
Basically same thing as #17, but for transaction rejection
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.
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.
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.
For known networks such as rinkeby, mainnet etc, does it make sense to reuse the existing canonical versions? i.e. no need to re-reploy?
Should it always use gnosis' contracts or suggest doing so?
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
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
Multiple projects are asking for a way for their apps to be used as a safe app via web3-react. It seems like in order to make it possible we need to create a connector based on https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/abstract-connector/src/index.ts
On tag the CI generates an archive with released versions. This got broken with the new monorepo setup. Should be fixed.
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:
.sendTransactions
, .eth.*
)It should be possible to perform eth_call
and other read calls requests via the Safe interface.
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.
This should only work for read calls (maybe each of these is a different function)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.