safe-global / safe-core-sdk Goto Github PK
View Code? Open in Web Editor NEWThe Safe{Core} SDK allows builders to add account abstraction functionality into their apps.
Home Page: https://docs.safe.global/sdk/overview
License: MIT License
The Safe{Core} SDK allows builders to add account abstraction functionality into their apps.
Home Page: https://docs.safe.global/sdk/overview
License: MIT License
Update the condition inside createTransaction(...)
that decides if the SDK will send a single or a batch transaction.
When passing an array of transaction as a parameter, take into account:
Check: https://gist.github.com/cmdzro/0547725ca6faa2067e7edf3c70b697f1#gistcomment-3954987
Add a tutorial to the Safe Dev Portal
safe-global/safe-docs#139
safeSdk.createTransaction(contractInteractionTransaction) will fail if the actual transaction will revert
Create a failing transaction
I'd like to iteratively build complex multi-step Gnosis Safe transactions and safely preview their side effects from forked mainnet without having to rely on the transaction service.
In general I'd like to use the multisig signer within the safe-ethers-provider
directory as the signer for the contracts that I'll be interacting with. This interactions.ts is a good example of the way I'd like to interact with the contracts with out having to construct a transaction similar to what is displayed here.
Another example of a similar feature can be seen here.
safe-ethers-provider
is a great too for building complex transactions in an easy and simple way. However, the reliance on the transaction service limits the versatility of the tool and makes it difficult to simulate on a forked network.
Please add a clear and concise description of any alternative solutions or features you have considered.
A solution closely resembling the desired functionality
N/A
We are pushing to implement EIP-3770 address references, which include a prefixed chain id before an address. We need to allow users to input addresses with a chain prefix.
There appears to be no support for all the GET /safes/{address}/all-transactions/
endpoint outlined in the swagger
Add a safeService.getAllTransactions(safeAddress)
function
It is needed to build functionality similar to the History
tab seen in the gnosis safe app. Without it, there is no straightforward way to get an overview of the safe
Safe user reported the following problem:
I try to Safe.create() to an existing contract that is NOT a safe, it throws all sorts of connection issues instead of a nice error > message. Basically I need a way of checking if an address is a safe. It works fine if the provided address is an EOA
Call safe.create() with a contract address that is not a Safe
A good error message and a method to check if an address is a safe
[ Error: missing revert data in call exception (error={"reason":"processing response error","code":"SERVER_ERROR","body":"{\"jsonrpc\":\"2.0\",\"id\":49,\"error\":{\"code\":-32000,\"message\":\"execution reverted\"}}"
, "error":{"code":-32000},"requestBody":"{\"method\":\"eth_call\",\"params\":[{\"from\":\"0xb64ff7a4a33acdf48d97dab0d764afd0f6176882\",\"to\":\"0x9fde8abd74998779fe90383e74666ea7387d4bb1\",\"data\":\"0x2f54bf6e0000000
0 0000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882\"},\"latest\"],\"id\":49,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"https://rinkeby.infura.io/v3/"}, data="0x", code=
C ALL_EXCEPTION, version=providers/5.4.3)
- index.js:199 Logger.makeError
[synthetix]/[@ethersproject]/logger/lib/index.js:199:21
- index.js:208 Logger.throwError
[synthetix]/[@ethersproject]/logger/lib/index.js:208:20
- json-rpc-provider.js:76 checkError
[synthetix]/[@ethersproject]/providers/lib/json-rpc-provider.js:76:16
- json-rpc-provider.js:633 JsonRpcProvider.<anonymous>
[synthetix]/[@ethersproject]/providers/lib/json-rpc-provider.js:633:47
- json-rpc-provider.js:48 step
[synthetix]/[@ethersproject]/providers/lib/json-rpc-provider.js:48:23
- json-rpc-provider.js:29 Object.throw
[synthetix]/[@ethersproject]/providers/lib/json-rpc-provider.js:29:53
- json-rpc-provider.js:21 rejected
[synthetix]/[@ethersproject]/providers/lib/json-rpc-provider.js:21:65
- task_queues.js:95 processTicksAndRejections
internal/process/task_queues.js:95:5
We need to use the SafeMultisigConfirmationResponse
type available in the safe-service-client
responses.
The safe-client-service
package should export the SafeMultisigConfirmationResponse
as for other types already exported.
Hey, thanks for these great SDK libs!
I've been wondering what the specific purpose of each of the packages is as listed in https://github.com/gnosis/safe-core-sdk#packages
Especially I had hard time figuring out how to add delegates using gnosis-core-sdk. It occurred that use case is supported in service client package.
So, could you
That would help consume the libs with less confusion.
The developer would call safeSdk.rejectTransaction(safeTransaction)
to propose the rejection of a transaction. Similar to signTransaction
but saving the rejection signatures associated to the transaction.
User should understand what they sign therefore we should support typed data signing
Hey! I successfully did proposal+approval+execution of an ETH transfer transaction.
But I keep failing with contract deployment one.
The code:
import {BigNumber, ethers, providers, Signer} from 'ethers'
import Safe, {EthersAdapter} from '@gnosis.pm/safe-core-sdk'
import SafeServiceClient from "@gnosis.pm/safe-service-client";
import {SafeTransactionDataPartial} from '@gnosis.pm/safe-core-sdk-types'
import {getDeployTx} from "../../src/execute/getDeployTx";
import {SimpleContract} from "../fixtures/exampleArtifacts";
import {AbiSymbol, Bytecode} from "../../src/symbols";
const config = {
txServiceUri: 'https://safe-transaction.rinkeby.gnosis.io', // Rinkeby Gnosis Transaction Service URI
infuraApiKey: 'xxxxxxx'
ethNetworkName: 'rinkeby', // in TT we test Gnosis Safes in Rinkeby
ttSafe: '0x8772CD484C059EC5c61459a0abb5A45ece16701f', // TT Rinkeby Test Safe
owner: { // one of many owners of the TT Test Safe
address: '0x4a70cc993A25F0D57Fb37B8E8D5C7CcC0B24Cd7d',
privateKey: process.env.OWNER_PRIVATE_KEY as string
},
delegate: { // one of the delegates
address: '0x48A1B8fF5cEa06D95187f9A1B528D0c90554A179',
privateKey: process.env.DELEGATE_PRIVATE_KEY as string
}
}
// based on https://docs.gnosis-safe.io/build/sdks/core-sdk
describe("Gnosis Safe as multisig contract deployment service in Rinkeby", () => {
let safeServiceClient: SafeServiceClient
let owner: Signer
let delegate: Signer
let safeByOwner: Safe // safe managed via the owner account
let safeByDelegate: Safe // safe managed via the delegate account
beforeEach(async () => {
safeServiceClient = new SafeServiceClient(config.txServiceUri)
const web3Provider = new providers.InfuraProvider(config.ethNetworkName, config.infuraApiKey)
owner = new ethers.Wallet(config.owner.privateKey, web3Provider)
delegate = new ethers.Wallet(config.delegate.privateKey, web3Provider)
safeByOwner = await Safe.create({
ethAdapter: new EthersAdapter({ethers, signer: owner}),
safeAddress: config.ttSafe
})
await safeByOwner.connect({})
safeByDelegate = await Safe.create({
ethAdapter: new EthersAdapter({ethers, signer: delegate}),
safeAddress: config.ttSafe
})
await safeByDelegate.connect({})
})
it('Enqueues a simple contract deployment transaction by a delegate', async () => {
const simpleContractDeploymentTx = getDeployTx(SimpleContract[AbiSymbol], SimpleContract[Bytecode], [])
const safeDeploymentTx: SafeTransactionDataPartial = {
to: safeByOwner.getAddress(),
data: simpleContractDeploymentTx.data as string,
value: '0',
safeTxGas: 1000000
}
const safeTransaction = await safeByOwner.createTransaction(safeDeploymentTx)
const safeTransactionHash = await safeByOwner.getTransactionHash(safeTransaction)
await safeServiceClient.proposeTransaction({
safeAddress: safeByOwner.getAddress(),
safeTxHash: safeTransactionHash,
safeTransaction,
senderAddress: await owner.getAddress()
})
console.log(`Simple contract deployment via Safe tx hash: ${safeTransactionHash}`)
})
it('Find tx details', async () => {
const t = await safeServiceClient.getTransaction('0x683fe944de35598048d190a7e39932c0d4b8036805c859eaa1d4f224e8b07dfa')
const pending = await safeServiceClient.getPendingTransactions(safeByOwner.getAddress())
const approvalResult = await safeByOwner.approveTransactionHash(t.safeTxHash)
//safeByOwner.executeTransaction()
})
})
Also:
export function getDeployTx(abi: Abi, bytecode: string, args: any[]) {
return new ContractFactory(abi, bytecode).getDeployTransaction(...args)
}
It's automatically approved (because of the owner) and when I execute from Safe UI it succeeds but internal transactions fail.
I got the following error after building and calling the createSafe method.
EthersSafeFactory.ts:104 Uncaught (in promise) TypeError: Cannot read property 'args' of undefined
at EthersSafeFactory.deployProxy (EthersSafeFactory.ts:104)
yarn build
It should be able to create a safe as described in the tests
I assume this has something to do with the build as the tests are passing while the method throws an error when I try to call the method in /dist after the build.
The error probably results from the following line: https://github.com/rsksmart/safe-core-sdk/blob/develop/src/EthersSafeFactory.ts#L104
Create initial version of Core SDK for generating signatures
SafeFactory
should either accept a version configuration parameter or should default to the currrent (1.3) version of safe
safeTxGas
is a workaround that was used so RPC providers could estimate correctly the gas used by a Safe transaction. This way we could get a valid gasLimit
and avoid running out of gas because transaction was estimated lower than the real cost.
Since v1.3.0 this workaround is not necessary any more as now a transaction failing by low gas will revert instead of succeed, and we could simply send a 0 value and let the wallets to estimate the full cost in gas of the transaction.
From the contract code comments:
If no safeTxGas and no gasPrice was set (e.g. both are 0),
then the internal tx is required to be successful
This makes it possible to use `estimateGas` without issues,
as it searches for the minimum gas where the tx doesn't revert
safeTxGas=0
when sending a transaction from a Safe that is using at least v1.3.0 version of the smart contractstandardizeSafeTransactionData
safeTxGas=0
Use safe-deployments to handle contract versions.
Make the property signatures
nullable in the type SafeMultisigTransactionResponse
returned by the Safe Transaction Service.
Web3Adapter
takes signerAddress
, typed as string
. In safe-react
we use the following function (so allowing string | null
would be a great help):
export const getAccountFrom = async (web3Provider: Web3): Promise<string | null> => {
const accounts = await web3Provider.eth.getAccounts()
return accounts && accounts.length > 0 ? accounts[0] : null
}
Methods that then require the use of signerAddress
should throw.
If the Safe Service Client is used to propose some transactions before any of them is executed, they will all have the same nonce
. The current nonce
should be retrieved and incremented before proposing each transaction.
Follow EIP 1271 for contract signatures.
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md
Deploy a gnosis smart contract on polygon!
This is a sample using an ERC-20 Token. It seems that it cannot find the ABI for the safe from the depth of the SDK.
I'm not sure what to do here and how to configure it. If I require a ContractNetworksConfig, how would it look like?
const ethAdapterOwner1 = new Web3Adapter({
web3,
signerAddress: '0x647C8f25Df7725747ab04BB71Ab606b8479A1435'
})
const safeSdk: Safe = await Safe.create(
{
ethAdapter: ethAdapterOwner1,
safeAddress: '0xeC31635F253059EDf229ed69ab704f785e44637C',
})
This throws the following error:
errors.js:107 Uncaught (in promise) Error: You must provide the json interface of the contract when instantiating a contract object.
at Object.ContractMissingABIError (errors.js:107)
at Contract (index.js:60)
at new Contract (index.js:257)
at Web3Adapter.getContract (eval at hmrApply (runtime-d6a2b2435d7a0f89.js:297), <anonymous>:61:16)
at Web3Adapter.getSafeContract (eval at hmrApply (runtime-d6a2b2435d7a0f89.js:297), <anonymous>:43:35)
at ContractManager.init (contractManager.ts:31)
at async Function.create (contractManager.ts:20)
at async Safe.init (Safe.ts:110)
at async Function.create (Safe.ts:92)
see aboe
no error
Add read functions to access the data from the Safe contract
There's no way to pass a nonce of the transaction to methods that build a specific transaction (change threshold, owner management, etc.). This behavior requires workarounds for multi-tx interactions by encoding transaction call data and using the raw createTransaciton
method.
Allow passing custom nonce or the same set of options as createTransaction
createTransaciton
methodRemove axios
dependency in safe-service-client
and use fetch
instead.
The documentation of the safe-core-sdk
has an error in the API Reference
/ connect
section:
https://github.com/gnosis/safe-core-sdk/tree/main/packages/safe-core-sdk#api-reference
The code sample for the contractNetworks
property was probably copy-pasted from the create
section. I assume it should use connect
instead of create
.
Documentation should read like:
const safeSdk = await Safe.connect({ ethAdapter, safeAddress, contractNetworks })
It seems that using WalletConnect signer does not work properly
Allow sending batch transactions using the safe-core-sdk
.
value out-of-bounds (argument="saltNonce", value=-706506811, code=INVALID_ARGUMENT, version=abi/5.4.1)
Probably the underlaying solidity value expects a uint
.
The README of the safe-core-sdk
package is outdated, and it doesn't include the changes related to the introduction of the TransactionResult
interface.
All the examples with execute
or approveTransactionHash
call the wait
method on the TransactionResult
interface, but it doesn't include such method.
Example
Wrong version:
const approveTxResponse = await safeSdk2.approveTransactionHash(txHash)
await approveTxResponse.wait()
Fixed version:
const executeTxResponse = await safeSdk3.executeTransaction(safeTransaction)
await executeTxResponse.transactionResponse?.wait()
Make the safe-core-sdk
compatible not only with ethersjs
but also with web3
Remove ethers from constructor and add it as a peer dependency
Add functions to submit signatures
Hi, I'm hoping you can help with the usage of this repo.
I (as one of the safe owners) am looking to programmatically initiate a transaction that the other safe owners can sign in the Gnosis UI.
Is this SDK the best way to achieve that?
Export EthAdapterTransaction
so it can be imported like this:
import { EthAdapterTransaction } from '@gnosis.pm/safe-core-sdk'
...
const txConfig: EthAdapterTransaction = { ... }
await ethAdapter.estimateGas(txConfig)
Currrently it must be imported this way:
import { EthAdapterTransaction } from '@gnosis.pm/safe-core-sdk/dist/src/ethereumLibs/EthAdapter'
Export EthSignSignature
to avoid importing it from @gnosis.pm/safe-core-sdk/dist/src/utils/signatures/SafeSignature
Currently there is an incorrect validation of the threshold when a new owner is added with a new threshold.
const safeTx = await sdk.getAddOwnerTx(newOwnerAddress, newThreshold)
The method that validates the threshold is:
private validateThreshold(threshold: number, numOwners: number): void {
if (threshold <= 0) {
throw new Error('Threshold needs to be greater than 0')
}
if (threshold > numOwners) {
throw new Error('Threshold cannot exceed owner count')
}
}
Calling getAddOwnerTx(...)
validates the threshold this way:
validateThreshold(newThreshold, owners.length) // owners does not contain the new owner here
It should be validated this other way (to take into account the new owner):
validateThreshold(newThreshold, owners.length + 1) // owners does not contain the new owner here
getAddOwnerTx("0x...", 2)
. This will throw an exception with the error message: "'Threshold cannot exceed owner count"Adding a new owner and updating the threshold of an existing Safe where the new threshold is equal to the amount of new owners should work.
Allow to revoke all the delegates of a Safe address by calling the new endpoint in the transaction-service.
Replace the signature
with a signer
in the methods to manage the delegates (the generation of the signature will be handled internally)
Make the safe-core-sdk
compatible with different Safe contract versions
Can we add a parameter to this method to enable passing gasLimit
or gasPrice
values to the safeContract.execTransaction
call? Gas estimation function is not working on RSK and we are building our own custom estimation. We want to pass this value in, and, if possible, avoid re-estimating.
Deploy a contract on polygon
I'm following the vanilla description from core sdk and client sdk and run into an error:
Uncaught TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
at Object.sendRequest (httpRequests.ts:16)
at SafeServiceClient.proposeTransaction (SafeServiceClient.ts:368)
at tmp (sample.ts:68)
at async <anonymous>:1:1
sendRequest @ httpRequests.ts:16
proposeTransaction @ SafeServiceClient.ts:368
tmp @ sample.ts:68
setTimeout (async)
runTimeout @ browser.js:41
process.nextTick @ browser.js:143
eval @ util.js:694
Promise.then (async)
bound bound request @ util.js:694
RequestManager.send @ index.js:155
sendRequest @ index.js:615
send @ index.js:647
_executeMethod @ index.js:768
getTransactionHash @ GnosisSafeContractWeb3.ts:62
getTransactionHash @ Safe.ts:319
tmp @ sample.ts:59
await in tmp (async)
(anonymous) @ VM5460:1`
I'm not sure if I'm doing it correctly and am basically try & error myself through the various SDKs, as I was not able to found documentation around this. My understanding is that this should be doable from a browser?
Run this code;
const safeAddress = '0xeC31635F253059EDf229ed69ab704f785e44637C';
const signerAddress = '0x647C8f25Df7725747ab04BB71Ab606b8479A1435'
// somehow load web3
const web3 = detectWeb3()
const abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousTWAPEpochPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTWAPEpochPeriod","type":"uint256"}],"name":"TWAPEpochChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTWAPOracle","type":"address"},{"indexed":true,"internalType":"address","name":"newTWAPOracle","type":"address"}],"name":"TWAPOracleChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newTWAPSource","type":"address"}],"name":"TWAPSourceAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"removedTWAPSource","type":"address"}],"name":"TWAPSourceRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"_burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTWAPSourceDexPool_","type":"address"}],"name":"addTWAPSource","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newTWAPEpochPeriod_","type":"uint256"}],"name":"changeTWAPEpochPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTWAPOracle_","type":"address"}],"name":"changeTWAPOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"twapSourceToRemove_","type":"address"}],"name":"removeTWAPSource","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"setVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"twapEpochPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"twapOracle","outputs":[{"internalType":"contract ITWAPOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
const address = '0x4e78011Ce80ee02d2c3e649Fb657E45898257815'
const contract = new web3.eth.Contract(abi, address)
const data = contract.methods.approve('0x4e78011Ce80ee02d2c3e649Fb657E45898257815', 12).encodeABI()
const ethAdapterOwner1 = new Web3Adapter({
web3: web3,
signerAddress
})
const safeSdk: Safe = await Safe.create(
{
ethAdapter: ethAdapterOwner1,
safeAddress: '0xeC31635F253059EDf229ed69ab704f785e44637C',
})
const transaction: SafeTransactionDataPartial = {
to: address,
value: '0',
data: data
}
const safeTransaction = await safeSdk.createTransaction(transaction)
const safeTxHash = await safeSdk.getTransactionHash(safeTransaction)
const transactionConfig: ProposeTransactionProps = {
safeAddress,
safeTransaction,
safeTxHash,
senderAddress: signerAddress
}
const safeService = new SafeServiceClient('https://safe-transaction.gnosis.io')
await safeService.proposeTransaction(transactionConfig)
No errors :-)
TBD: Check rsksmart#1 and rsksmart#2
Add gas calculation utilities (gas estimation)
This PR (#87) fixed a wrong import of the SafeTranscationDataPartial
type in the README
There is also an import that can be improved in packages/safe-core-sdk/src/utils/transactions/types.ts
When creating a multisend transaction the user is not allowed to set the optional params included in SafeTransactionDataPartial
(safeTxGas
, baseGas
, gasPrice
, gasToken
, refundReceiver
and nonce
).
The user is allowed to set the optional params included in SafeTransactionDataPartial
(safeTxGas
, baseGas
, gasPrice
, gasToken
, refundReceiver
and nonce
) when creating a multisend transaction.
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.