分类 默认分类 下的文章

  • 首先需要npm安裝ethers
  • 然后再在项目里引入
const ethers = require("ethers") // nodejs
import ethers from "ethers" // front-end
// 如果是非webpack前端,也可以直接用script标签引入.js文件
  • 关联钱包
const wallet = new ethers.Wallet('your private key') // 这个必须用私钥。还有另一个方式是用助记词
  • 将钱包关联到contract,这样就可以发起签名,进行transfer、approve等操作
const account = wallet.connect(provider)
const someContract = new ethers.Contract(
  'contract address for example, USDT, BUSD, panca etc...',
  ['function approve(address spender, uint amount) public returns(bool)',
  'function allowance(address owner, address spender) view returns(uint256)'], // 这个数组放你需要用到的abi
  account
)
  • 配置provider,用于链上交互
const provider = new ethers.providers.WebSocketProvider("wss://bsc-ws-node.nariox.org:443") // 示例里的链接为bsc主网的社区wss,测试用可以,大型项目建议使用付费的或者自建full node
  • 例子1:发起approve。注意,await需要在async类型的函数里运行
const gasPrice = await provider.getGasPrice(); // bsc大多时候返回5000000000 (5e9)
const approveResult = await someContract.approve(
  "spender's address", // 允许让谁调用,可以是别人的账号,也可以是诸如pancakeswap的router address等
  123456, // 最高0xffff(64个F)
  { gasPrice: gasPrice, gasLimit: "450000" } // 为什么gasPrice>gasLimit?
)
// approveResult包含了此次approve事件的hash等信息
  • 例子2:查看某个approve的授权额
const allowance = await someContract.allowance(wallet.address, "spender's address")
// 返回值为uni256的BigNumber,如果是0,用0===allowance依然false,但0==allowance则为true
// 如果从来没approve过,则allowance为0
  • 例子3:取消某个approve:

    • 方法跟例子1一样,只不过第二个参数授权额度设置为0即可
  • 例子4:根据token0和token1获取它们在LP的pair address
// 想要获取pair address需要先构造对应AMM的factory contract
const factory = new ethers.Contract(
  "AMM's factory address", 
  ["function getPair(address tokenA, address tokenB) external view returns (address pair)"], // factory的abi不止这个,详情查看对应的factory.sol,如果是bsc则在bscscan上查AMM's factory address应该也能查到
  account
)
const pairAddress = await factory.getPair("token0 address", "token1 address") // 两个address顺序调换不影响
  • 例子5:获取某个token对在LP里的储量
// 想要获得token0和token1在LP里的储量,需要先构造pair contract
const pair = new ethers.Contract(
  pairAddress,
  ["function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)"],
  // 如果想要更多其它abi,假设是bsc链的pairAddress,可以去bscscan搜,里面直接列出了所有的function
  account
)
const reserves = await pair.getReserves()
// reserves.reserve0和reserves.reserve1就是token0和token1在LP里的储量,具体顺序可能需要打印log才知道
// 此时我们就得到大名鼎鼎的X*Y=K了,reserve0和reserve1分别就是X和Y
// 利用reserve0/reserve1或者reserve1/reserve0即可得到他们之间互相的swap价格,如果不考虑swap数量的话。如果考虑数量对价格的impact,需要用到下面[例子7]的方式
  • 例子6:ethers.utils类的使用:直接看官方文档吧,这个包含了wei和ether等单位转换之类的小工具
  • 例子7:根据tokenIn的数量获取swap价格
// 首先要构建router contract
const router = new ethers.Contract(
  'router contract of AMM, for example pancake',
  [
    "function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)",
    "function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)",
  ],
  account
)
// 然后再设置tokenIn的数量。变量里的in和out分别指放入LP(sell)和从LP取出(buy)
const amountIn = ethers.utils.parseEther("123"); // parseEther表示精度为18的token,如果精度不为18需要用另一个parse 
const amounts = await router.getAmountsOut(amountIn, [
  'tokenIn contract address',
  'tokenOut contract',
]);
// amounts是一个数组,amounts[0]和amounts[1]跟tokenIn和tokenOut的对应关系可以自己打log测试一下
// 为什么不直接用X/Y去计算价格?因为amountIn会导致X和Y数量的变化,价格也跟着变,如果K大还好,K小的话,影响很大
  • 例子8:发起swap,接上例
const tx = await router.swapExactTokensForTokens(
  amountIn,
  amounts[1].sub(amounts[1].div(10)), // 这个参数称为amountOutMin,如果最终swap得到的tokenOut数量低于这个值系统就不swap
  [tokenIn address, tokenOut address],
  wallet.address,
  Date.now() + 1000 * 60 * 10, // 链上排队?超过10分钟则放弃swap
  {
    gasPrice: gasPrice,
    gasLimit: "450000", // gasLimit > gasPrice????
    nonce: null, // ???
  }
)
const receipt = await tx.wait();
// receipt包含了本次swap的hash等信息

springboot打包jar

  • 转自 https://blog.csdn.net/qq_37350706/article/details/84325520
  • 首先配置pom
  • 双击如下图package,如果没有打包出jar,看看是否有代码报错,代码报错是无法打包的,springboot的单元测试代码有错也无法打包,解决代码错误的问题,然后clean一下再package
  • 一切顺利的话应该会得到.jar文件

服务器部署.jar文件

  • 上传.jar文件到服务器
  • 首先查看是否已经在运行
ps -ux|grep springboot.jar| grep -v grep
  • 用这个方式可以终止其运行
kill -9 进程号
  • 上述的9不是进程号,应该在“kill -9 ”后带上进程号。这个细节,时间久了我自己也会忘记
  • 后台运行刚才打包的.jar
nohup java -jar springboot.jar --spring.datasource.url="jdbc:mysql://127.0.0.1/database_name?useSSL=false&serverTimezone=Asia/Shanghai" --spring.datasource.password=123456 --server.port=8081 &
  • 有时8080端口被占,执行完后,用grep也查不到进程,可用参数更改端口
  • 我有一次本地运行好好的,服务器报500错误,发现是本地测试时,数据库密码跟服务器不一样,上述参数也可以用于更改密码

TRC20主网

TRC20测试网shasta

TRC20测试网nile

TRC10主网

TRC10测试网shasta

TRC10测试网nile

总结

  • 判断token是否存在都用0==total
  • TRC20主网和测试网获取方式一样
  • TRC10主网和测试网获取方式一样

华为

  • 一把就通过了。。下次如果被拒绝,我再补充

OPPO

  • 名称被前面的开发者占用,同类型资源主标题过于相似会造成用户选择困难。若您无法提供商标权,请您对名称进行合规修改,或者您可以在主标题前加入公司名称或品牌词以作区分
  • 您需提供贵司自己的ICP备案网址。(备案要求:备案网址的页面须有可查的此资源的信息,备案号在网页中显示)

VIVO

  • 应用存在隐私政策问题,如:应用隐私政策没有摄像头权限收集说明--不通过;
  • 隐私政策未明确账号注销相关信息及账号注销处理时效
  • 应用名称请勿使用不具品牌识别性词汇,包括但不限于类别词及类别词叠加
  • 应用无意见反馈渠道
  • 隐私政策未明确权限收集相关说明

小米

  • 应用不得是简单的网站页面打包或套用模板、内容聚合或罗列链接
  • 很抱歉,您的应用未通过审核,原因是:请参考小米应用商店规范做出修改
  • 摘录几条规范:

    • 确保提供应用审核期间可用有效的测试和功能演示视频
    • 应用信息中填写的名称不得与安装到设备中显示的名称不一致
    • 应用名称不得使用其他热门应用名称或别称,也不得混有商业化用语或流行用语等与应用功能无关的词语
    • 应用名称不得仅以类别词命名,如以壁纸、标签、电话、桌面、安全助手、wifi等名称做为应用的名称,在此类名称增加副标题也不符合上架条件
    • 应用名称不得与线上在架应用名称相同
    • 应用截图的通知栏中不得包含与应用功能无关内容,请仅保留手机系统自带的信号、运营商信息等提示
    • 应用内必须包含需提供有效更正、删除个人信息等用户账号功能,不得为注销服务设置障碍的情况
    • 长期未更新的应用可能会被下架

其它

  • 来自VIVO的邮件:截止至2021年12月底,现有和新发布的应用/游戏必须上传包含64位包体的APK包(支持32位64位双包上传,或兼容32位和64位的单包上传两种形式,不再接收仅支持32位的APK包)